-
Notifications
You must be signed in to change notification settings - Fork 5
staged-images: Add chunkah-staged bootc base image builds #152
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
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| name: Build chunkah-staged bootc base images | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - 'staged-images/**' | ||
| - '.github/workflows/build-staged-images.yml' | ||
| schedule: | ||
| # Rebuild weekly to pick up upstream base image updates | ||
| - cron: '0 6 * * 1' | ||
| workflow_dispatch: | ||
|
|
||
| concurrency: | ||
| group: ${{ github.workflow }}-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| env: | ||
| REGISTRY: ghcr.io | ||
|
|
||
| jobs: | ||
| # Read sources.json and generate matrices for downstream jobs. | ||
| generate-matrix: | ||
| name: Generate matrix | ||
| runs-on: ubuntu-24.04 | ||
| outputs: | ||
| mirror: ${{ steps.matrix.outputs.mirror }} | ||
| build: ${{ steps.matrix.outputs.build }} | ||
| manifest: ${{ steps.matrix.outputs.manifest }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: extractions/setup-just@v3 | ||
| - id: matrix | ||
| run: | | ||
| echo "mirror=$(just staged-images/ci-mirror-matrix)" >> "$GITHUB_OUTPUT" | ||
| echo "build=$(just staged-images/ci-matrix)" >> "$GITHUB_OUTPUT" | ||
| echo "manifest=$(just staged-images/ci-manifest-matrix)" >> "$GITHUB_OUTPUT" | ||
|
|
||
| # Mirror upstream source images to GHCR so we have our own copy. | ||
| # Upstream registries (quay.io) may delete old manifests, breaking | ||
| # digest-pinned pulls. | ||
| mirror: | ||
| name: Mirror ${{ matrix.name }}:${{ matrix.tag }} | ||
| needs: generate-matrix | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: ${{ fromJson(needs.generate-matrix.outputs.mirror) }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: bootc-dev/actions/bootc-ubuntu-setup@main | ||
| - name: Log in to GHCR | ||
| run: | | ||
| echo "${{ secrets.GITHUB_TOKEN }}" | \ | ||
| podman login -u "${{ github.actor }}" --password-stdin ${{ env.REGISTRY }} | ||
| - name: Mirror image | ||
| run: just staged-images/mirror ${{ matrix.name }}-${{ matrix.tag }} | ||
| env: | ||
| REGISTRY_OWNER: ${{ github.repository_owner }} | ||
|
|
||
| build: | ||
| name: Build ${{ matrix.name }}:${{ matrix.tag }} (${{ matrix.arch }}) | ||
| needs: [generate-matrix, mirror] | ||
| if: ${{ !cancelled() }} | ||
| runs-on: ${{ matrix.runner }} | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: ${{ fromJson(needs.generate-matrix.outputs.build) }} | ||
| steps: | ||
| - uses: actions/checkout@v6 | ||
| - uses: bootc-dev/actions/bootc-ubuntu-setup@main | ||
| - name: Log in to GHCR | ||
| run: | | ||
| echo "${{ secrets.GITHUB_TOKEN }}" | \ | ||
| podman login -u "${{ github.actor }}" --password-stdin ${{ env.REGISTRY }} | ||
| - name: Build staged image | ||
| run: just staged-images/build ${{ matrix.image_key }} | ||
| env: | ||
| SOURCE_FROM_MIRROR: "1" | ||
| REGISTRY_OWNER: ${{ github.repository_owner }} | ||
| - name: Push by digest | ||
| id: push | ||
| run: | | ||
| digest=$(just staged-images/push ${{ matrix.image_key }} ${{ matrix.arch }}) | ||
| echo "digest=${digest}" >> "$GITHUB_OUTPUT" | ||
| env: | ||
| REGISTRY_OWNER: ${{ github.repository_owner }} | ||
| - name: Upload digest artifact | ||
| run: | | ||
| mkdir -p "${{ runner.temp }}/digests" | ||
| echo "${{ steps.push.outputs.digest }}" > "${{ runner.temp }}/digests/${{ matrix.arch }}" | ||
| - uses: actions/upload-artifact@v7 | ||
| with: | ||
| name: staged-digests-${{ matrix.name }}-${{ matrix.tag }}-${{ matrix.arch }} | ||
| path: ${{ runner.temp }}/digests/* | ||
| if-no-files-found: error | ||
| retention-days: 1 | ||
|
|
||
| manifest: | ||
| name: Manifest ${{ matrix.name }}:${{ matrix.tag }} | ||
| needs: [generate-matrix, build] | ||
| if: ${{ !cancelled() }} | ||
| runs-on: ubuntu-24.04 | ||
| permissions: | ||
| contents: read | ||
| packages: write | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: ${{ fromJson(needs.generate-matrix.outputs.manifest) }} | ||
| steps: | ||
| - uses: bootc-dev/actions/bootc-ubuntu-setup@main | ||
| - uses: bootc-dev/actions/create-manifest@main | ||
| with: | ||
| image: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.name }} | ||
| tags: ${{ env.REGISTRY }}/${{ github.repository_owner }}/${{ matrix.name }}:${{ matrix.tag }} | ||
| artifact-pattern: staged-digests-${{ matrix.name }}-${{ matrix.tag }}-* | ||
| registry-login-env: 'false' |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| source-config.json | ||
| out.ociarchive |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| # Rechunk a bootc base image with chunkah | ||
| # | ||
| # Takes an upstream bootc image (fedora-bootc or centos-bootc), strips | ||
| # the /sysroot (ostree data), and rechunks using chunkah for optimal | ||
| # layer reuse across updates. The result is a "staged" base image | ||
| # suitable for use as a FROM base in bootc development. | ||
| # | ||
| # Usage: just staged-images/build fedora-bootc-44 | ||
|
|
||
| ARG SOURCE_IMAGE | ||
| ARG CHUNKAH=quay.io/jlebon/chunkah:latest | ||
| ARG MAX_LAYERS=128 | ||
|
|
||
| FROM ${SOURCE_IMAGE} AS source | ||
|
|
||
| FROM ${CHUNKAH} AS chunkah | ||
| ARG MAX_LAYERS | ||
| RUN --mount=type=bind,target=/run/src,rw \ | ||
|
cgwalters marked this conversation as resolved.
|
||
| --mount=from=source,target=/chunkah,ro \ | ||
| chunkah build \ | ||
| --config /run/src/source-config.json \ | ||
|
cgwalters marked this conversation as resolved.
|
||
| --prune /sysroot/ \ | ||
| --max-layers "${MAX_LAYERS}" \ | ||
| --label ostree.commit- \ | ||
| --label ostree.final-diffid- \ | ||
| > /run/src/out.ociarchive | ||
|
|
||
| FROM oci-archive:out.ociarchive | ||
|
cgwalters marked this conversation as resolved.
|
||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,101 @@ | ||
| _sources := justfile_directory() / "sources.json" | ||
| registry := env("REGISTRY", "ghcr.io") | ||
| registry_owner := env("REGISTRY_OWNER", "bootc-dev") | ||
|
|
||
| # Look up a field from sources.json by image key (e.g. fedora-bootc-43) | ||
| [private] | ||
| _field image field: | ||
| @jq -re --arg n "{{image}}" '.[] | select(.name + "-" + .tag == $n) | .{{field}}' "{{_sources}}" | ||
|
|
||
| # List available staged images | ||
| list: | ||
| @jq -r '.[] | .name + "-" + .tag' "{{_sources}}" | ||
|
|
||
| # Mirror an upstream source image to our registry. | ||
| # Usage: just staged-images/mirror fedora-bootc-43 | ||
| mirror image: | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
| name=$(just {{justfile_directory()}}/_field {{image}} name) | ||
| tag=$(just {{justfile_directory()}}/_field {{image}} tag) | ||
| src=$(just {{justfile_directory()}}/_field {{image}} source) | ||
| dest="{{registry}}/{{registry_owner}}/${name}-source:${tag}" | ||
| # skopeo doesn't support tag@digest, use digest-only form | ||
| src_by_digest="${src%%:*}@${src##*@}" | ||
| echo "Mirroring ${src_by_digest} -> ${dest}" | ||
| skopeo copy --all --retry-times 3 "docker://${src_by_digest}" "docker://${dest}" | ||
| echo "Mirrored ${dest}" | ||
|
|
||
| # Build a staged image locally. | ||
| # Usage: just staged-images/build fedora-bootc-43 | ||
| # Set SOURCE_FROM_MIRROR=1 to pull from registry mirror instead of upstream. | ||
| build image: | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
| name=$(just {{justfile_directory()}}/_field {{image}} name) | ||
| tag=$(just {{justfile_directory()}}/_field {{image}} tag) | ||
| src=$(just {{justfile_directory()}}/_field {{image}} source) | ||
| staged_name="${name}-staged" | ||
| if [ "${SOURCE_FROM_MIRROR:-}" = "1" ]; then | ||
| src="{{registry}}/{{registry_owner}}/${name}-source:${tag}" | ||
| fi | ||
| echo "=== Pulling source image ===" | ||
| podman pull "${src}" | ||
| echo "=== Writing source config ===" | ||
| podman inspect "${src}" > "{{justfile_directory()}}/source-config.json" | ||
| echo "=== Building ${staged_name}:${tag} ===" | ||
| # -v is needed for buildah < 1.44 (see containers/buildah#5952) | ||
| buildah build --skip-unused-stages=false \ | ||
| -v "{{justfile_directory()}}:/run/src" --security-opt=label=disable \ | ||
| --build-arg SOURCE_IMAGE="${src}" \ | ||
| --build-arg MAX_LAYERS=128 \ | ||
| -f "{{justfile_directory()}}/Containerfile" \ | ||
| -t "localhost/${staged_name}:${tag}" \ | ||
| "{{justfile_directory()}}" | ||
| echo "=== Verifying ===" | ||
| echo "Labels:" | ||
| podman inspect "localhost/${staged_name}:${tag}" | jq '.[0].Config.Labels' | ||
| echo "Layer count:" | ||
| podman inspect "localhost/${staged_name}:${tag}" | jq '.[0].RootFS.Layers | length' | ||
| echo "Built localhost/${staged_name}:${tag}" | ||
|
|
||
| # Build all staged images | ||
| build-all: | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
| for image in $(jq -r '.[] | .name + "-" + .tag' "{{_sources}}"); do | ||
| just {{justfile_directory()}}/build "$image" | ||
| done | ||
|
|
||
| # Push a built staged image by digest, print only the digest to stdout. | ||
| # Usage: just staged-images/push fedora-bootc-43 amd64 | ||
| push image arch="": | ||
| #!/bin/bash | ||
| set -euo pipefail | ||
| name=$(just {{justfile_directory()}}/_field {{image}} name) | ||
| tag=$(just {{justfile_directory()}}/_field {{image}} tag) | ||
| staged_name="${name}-staged" | ||
| arch="{{arch}}" | ||
| if [ -z "$arch" ]; then | ||
| arch=$(podman info --format '{{{{.Host.Arch}}') | ||
| fi | ||
| dest="{{registry}}/{{registry_owner}}/${staged_name}" | ||
| # Use a per-arch tag to avoid collisions when pushing in parallel | ||
| push_tag="${tag}-${arch}" | ||
| podman tag "localhost/${staged_name}:${tag}" "${dest}:${push_tag}" >&2 | ||
| digestfile=$(mktemp) | ||
| podman push --retry 3 --digestfile "${digestfile}" "${dest}:${push_tag}" >&2 | ||
| digest=$(cat "${digestfile}") | ||
| rm -f "${digestfile}" | ||
| echo "${digest}" | ||
|
|
||
| # Generate GHA matrices from sources.json (used by CI workflow) | ||
| [private] | ||
| ci-matrix: | ||
| @jq -c '[.[] | . as $img | {name: ($img.name + "-staged"), tag: $img.tag, image_key: ($img.name + "-" + $img.tag), arch: "amd64", runner: "ubuntu-24.04"}, {name: ($img.name + "-staged"), tag: $img.tag, image_key: ($img.name + "-" + $img.tag), arch: "arm64", runner: "ubuntu-24.04-arm"}] | {include: .}' "{{_sources}}" | ||
| [private] | ||
| ci-mirror-matrix: | ||
| @jq -c '[.[] | {name: .name, tag: .tag, source: .source, mirror_name: (.name + "-source")}] | {include: .}' "{{_sources}}" | ||
| [private] | ||
| ci-manifest-matrix: | ||
| @jq -c '[.[] | {name: (.name + "-staged"), tag: .tag}] | {include: .}' "{{_sources}}" |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| [ | ||
| { | ||
| "_renovate": "datasource=docker depName=quay.io/fedora/fedora-bootc", | ||
| "name": "fedora-bootc", | ||
| "tag": "43", | ||
| "source": "quay.io/fedora/fedora-bootc:43@sha256:dca83fb0b030b529394a129e82f0f75913d0b21f9da304b7ac048b1f12e48932" | ||
| }, | ||
| { | ||
| "_renovate": "datasource=docker depName=quay.io/fedora/fedora-bootc", | ||
| "name": "fedora-bootc", | ||
| "tag": "44", | ||
| "source": "quay.io/fedora/fedora-bootc:44@sha256:4abd97abb04f600ba7a0eda950fd1d241d43bf472fd9fdd85e87a6be6cd5b1d1" | ||
| }, | ||
| { | ||
| "_renovate": "datasource=docker depName=quay.io/centos-bootc/centos-bootc", | ||
| "name": "centos-bootc", | ||
| "tag": "stream9", | ||
| "source": "quay.io/centos-bootc/centos-bootc:stream9@sha256:2b96ee6f7157ed79c0f3db4d2c56686444e61733cabddc6229711c6a6b5dd673" | ||
| }, | ||
| { | ||
| "_renovate": "datasource=docker depName=quay.io/centos-bootc/centos-bootc", | ||
| "name": "centos-bootc", | ||
| "tag": "stream10", | ||
| "source": "quay.io/centos-bootc/centos-bootc:stream10@sha256:43d2199dc2b147905ff3970b77957ac4775554b5ee6973abb577243a3fa28614" | ||
| } | ||
| ] |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.