Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.3] automate the ironbank generation (backport #8537) #8661

Merged
merged 3 commits into from
Jul 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,7 @@ APM_AGENT_JAVA_PUB_KEY:=apm-agent-java-public-key.asc
release: export PATH:=$(dir $(BIN_MAGE)):$(PATH)
release: $(MAGE) $(PYTHON) build/$(JAVA_ATTACHER_JAR) build/dependencies.csv
$(MAGE) package
$(MAGE) ironbank

build/dependencies.csv: $(PYTHON) go.mod
$(PYTHON) script/generate_notice.py ./x-pack/apm-server --csv $@
Expand Down
106 changes: 106 additions & 0 deletions magefile.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"log"
"os"
"path/filepath"
"runtime"
"strings"

"github.com/magefile/mage/mg"
Expand Down Expand Up @@ -138,6 +139,24 @@ func filterPackages(types string) {
mage.Packages = packages
}

// Ironbank packages apm-server for the Ironbank distribution, relying on the
// binaries having already been built.
//
// Use SNAPSHOT=true to build snapshots.
func Ironbank() error {
if runtime.GOARCH != "amd64" {
fmt.Printf(">> Ironbank images are only supported for amd64 arch (%s is not supported)\n", runtime.GOARCH)
return nil
}
if err := prepareIronbankBuild(); err != nil {
return errors.Wrap(err, "failed to prepare the ironbank context")
}
if err := saveIronbank(); err != nil {
return errors.Wrap(err, "failed to save artifacts for ironbank")
}
return nil
}

// Package builds and packages apm-server for distribution.
//
// Use SNAPSHOT=true to build snapshots.
Expand Down Expand Up @@ -180,6 +199,7 @@ func Update() error {
return nil
}

// GoTestUnit runs the go test unit.
// Use RACE_DETECTOR=true to enable the race detector.
func GoTestUnit(ctx context.Context) error {
return mage.GoTest(ctx, mage.DefaultGoTestUnitArgs())
Expand Down Expand Up @@ -239,6 +259,92 @@ func customizePackaging() {
}
}

func saveIronbank() error {
fmt.Println(">> saveIronbank: save the IronBank container context.")

ironbank := getIronbankContextName()
buildDir := filepath.Join("build", ironbank)
if _, err := os.Stat(buildDir); os.IsNotExist(err) {
return fmt.Errorf("cannot find the folder with the ironbank context: %+v", err)
}

distributionsDir := "build/distributions"
if _, err := os.Stat(distributionsDir); os.IsNotExist(err) {
err := os.MkdirAll(distributionsDir, 0750)
if err != nil {
return fmt.Errorf("cannot create folder for docker artifacts: %+v", err)
}
}

// change dir to the buildDir location where the ironbank folder exists
// this will generate a tar.gz without some nested folders.
wd, _ := os.Getwd()
os.Chdir(buildDir)
defer os.Chdir(wd)

// move the folder to the parent folder, there are two parent folder since
// buildDir contains a two folders dir.
tarGzFile := filepath.Join("..", "..", distributionsDir, ironbank+".tar.gz")

// Save the build context as tar.gz artifact
err := mage.Tar("./", tarGzFile)
if err != nil {
return fmt.Errorf("cannot compress the tar.gz file: %+v", err)
}

return errors.Wrap(mage.CreateSHA512File(tarGzFile), "failed to create .sha512 file")
}

func getIronbankContextName() string {
version, _ := mage.BeatQualifiedVersion()
defaultBinaryName := "{{.Name}}-ironbank-{{.Version}}{{if .Snapshot}}-SNAPSHOT{{end}}"
outputDir, _ := mage.Expand(defaultBinaryName+"-docker-build-context", map[string]interface{}{
"Name": "apm-server",
"Version": version,
})
return outputDir
}

func prepareIronbankBuild() error {
fmt.Println(">> prepareIronbankBuild: prepare the IronBank container context.")
ironbank := getIronbankContextName()
buildDir := filepath.Join("build", ironbank)
templatesDir := filepath.Join("packaging", "ironbank")

data := map[string]interface{}{
"MajorMinor": majorMinor(),
}

err := filepath.Walk(templatesDir, func(path string, info os.FileInfo, _ error) error {
if !info.IsDir() {
target := strings.TrimSuffix(
filepath.Join(buildDir, filepath.Base(path)),
".tmpl",
)

err := mage.ExpandFile(path, target, data)
if err != nil {
return errors.Wrapf(err, "expanding template '%s' to '%s'", path, target)
}
}
return nil
})

if err != nil {
return err
}
return nil
}

func majorMinor() string {
if v, _ := mage.BeatQualifiedVersion(); v != "" {
parts := strings.SplitN(v, ".", 3)
return parts[0] + "." + parts[1]
}
return ""
}

// Check checks the source code for common problems.
func Check() error {
fmt.Println(">> check: Checking source code for common problems")

Expand Down
74 changes: 74 additions & 0 deletions packaging/ironbank/Dockerfile.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
################################################################################
# Build stage 0
# Extract APM Server and make various file manipulations.
################################################################################
ARG BASE_REGISTRY=registry1.dsop.io
ARG BASE_IMAGE=ironbank/redhat/ubi/ubi8
ARG BASE_TAG=8.6

FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG} AS builder

ARG ELASTIC_STACK={{ beat_version }}
ARG ELASTIC_PRODUCT=apm-server
ARG OS_AND_ARCH=linux-x86_64

RUN mkdir /usr/share/${ELASTIC_PRODUCT}
WORKDIR /usr/share/${ELASTIC_PRODUCT}
COPY --chown=1000:0 ${ELASTIC_PRODUCT}-${ELASTIC_STACK}-${OS_AND_ARCH}.tar.gz .
RUN tar --strip-components=1 -zxf ${ELASTIC_PRODUCT}-${ELASTIC_STACK}-${OS_AND_ARCH}.tar.gz
# Support arbitrary user ids
# Ensure that group permissions are the same as user permissions.
# This will help when relying on GID-0 to run Kibana, rather than UID-1000.
# OpenShift does this, for example.
# REF: https://docs.okd.io/latest/openshift_images/create-images.html
RUN chmod -R g=u /usr/share/${ELASTIC_PRODUCT}

# Create auxiliar folders and assing default permissions.
RUN mkdir /usr/share/${ELASTIC_PRODUCT}/data /usr/share/${ELASTIC_PRODUCT}/logs && \
chown -R root:root /usr/share/${ELASTIC_PRODUCT} && \
find /usr/share/${ELASTIC_PRODUCT} -type d -exec chmod 0750 {} \; && \
find /usr/share/${ELASTIC_PRODUCT} -type f -exec chmod 0640 {} \; && \
chmod 0750 /usr/share/${ELASTIC_PRODUCT}/${ELASTIC_PRODUCT} && \
chmod 0770 /usr/share/${ELASTIC_PRODUCT}/data /usr/share/${ELASTIC_PRODUCT}/logs

################################################################################
# Build stage 1
# Copy prepared files from the previous stage and complete the image.
################################################################################
FROM ${BASE_REGISTRY}/${BASE_IMAGE}:${BASE_TAG}

ARG ELASTIC_PRODUCT=apm-server

COPY LICENSE /licenses/elastic-${ELASTIC_PRODUCT}

# Add a dumb init process
COPY tinit /tinit
RUN chmod +x /tinit

# Bring in product from the initial stage.
COPY --from=prep_files --chown=1000:0 /usr/share/${ELASTIC_PRODUCT} /usr/share/${ELASTIC_PRODUCT}
WORKDIR /usr/share/${ELASTIC_PRODUCT}
RUN ln -s /usr/share/${ELASTIC_PRODUCT} /opt/${ELASTIC_PRODUCT}

ENV ELASTIC_CONTAINER true
RUN ln -s /usr/share/${ELASTIC_PRODUCT}/${ELASTIC_PRODUCT} /usr/bin/${ELASTIC_PRODUCT}

# Support arbitrary user ids
# Ensure gid 0 write permissions for OpenShift.
RUN chmod -R g+w /usr/share/${ELASTIC_PRODUCT}

# config file ("${ELASTIC_PRODUCT}.yml") can only be writable by the owner
RUN chmod go-w /usr/share/${ELASTIC_PRODUCT}/${ELASTIC_PRODUCT}.yml

# Remove the suid bit everywhere to mitigate "Stack Clash"
RUN find / -xdev -perm -4000 -exec chmod u-s {} +

# Provide a non-root user to run the process.
RUN groupadd --gid 1000 ${ELASTIC_PRODUCT} && useradd --uid 1000 --gid 1000 --home-dir /usr/share/${ELASTIC_PRODUCT} --no-create-home ${ELASTIC_PRODUCT}
USER ${ELASTIC_PRODUCT}

EXPOSE 8200
ENTRYPOINT ["/tinit", "--", "/usr/share/apm-server/apm-server"]
CMD ["-environment", "container"]

HEALTHCHECK --interval=10s --timeout=5s --start-period=1m --retries=5 CMD (curl -I -f --max-time 5 https://localhost:8200 || curl -I -f --max-time 5 http://localhost:8200 || exit 1)
Loading