Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
554 changes: 242 additions & 312 deletions .github/workflows/build-hypervisor.yml

Large diffs are not rendered by default.

248 changes: 105 additions & 143 deletions .github/workflows/build-minimal-bootc.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Build Fedora Minimal Bootc

on:
# Manual trigger with version selection
workflow_dispatch:
inputs:
fedora_version:
Expand All @@ -13,199 +12,162 @@ on:
- '43'
- '44'
- 'rawhide'
rechunk:
description: 'Rechunk the image for better efficiency'
required: false
default: true
type: boolean

# Weekly build (Saturdays at 2am UTC)
schedule:
- cron: '0 2 * * 6'

# Build on pushes to main that touch these files
push:
branches:
- main
branches: [main]
paths:
- 'fedora-bootc-minimal.Containerfile'
- 'policy-minimal.json.template'
- 'cosign.pub'
- '.github/workflows/build-minimal-bootc.yml'

concurrency:
group: build-minimal-bootc-${{ github.ref }}
cancel-in-progress: false

env:
STABLE_FEDORA_VERSION: '43'
IMAGE_NAME: fedora-bootc-minimal

jobs:
build-minimal-bootc:
runs-on: ubuntu-24.04 # Required by rechunk action for advanced podman features
build:
runs-on: ubuntu-24.04
timeout-minutes: 90
permissions:
contents: read
packages: write
id-token: write

strategy:
matrix:
# Build for multiple Fedora versions
fedora_version:
- '43'

steps:
- name: Setup podman
- name: Checkout repository
uses: actions/checkout@v4

- name: Resolve build parameters
id: params
env:
INPUT_VERSION: ${{ inputs.fedora_version }}
OWNER_RAW: ${{ github.repository_owner }}
run: |
sudo apt-get update
sudo apt-get install -y podman
podman --version
VERSION="${INPUT_VERSION:-${STABLE_FEDORA_VERSION}}"
OWNER=$(echo "$OWNER_RAW" | tr '[:upper:]' '[:lower:]')
TAG=$(date +%Y%m%d-%H%M)
{
echo "version=${VERSION}"
echo "owner=${OWNER}"
echo "tag=${TAG}"
echo "image_base=ghcr.io/${OWNER}/${IMAGE_NAME}"
} >> "$GITHUB_OUTPUT"

- name: Install cosign
uses: sigstore/cosign-installer@v3.7.0

- name: Set Fedora version
id: set_version
- name: Install podman
run: |
# Use manual input if provided, otherwise use matrix version
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "version=${{ inputs.fedora_version }}" >> $GITHUB_OUTPUT
else
echo "version=${{ matrix.fedora_version }}" >> $GITHUB_OUTPUT
fi

- name: Checkout repository
uses: actions/checkout@v4
sudo apt-get update
sudo apt-get install -y podman
podman --version

- name: Generate /etc/containers/policy.json for github keyless signing
# owner needs to be lowercase, but workflow ref needs to preserve case
- name: Render policy.json
env:
OWNER: ${{ steps.params.outputs.owner }}
run: |
OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')

sed -e "s|__REGISTRY_NAMESPACE__|${OWNER}|g" \
-e "s|__MINIMAL_WORKFLOW_REF__|${{ github.workflow_ref }}|g" \
policy-minimal.json.template > policy.json

echo "Generated policy.json for minimal:"
cat policy.json

- name: Set build timestamp
id: timestamp
run: |
echo "tag=$(date +%Y%m%d-%H%M)" >> $GITHUB_OUTPUT

- name: Clone Fedora bootc manifests
run: |
git clone --depth 1 https://gitlab.com/fedora/bootc/base-images.git manifests
cd manifests
git log -1
echo "Using local podman 4-compatible Containerfile with upstream manifests"

- name: Copy policy.json into build context
run: |
git -C manifests log -1
cp policy.json manifests/policy.json
echo "Copied policy.json to manifests/ directory"
cp cosign.pub manifests/cosign.pub

- name: Build minimal bootc container
- name: Build minimal bootc image
env:
VERSION: ${{ steps.params.outputs.version }}
TAG: ${{ steps.params.outputs.tag }}
run: |
sudo podman build \
--security-opt=label=disable \
--cap-add=all \
--device /dev/fuse \
-f fedora-bootc-minimal.Containerfile \
--build-arg MANIFEST=minimal \
--build-arg BUILDER_IMAGE=quay.io/fedora/fedora:${{ steps.set_version.outputs.version }} \
--build-arg REPOS_IMAGE=quay.io/fedora/fedora:${{ steps.set_version.outputs.version }} \
-t localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }} \
--build-arg BUILDER_IMAGE=quay.io/fedora/fedora:${VERSION} \
--build-arg REPOS_IMAGE=quay.io/fedora/fedora:${VERSION} \
-t localhost/${IMAGE_NAME}:build \
manifests
sudo podman inspect localhost/${IMAGE_NAME}:build > /dev/null

- name: Test built image
run: |
sudo podman images | grep fedora-bootc-minimal
sudo podman inspect localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }}

- name: Rechunk image with bootc-base-imagectl
- name: Rechunk image
env:
VERSION: ${{ steps.params.outputs.version }}
run: |
# Use bootc-base-imagectl rechunk (official bootc method)
sudo podman run --rm --privileged \
-v /var/lib/containers:/var/lib/containers \
quay.io/fedora/fedora-bootc:${{ steps.set_version.outputs.version }} \
quay.io/fedora/fedora-bootc:${VERSION} \
/usr/libexec/bootc-base-imagectl rechunk \
localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }} \
localhost/fedora-bootc-minimal:rechunked
localhost/${IMAGE_NAME}:build \
localhost/${IMAGE_NAME}:rechunked

# List all images to verify rechunk created the image
echo "All images after rechunk:"
sudo podman images

- name: Tag rechunked image
run: |
# Apply all the tags we need to the rechunked image
sudo podman tag localhost/fedora-bootc-minimal:rechunked \
localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }}
sudo podman tag localhost/fedora-bootc-minimal:rechunked \
localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}
sudo podman tag localhost/fedora-bootc-minimal:rechunked \
localhost/fedora-bootc-minimal:latest

# Clean up the temporary rechunked tag
sudo podman rmi localhost/fedora-bootc-minimal:rechunked

- name: Login to GitHub Container Registry
- name: Login to GHCR
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ACTOR: ${{ github.actor }}
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | sudo podman login ghcr.io -u ${{ github.actor }} --password-stdin

- name: Push to GitHub Container Registry
echo "$GH_TOKEN" | sudo podman login ghcr.io -u "$ACTOR" --password-stdin
echo "$GH_TOKEN" | cosign login ghcr.io -u "$ACTOR" --password-stdin

- name: Tag and push
id: push
env:
IMAGE_BASE: ${{ steps.params.outputs.image_base }}
VERSION: ${{ steps.params.outputs.version }}
TAG: ${{ steps.params.outputs.tag }}
run: |
# Lowercase repository owner for ghcr.io compatibility
OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')

# Tag with timestamp and version
sudo podman tag localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }} \
ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }}

sudo podman tag localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }} \
ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}

# Also tag 'latest' for the stable version
if [ "${{ steps.set_version.outputs.version }}" == "43" ]; then
sudo podman tag localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }} \
ghcr.io/${OWNER}/fedora-bootc-minimal:latest
TAGS=("${VERSION}-${TAG}" "${VERSION}")
if [ "${VERSION}" = "${STABLE_FEDORA_VERSION}" ]; then
TAGS+=("latest")
fi

# Push all tags
sudo podman push ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }}
sudo podman push ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}

if [ "${{ steps.set_version.outputs.version }}" == "43" ]; then
sudo podman push ghcr.io/${OWNER}/fedora-bootc-minimal:latest
fi

- name: Login to GitHub Container Registry for cosign
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | cosign login ghcr.io -u ${{ github.actor }} --password-stdin

- name: Sign images with cosign
FIRST=true
for t in "${TAGS[@]}"; do
sudo podman tag localhost/${IMAGE_NAME}:rechunked "${IMAGE_BASE}:${t}"
if [ "${FIRST}" = "true" ]; then
sudo podman push --digestfile /tmp/digest.txt "${IMAGE_BASE}:${t}"
FIRST=false
else
sudo podman push "${IMAGE_BASE}:${t}"
fi
done

DIGEST=$(cat /tmp/digest.txt)
{
printf 'tags<<EOF\n%s\nEOF\n' "${TAGS[*]}"
echo "digest=${DIGEST}"
} >> "$GITHUB_OUTPUT"

- name: Sign images
env:
COSIGN_PRIVATE_KEY: ${{ secrets.COSIGN_SECRET }}
IMAGE_BASE: ${{ steps.params.outputs.image_base }}
DIGEST: ${{ steps.push.outputs.digest }}
run: |
OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')

cosign sign --yes ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }}

cosign sign --yes ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}
cosign sign -y --key env://COSIGN_PRIVATE_KEY "${IMAGE_BASE}@${DIGEST}"

if [ "${{ steps.set_version.outputs.version }}" == "43" ]; then
cosign sign --yes ghcr.io/${OWNER}/fedora-bootc-minimal:latest
fi

- name: Cleanup local images
- name: Summary
env:
IMAGE_BASE: ${{ steps.params.outputs.image_base }}
TAGS: ${{ steps.push.outputs.tags }}
run: |
OWNER=$(echo "${{ github.repository_owner }}" | tr '[:upper:]' '[:lower:]')

# Remove all local tags from root storage
sudo podman rmi localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }} || true
sudo podman rmi localhost/fedora-bootc-minimal:${{ steps.set_version.outputs.version }} || true
sudo podman rmi localhost/fedora-bootc-minimal:latest || true
sudo podman rmi ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }}-${{ steps.timestamp.outputs.tag }} || true
sudo podman rmi ghcr.io/${OWNER}/fedora-bootc-minimal:${{ steps.set_version.outputs.version }} || true

# Also clean up :latest tag if it was pushed
if [ "${{ steps.set_version.outputs.version }}" == "43" ]; then
sudo podman rmi ghcr.io/${OWNER}/fedora-bootc-minimal:latest || true
fi

# Prune root storage to remove dangling layers
sudo podman system prune -af --volumes

# Show final disk usage
df -h
{
echo "## Minimal bootc build complete"
echo ""
echo "Pushed and signed:"
for t in $TAGS; do
echo "- \`${IMAGE_BASE}:${t}\`"
done
} >> "$GITHUB_STEP_SUMMARY"
4 changes: 4 additions & 0 deletions cosign.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1tsMEtSTv5qyeHuDzrsH1OKi5+9q
pTwpSBwtGluq8NyAkoNxCJHR0TuL9UbdMjHd37mk6AI4bVyPskxbeD6WIg==
-----END PUBLIC KEY-----
34 changes: 7 additions & 27 deletions fedora-bootc-minimal.Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,40 +27,20 @@ RUN --mount=type=cache,id=bootc-base-image-cache,target=/cache sh -c 'set -xeuo
/usr/libexec/bootc-base-imagectl list >/dev/null && \
/usr/libexec/bootc-base-imagectl build-rootfs --cachedir=/cache --reinject --manifest=${MANIFEST} /repos /target-rootfs'

# get the keys for github keyless signing
FROM alpine AS keyless-keys

RUN apk add curl jq openssl

# writes to ~/.sigstore/root/
RUN curl -o cosign -L "https://github.com/sigstore/cosign/releases/latest/download/cosign-linux-amd64" && \
chmod +x cosign && \
./cosign initialize

# Extract the base64-encoded cosign public key from trusted_root.json,
# decode it from base64, convert from DER to PEM format
RUN mkdir -p /etc/pki/rekor && \
cat ~/.sigstore/root/tuf-repo-cdn.sigstore.dev/targets/trusted_root.json | \
jq -r '.tlogs[0].publicKey.rawBytes' | \
base64 -d > rekor_temp.pub && \
openssl pkey -pubin -inform DER -in rekor_temp.pub -outform PEM -out /etc/pki/rekor/rekor.pub

# same with the fulcio cert
RUN mkdir -p /etc/pki/fulcio && \
cat ~/.sigstore/root/tuf-repo-cdn.sigstore.dev/targets/trusted_root.json | \
jq -r '.certificateAuthorities[0].certChain.certificates[0].rawBytes' | \
base64 -d > fulcio_temp.crt && \
openssl x509 -inform DER -in fulcio_temp.crt -outform PEM -out /etc/pki/fulcio/fulcio.crt.pem


FROM scratch
COPY --from=builder /target-rootfs/ /
COPY --from=keyless-keys /etc/pki /etc/pki
COPY cosign.pub /etc/pki/containers/cosign.pub
COPY policy.json /etc/containers/policy.json

# Bootc labels and metadata
LABEL containers.bootc 1
LABEL ostree.bootable 1
LABEL bootc.diskimage-builder quay.io/centos-bootc/bootc-image-builder

LABEL org.opencontainers.image.title="Minimal Fedora bootc Image"
LABEL org.opencontainers.image.description="Build of Fedora bootc minimal"

ENV container=oci

STOPSIGNAL SIGRTMIN+3
CMD ["/usr/sbin/init"]
10 changes: 0 additions & 10 deletions hypervisor-amd.Containerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,5 @@ RUN mkdir -p /etc/cdi && \
# rocm-smi tries to use libdrm_amdgpu.so, this is a workaround to provide it
RUN ln -s /usr/lib64/libdrm_amdgpu.so.1 /usr/lib64/libdrm_amdgpu.so

# Define required labels for this bootc image to be recognized as such
LABEL containers.bootc 1
LABEL ostree.bootable 1
LABEL org.opencontainers.image.title="Hypervisor Bootc Image - AMD GPU"
LABEL org.opencontainers.image.description="Bootc-based hypervisor with AMD GPU support (ROCm)"

# https://pagure.io/fedora-kiwi-descriptions/pull-request/52
ENV container=oci

# Optional labels that only apply when running this image as a container. These keep the default entry point running under systemd.
STOPSIGNAL SIGRTMIN+3
CMD ["/usr/sbin/init"]
Loading
Loading