Build container image #153
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
| --- | |
| name: Build container image | |
| on: | |
| pull_request: | |
| branches: | |
| - main | |
| schedule: | |
| - cron: '40 10 * * *' # 10:40am UTC everyday | |
| push: | |
| branches: | |
| - main | |
| paths-ignore: | |
| - '**/README.md' | |
| workflow_dispatch: | |
| env: | |
| IMAGE_DESC: "small mods to zirconium for my own convenience" | |
| IMAGE_KEYWORDS: "bootc,niri" | |
| IMAGE_LOGO_URL: "https://avatars.githubusercontent.com/u/120078124?s=200&v=4" # Put your own image here for a fancy profile on https://artifacthub.io/! | |
| IMAGE_NAME: "${{ github.event.repository.name }}" # output image name, usually same as repo name | |
| IMAGE_REGISTRY: "ghcr.io/${{ github.repository_owner }}" # do not edit | |
| DEFAULT_TAG: "latest" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref || github.run_id }}-${{ inputs.brand_name}}-${{ inputs.stream_name }} | |
| cancel-in-progress: true | |
| jobs: | |
| build_push: | |
| name: Build and push image | |
| runs-on: ubuntu-24.04 | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| steps: | |
| - name: Prepare environment | |
| run: | | |
| # Lowercase the image uri | |
| echo "IMAGE_REGISTRY=${IMAGE_REGISTRY,,}" >> ${GITHUB_ENV} | |
| echo "IMAGE_NAME=${IMAGE_NAME,,}" >> ${GITHUB_ENV} | |
| - name: Mount BTRFS for podman storage | |
| if: ${{ matrix.platform != 'arm64' }} | |
| uses: ublue-os/container-storage-action@911baca08baf30c8654933e9e9723cb399892140 | |
| continue-on-error: true | |
| with: | |
| target-dir: /var/lib/containers | |
| mount-opts: compress-force=zstd:2 | |
| - name: Checkout | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| - name: Build Image | |
| id: build_image | |
| run: | | |
| sudo podman build -t "localhost/${{env.IMAGE_NAME}}:${{env.DEFAULT_TAG}}" -f ./Containerfile . | |
| # rechunking an image reorganizes the contents of your custom image in order to even out the amount of data in each layer | |
| # if you are building your image on top of another image, it also ensures that aspect of the base image that was overidden will be removed entirely | |
| # these combined will make downloads more consistent (not faster) and potentially smaller, if you are overriding parts of the base image | |
| # the tradeoff is that the image build itself will take significantly longer, because rechunking is an intensive process | |
| - name: Rechunk Image | |
| id: rechunker | |
| run: | | |
| sudo podman run --rm \ | |
| --privileged \ | |
| -t \ | |
| -v /var/lib/containers:/var/lib/containers \ | |
| "quay.io/centos-bootc/centos-bootc:stream10" \ | |
| /usr/libexec/bootc-base-imagectl rechunk --max-layers 80 \ | |
| "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" \ | |
| "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" | |
| # TODO: remove me when we have a new podman in 26.04 runners | |
| # needed because old podman doesn't push layer annotations for | |
| # the rpm-ostree rechunker at all | |
| - name: Install Podman from Brew | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| run: | | |
| /home/linuxbrew/.linuxbrew/bin/brew install podman | |
| # These `if` statements are so that pull requests for your custom images do not make it publish any packages under your name without you knowing | |
| # They also check if the runner is on the default branch so that things like the merge queue (if you enable it), are going to work | |
| - name: Login to GitHub Container Registry | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| LOGIN_USER: ${{ github.actor }} | |
| run: | | |
| echo "${GITHUB_TOKEN}" | sudo podman login -u "${LOGIN_USER}" --password-stdin "ghcr.io" | |
| echo "${GITHUB_TOKEN}" | docker login -u "${LOGIN_USER}" --password-stdin "ghcr.io" # For cosign | |
| - name: Push to GHCR | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| id: push | |
| env: | |
| IMAGE_REGISTRY: ${{ env.IMAGE_REGISTRY }} | |
| IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
| IMAGE_DIGEST: ${{ steps.load.outputs.digest }} | |
| MAX_RETRIES: 3 | |
| run: | | |
| set -x | |
| # HACK: push a second time so layer annotations are present | |
| # TODO: remove me when https://github.com/containers/podman/issues/27796 fixed | |
| for i in $(seq "${MAX_RETRIES}"); do | |
| sudo /home/linuxbrew/.linuxbrew/bin/podman push --digestfile=/tmp/digestfile "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" "${IMAGE_REGISTRY}/${IMAGE_NAME}:${DEFAULT_TAG}" && break || sleep $((5 * i)); | |
| done | |
| echo "remote_image_digest=$(< /tmp/digestfile)" | tee "${GITHUB_OUTPUT}" | |
| for i in $(seq "${MAX_RETRIES}"); do | |
| sudo /home/linuxbrew/.linuxbrew/bin/podman push --digestfile=/tmp/digestfile "localhost/${IMAGE_NAME}:${DEFAULT_TAG}" "${IMAGE_REGISTRY}/${IMAGE_NAME}:${DEFAULT_TAG}" && break || sleep $((5 * i)); | |
| done | |
| echo "remote_image_digest=$(< /tmp/digestfile)" | tee "${GITHUB_OUTPUT}" | |
| - name: Install Cosign | |
| uses: sigstore/cosign-installer@v4.1.0 | |
| if: github.event_name != 'pull_request' | |
| - name: Sign Image | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| env: | |
| REMOTE_IMAGE_DIGEST: ${{ steps.push.outputs.remote_image_digest }} | |
| COSIGN_EXPERIMENTAL: false | |
| COSIGN_PRIVATE_KEY: ${{ secrets.SIGNING_SECRET }} | |
| run: cosign sign -y --new-bundle-format=false --use-signing-config=false --key env://COSIGN_PRIVATE_KEY "${IMAGE_REGISTRY}/${IMAGE_NAME}@${REMOTE_IMAGE_DIGEST}" | |
| - name: Create Job Outputs | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| env: | |
| IMAGE_NAME: ${{ env.IMAGE_NAME }} | |
| DIGEST: ${{ steps.push.outputs.remote_image_digest }} | |
| run: | | |
| set -x | |
| mkdir -p /tmp/outputs/digests | |
| echo "${DIGEST}" | tee "/tmp/outputs/digests/${IMAGE_NAME}.txt" | |
| - name: Upload Output Artifacts | |
| if: github.event_name != 'pull_request' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch) | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v5 | |
| with: | |
| name: ${{ env.IMAGE_NAME }}-${{ matrix.platform }} | |
| retention-days: 1 | |
| if-no-files-found: error | |
| path: | | |
| /tmp/outputs/digests/*.txt |