Skip to content

Build container image #153

Build container image

Build container image #153

Workflow file for this run

---
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