Docker Image #43
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ## Github workflow to build a docker image from source | |
| # - first builds the binaries from source for x86_64 and arm64 | |
| # - then builds the docker image from the binary artifacts | |
| name: Docker Image | |
| on: | |
| workflow_dispatch: | |
| schedule: | |
| - cron: "00 05 * * *" # 0500 UTC | |
| env: | |
| # build for both x64 and arm64 arch | |
| DOCKER_PLATFORMS: "linux/amd64,linux/arm64" | |
| # publish images to ghcr | |
| DOCKER_REGISTRY: "ghcr.io" | |
| # set a default command to build. we'll define specific build config options later per arch. | |
| CMD: "cargo build --features monitoring_prom,slog_json --profile release --workspace" | |
| # do not generate provenance from the docker build step, instead attest the image specifically | |
| PROVENANCE: false | |
| # set the build target statically, since we only need to build for linux-glibc | |
| ARCH: linux-glibc | |
| concurrency: | |
| group: docker-image-${{ github.head_ref || github.ref || github.run_id }} | |
| ## Always cancel duplicate jobs | |
| cancel-in-progress: true | |
| jobs: | |
| ## Build arch dependent binaries from source | |
| build-binaries: | |
| name: Build Binaries | |
| runs-on: ubuntu-latest | |
| permissions: | |
| id-token: write | |
| attestations: write | |
| strategy: | |
| max-parallel: 2 | |
| matrix: | |
| arch: | |
| - linux-glibc | |
| cpu: | |
| - x86-64 | |
| - arm64 | |
| steps: | |
| ## set local env vars | |
| - name: Set Local Vars | |
| id: set_vars | |
| shell: bash | |
| run: | | |
| var_branch="${{ github.ref_name }}" | |
| if [ "${{ github.event_name }}" == "schedule" ]; then | |
| var_branch="develop" | |
| fi | |
| echo "BRANCH=${var_branch}" >> $GITHUB_ENV | |
| ## Checkout the code | |
| - name: Checkout the latest code | |
| id: git_checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: ${{ env.BRANCH }} | |
| ## Set target env var based on the type of arch build | |
| ## - simplified from ./release-build.yml configure_target_platform step (only 2 target triples to build in this workflow) | |
| - name: Configure Target Platform | |
| id: configure_target_platform | |
| shell: bash | |
| run: | | |
| case ${{ matrix.cpu }} in | |
| x86-64*) | |
| ARCHIVE_NAME="$(echo "${{ matrix.cpu }}" | sed -e 's|86-||g')" # if matrix.cpu ever changes to a different x86 version, this will set the archive naming appropriately. | |
| # set the CPU to build for. if the matrix defines x86-64, default to -v3, else use what's defined in the matrix | |
| case ${{ matrix.cpu }} in | |
| x86-64) | |
| TARGET_CPU="${{ matrix.cpu }}-v3" # default to x86-64-v3 if generic x86-64 is used for the build | |
| ;; | |
| *) | |
| TARGET_CPU="${{ matrix.cpu }}" # if matrix.cpu is specifically v3/v4, we should target that | |
| ;; | |
| esac | |
| # install dependencies for the x86-64 architecture, and set the rust target for the build step | |
| sudo apt-get update && sudo apt-get install -y git libclang-dev llvm || exit 1 | |
| TARGET="x86_64-unknown-linux-gnu" | |
| ;; | |
| arm64) | |
| # install dependencies for the arm64 architecture, and set the rust target for the build step | |
| ARCHIVE_NAME=${{ matrix.cpu }} | |
| sudo apt-get update && sudo apt-get install -y git gcc-aarch64-linux-gnu libclang-dev llvm || exit 1 | |
| TARGET="aarch64-unknown-linux-gnu" | |
| ;; | |
| *) | |
| echo "Unsupported architecture: ${{ matrix.cpu }}" | |
| exit 1 | |
| ;; | |
| esac | |
| if [[ -z "$TARGET" ]]; then | |
| echo "[ERROR] TARGET Variable is empty for ${{ env.ARCH }}-${{ matrix.cpu }}"; | |
| exit 1 | |
| fi | |
| echo "TARGET=${TARGET}" >> "$GITHUB_ENV" | |
| echo "TARGET_CPU=${TARGET_CPU}" >> "$GITHUB_ENV" | |
| echo "ZIPFILE_NAME=${{ env.ARCH }}-${ARCHIVE_NAME}" >> "$GITHUB_ENV" | |
| ## Install rust toolchain for the target being built | |
| - name: Setup Rust Toolchain | |
| id: setup_rust_toolchain | |
| uses: actions-rust-lang/setup-rust-toolchain@1780873c7b576612439a134613cc4cc74ce5538c # v1.15.2 | |
| with: | |
| toolchain: stable | |
| cache: false | |
| target: ${{ env.TARGET }} | |
| ## Build the binaries | |
| - name: Build Binaries | |
| id: build_binaries | |
| shell: bash | |
| run: | | |
| # | |
| # for each target, we will also echo the command being run so it's easier to see in the logs what command was run | |
| # | |
| case "${{ env.TARGET }}" in | |
| # linux glibc aarch64 | |
| aarch64-unknown-linux-gnu) | |
| LINKER=aarch64-linux-gnu-gcc | |
| echo "$CMD --target $TARGET --config \"target.${TARGET}.linker=\\\"${LINKER}\\\"\" " | |
| ${{ env.CMD }} --target $TARGET --config "target.${{ env.TARGET }}.linker=\"${LINKER}\"" || exit 1 | |
| ;; | |
| # linux glibc x64 | |
| x86_64-unknown-linux-gnu) | |
| # use the default linker | |
| echo "$CMD --target $TARGET --config build.rustflags=\"\\\"-C target-cpu=${TARGET_CPU}\\\"\" " | |
| ${{ env.CMD }} --target $TARGET --config build.rustflags="\"-C target-cpu=${TARGET_CPU}\"" || exit 1 | |
| ;; | |
| *) | |
| echo "No matrix match for build target ($TARGET). using defaults" | |
| ${{ env.CMD }} || exit 1 | |
| ;; | |
| esac | |
| exit 0 | |
| ## Compress the binary artifacts | |
| - name: Compress binaries | |
| id: compress_artifacts | |
| shell: bash | |
| run: | | |
| # compress all binaries in the target directory for any architecture | |
| file -0 ./target/${{ env.TARGET }}/release/* | sed -nE 's/\x0:\s*(ELF|PE32+|Mach).*//p' | zip --junk-paths ${{ env.ZIPFILE_NAME }}.zip -@ | |
| ## Upload the binary archive using the commit sha as the key | |
| - name: Upload Artifact | |
| id: upload_artifact | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: ${{ github.sha }}-${{ env.ZIPFILE_NAME }} | |
| path: ${{ env.ZIPFILE_NAME }}.zip | |
| ## Attest the binary archive | |
| - name: Attest Artifact | |
| uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 | |
| with: | |
| subject-path: ${{ env.ZIPFILE_NAME }}.zip | |
| image: | |
| name: Build Image | |
| runs-on: ubuntu-latest | |
| needs: | |
| - build-binaries | |
| permissions: | |
| id-token: write | |
| attestations: write | |
| packages: write | |
| steps: | |
| ## Retrieve repository description for image annotation | |
| - name: Get repository description | |
| id: repo_desc | |
| run: | | |
| DESCRIPTION=$(gh api repos/${{ github.repository }} --jq '.description') | |
| echo "description=$DESCRIPTION" >> $GITHUB_OUTPUT | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| ## set local env vars | |
| - name: Set Local Vars | |
| id: set_vars | |
| shell: bash | |
| run: | | |
| var_branch="${{ github.ref_name }}" | |
| var_annotation_pattern="${var_branch}" # default to use the branch name | |
| var_default_image="${{ env.DOCKER_REGISTRY }}/${{ github.repository }}" | |
| if [ "${{ github.event_name }}" == "schedule" ]; then | |
| var_default_image="${{ env.DOCKER_REGISTRY }}/${{ github.repository_owner }}/stacks-nightly" | |
| var_branch="develop" | |
| var_annotation_pattern="Nightly" # for scheduled (nightly) builds, use 'Nightly' | |
| fi | |
| echo "DOCKER_IMAGES=${var_default_image}" >> $GITHUB_ENV | |
| echo "BRANCH=${var_branch}" >> $GITHUB_ENV | |
| echo "ANNOTATION_PATTERN=${var_annotation_pattern}" >> $GITHUB_ENV | |
| ## Checkout the code | |
| - name: Checkout the latest code | |
| id: git_checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| ref: ${{ env.BRANCH }} | |
| sparse-checkout: | | |
| .github | |
| ## Download binary artifacts | |
| - name: Download Artifacts | |
| id: download_artifacts | |
| uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 | |
| with: | |
| pattern: ${{ github.sha }}-* # linux-glibc variants are the only artifacts produced, download for both architectures (Dockerfile will choose specific architecture arhive) | |
| path: /tmp/release | |
| merge-multiple: true | |
| ## Setup Docker for the builds | |
| - name: Docker setup | |
| id: docker_setup | |
| uses: stacks-network/actions/docker@main | |
| with: | |
| registry: ${{ env.DOCKER_REGISTRY }} | |
| username: ${{ github.actor }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| ## Set docker metatdata | |
| - name: Docker Metadata | |
| id: docker_metadata | |
| uses: docker/metadata-action@318604b99e75e41977312d83839a89be02ca4893 #v5.9.0 | |
| env: | |
| DOCKER_METADATA_ANNOTATIONS_LEVELS: manifest,index | |
| with: | |
| images: ${{ env.DOCKER_IMAGES }} | |
| labels: | | |
| org.opencontainers.image.created={{commit_date 'YYYY-MM-DDTHH:mm:ss.SSS[Z]'}} | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| annotations: | | |
| org.opencontainers.image.description=${{ steps.repo_desc.outputs.description }} | ${{ env.ANNOTATION_PATTERN}} Image | |
| org.opencontainers.image.title=Stacks Core ${{ env.ANNOTATION_PATTERN}} | |
| tags: | | |
| # if trigger is workflow_dispatch | |
| type=ref,event=branch,enable=${{ github.event_name == 'workflow_dispatch' }} | |
| # if trigger is schedule, use a timestamp | |
| type=schedule,pattern={{date 'YYYYMMDD'}} | |
| ## Build and push the docker image(s) | |
| - name: Build and Push | |
| id: docker_build | |
| uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 | |
| with: | |
| sbom: false | |
| provenance: ${{ env.PROVENANCE }} | |
| context: /tmp | |
| file: ./.github/actions/dockerfiles/debian/Dockerfile | |
| platforms: ${{ env.DOCKER_PLATFORMS }} | |
| tags: ${{ steps.docker_metadata.outputs.tags }} | |
| labels: ${{ steps.docker_metadata.outputs.labels }} | |
| annotations: ${{ steps.docker_metadata.outputs.annotations }} # Note: annotations are used for multi-architecture ghcr images | |
| push: ${{ env.DOCKER_PUSH }} | |
| ## Generate docker image attestation(s) | |
| - name: Attest Image | |
| if: | | |
| env.PROVENANCE != true | |
| id: attest_artifact | |
| uses: actions/attest-build-provenance@977bb373ede98d70efdf65b84cb5f73e068dcc2a # v3.0.0 | |
| with: | |
| subject-name: | | |
| ${{ env.DOCKER_IMAGES }} | |
| subject-digest: ${{ steps.docker_build.outputs.digest }} | |
| push-to-registry: ${{ env.DOCKER_PUSH }} | |
| ## Sign the images with GitHub OIDC Token | |
| ## - https://github.blog/security/supply-chain-security/safeguard-container-signing-capability-actions/ | |
| ## - annotations show as null per https://github.com/sigstore/cosign/pull/4508 until a future release (or tagging this specific commit) | |
| - name: Install Cosign | |
| id: cosign_install | |
| uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 | |
| - name: Sign the images OIDC Token | |
| id: cosign_image | |
| shell: bash | |
| env: | |
| DIGEST: ${{ steps.docker_build.outputs.digest }} | |
| TAGS: ${{ steps.docker_metadata.outputs.tags }} | |
| run: | | |
| images="" | |
| for tag in ${TAGS}; do | |
| images+="${tag}@${DIGEST} " | |
| done | |
| cosign sign \ | |
| -a "repo=${{ github.repository }}" \ | |
| -a "ref=${{ github.sha }}" \ | |
| --yes \ | |
| ${images} |