From e0659c2a88c5cc0dc0a79423d02a2bc79933b8d4 Mon Sep 17 00:00:00 2001 From: Raphanus Lo Date: Mon, 10 Feb 2025 14:23:38 +0800 Subject: [PATCH] feat: self-contained container image build Signed-off-by: Raphanus Lo --- .github/workflows/build.yml | 96 +++++++++++++++++-------------------- Makefile | 21 ++++++++ package/Dockerfile | 20 ++++++-- scripts/package | 64 +++++++++++++++++++------ 4 files changed, 131 insertions(+), 70 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 089f6b8a..fc95c82c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,10 +11,50 @@ jobs: build: name: Build binaries runs-on: ubuntu-22.04 + outputs: + version_major: ${{ steps.build_info.outputs.version_major }} + version_minor: ${{ steps.build_info.outputs.version_minor }} + version_build: ${{ steps.build_info.outputs.version_build }} + image_tag: ${{ steps.build_info.outputs.image_tag }} + steps: - name: Checkout code uses: actions/checkout@v4 + - id: build_info + name: Declare build info + run: | + version_major='' + version_minor='' + version_build='' + image_tag='' + + branch=${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}} + ref=${{ github.ref }} + if [[ "$ref" =~ 'refs/tags/' ]]; then + version=$(sed -E 's/^v([0-9.]*)$/\1' <<<$ref ) + version_major=$(cut -d. -f1 <<<$version) + version_minor=$(cut -d. -f2 <<<$version) + version_build=$(cut -d. -f3 <<<$version) + image_tag="$version" + elif [[ "$ref" =~ 'refs/heads/' ]]; then + image_tag="${branch}-head" + elif [[ "$ref" =~ 'refs/pull/' ]]; then + image_tag="pr${{ github.event.number }}" + fi + + echo "version_major=${version_major}" >>$GITHUB_OUTPUT + echo "version_minor=${version_minor}" >>$GITHUB_OUTPUT + echo "version_build=${version_build}" >>$GITHUB_OUTPUT + echo "image_tag=${image_tag}" >>$GITHUB_OUTPUT + + cat <> "$GITHUB_ENV" - - name: Login to Docker Hub uses: docker/login-action@v3 with: @@ -71,24 +81,8 @@ jobs: password: ${{ secrets.DOCKER_PASSWORD }} # longhornio/longhorn-share-manager image - - name: docker-publish - if: ${{ startsWith(github.ref, 'refs/heads/') }} - uses: docker/build-push-action@v5 - with: - context: ./ - push: true - platforms: linux/amd64,linux/arm64 - tags: longhornio/longhorn-share-manager:${{ env.branch }}-head - file: package/Dockerfile - sbom: true - - - name: docker-publish-with-tag - if: ${{ startsWith(github.ref, 'refs/tags/') }} - uses: docker/build-push-action@v5 - with: - context: ./ - push: true - platforms: linux/amd64,linux/arm64 - tags: longhornio/longhorn-share-manager:${{ github.ref_name }} - file: package/Dockerfile - sbom: true + - name: Build and publish image + env: + REPO: docker.io/longhornio + TAG: ${{ needs.build.outputs.image_tag }} + run: make workflow-image-build-push diff --git a/Makefile b/Makefile index 78839b9b..ef4f2c91 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,9 @@ TARGETS := $(shell ls scripts) +MACHINE := longhorn +# Define the target platforms that can be used across the ecosystem. +# Note that what would actually be used for a given project will be +# defined in TARGET_PLATFORMS, and must be a subset of the below: +DEFAULT_PLATFORMS := linux/amd64,linux/arm64 .dapper: @echo Downloading dapper @@ -10,6 +15,22 @@ TARGETS := $(shell ls scripts) $(TARGETS): .dapper ./.dapper $@ +.PHONY: buildx-machine +buildx-machine: + @docker buildx create --name=$(MACHINE) --platform=$(DEFAULT_PLATFORMS) 2>/dev/null || true + docker buildx inspect $(MACHINE) + +# variables needed from GHA caller: +# - REPO: image repo, include $registry/$repo_path +# - TAG: image tag +# - TARGET_PLATFORMS: optional, to be passed for buildx's --platform option +# - IID_FILE_FLAG: optional, options to generate image ID file +.PHONY: workflow-image-build-push workflow-image-build-push-secure +workflow-image-build-push: buildx-machine + MACHINE=$(MACHINE) OUTPUT_ARGS='--push' bash scripts/package +workflow-image-build-push-secure: buildx-machine + MACHINE=$(MACHINE) OUTPUT_ARGS='--push' IS_SECURE=true bash scripts/package + .DEFAULT_GOAL := ci .PHONY: $(TARGETS) diff --git a/package/Dockerfile b/package/Dockerfile index 42aba843..3516bedc 100644 --- a/package/Dockerfile +++ b/package/Dockerfile @@ -1,6 +1,18 @@ # syntax=docker/dockerfile:1.13.0 +FROM registry.suse.com/bci/golang:1.23 AS app_builder -FROM registry.suse.com/bci/bci-base:15.6 AS build +WORKDIR /app + +# Copy the build script and source code +COPY . /app + +# Make the build script executable +RUN chmod +x /app/scripts/build + +# Run the build script +RUN /app/scripts/build + +FROM registry.suse.com/bci/bci-base:15.6 AS lib_builder RUN zypper -n ref && \ zypper update -y @@ -73,9 +85,9 @@ RUN sed -i s/systemd// /etc/nsswitch.conf # ganesha reads /etc/mtab for mounted volumes RUN ln -sf /proc/self/mounts /etc/mtab -COPY --from=build /usr/local /usr/local/ -COPY --from=build /ganesha-extra / -COPY package/bin/longhorn-share-manager-${ARCH} /longhorn-share-manager +COPY --from=lib_builder /usr/local /usr/local/ +COPY --from=lib_builder /ganesha-extra / +COPY --from=app_builder /app/bin/longhorn-share-manager-${ARCH} /longhorn-share-manager # run ldconfig after libs have been copied RUN ldconfig diff --git a/scripts/package b/scripts/package index 1df847fd..122028ba 100755 --- a/scripts/package +++ b/scripts/package @@ -5,25 +5,59 @@ source $(dirname $0)/version cd $(dirname $0)/.. -PROJECT=`basename "$PWD"` +project=$(basename "$PWD") -if [ ! -x ./bin/longhorn ]; then - ./scripts/build -fi - -cp -r bin package/ +command -v buildx >/dev/null && build_cmd=(buildx) || build_cmd=(docker buildx) -APIVERSION=`./bin/longhorn-share-manager version --client-only|jq ".clientVersion.apiVersion"` -TAG=${TAG:-"v${APIVERSION}_`date -u +%Y%m%d`"} +# read configurable parameters REPO=${REPO:-longhornio} -IMAGE=${REPO}/${PROJECT}:${TAG} +IMAGE_NAME=${IMAGE_NAME:-$project} +TAG=${TAG:-''} +OUTPUT_ARGS=${OUTPUT_ARGS:-'--load'} +IS_SECURE=${IS_SECURE:-'false'} +MACHINE=${MACHINE:-''} +TARGET_PLATFORMS=${TARGET_PLATFORMS:-''} +IID_FILE=${IID_FILE:-''} +IID_FILE_FLAG=${IID_FILE_FLAG:-''} + +if [[ -z $TAG ]]; then + if api_version=$(./bin/longhorn-share-manager version --client-only | jq ".clientVersion.apiVersion"); then + TAG="v${api_version}_$(date -u +%Y%m%d)" + else + TAG="$VERSION" + fi +fi -# update base image to get latest changes -BASE_IMAGE=`grep FROM package/Dockerfile | grep -v AS | awk '{print $2}'` -docker pull ${BASE_IMAGE} +image="${REPO}/${IMAGE_NAME}:${TAG}" + +builder_args=() +[[ $MACHINE ]] && builder_args+=('--builder' "$MACHINE") -buildx build --load -t ${IMAGE} -f package/Dockerfile . +IFS=' ' read -r -a iid_file_args <<<"$IID_FILE_FLAG" +[[ -n "$IID_FILE" && ${#iid_file_args} == 0 ]] && iid_file_args=('--iidfile' "$IID_FILE") -echo Built ${IMAGE} +IFS=' ' read -r -a buildx_args <<<"$OUTPUT_ARGS" +[[ $IS_SECURE == 'true' ]] && buildx_args+=('--sbom=true' '--attest' 'type=provenance,mode=max') +[[ $TARGET_PLATFORMS ]] && buildx_args+=('--platform' "$TARGET_PLATFORMS") -echo ${IMAGE} > ./bin/latest_image +# update base image to get latest changes +grep 'FROM.*/' package/Dockerfile | awk '{print $2}' | while read -r base_image +do + docker pull "$base_image" +done + +echo "${build_cmd[@]}" build --no-cache \ + "${builder_args[@]}" \ + "${iid_file_args[@]}" \ + "${buildx_args[@]}" \ + -t "$image" -f package/Dockerfile . +"${build_cmd[@]}" build --no-cache \ + "${builder_args[@]}" \ + "${iid_file_args[@]}" \ + "${buildx_args[@]}" \ + -t "$image" -f package/Dockerfile . + +echo "Built $image" + +mkdir ./bin || true +echo "$image" > ./bin/latest_image