Skip to content
Open
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
61 changes: 46 additions & 15 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -99,23 +99,31 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read
strategy:
fail-fast: false
matrix:
# The Containerfile cross-compiles, so a non-native architecture still
# builds on this amd64 runner without emulation.
arch: [amd64, arm64]
env:
ARCH: ${{ matrix.arch }}
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false

- name: Build operator image
run: make buildimg
run: make buildimg IMG="bootc-operator:dev-${ARCH}" PLATFORM="linux/${ARCH}"

- name: Save operator image
run: podman save -o operator-image.tar bootc-operator:dev
run: podman save -o "operator-image-${ARCH}.tar" "bootc-operator:dev-${ARCH}"

- name: Upload operator image
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: operator-image
path: operator-image.tar
name: operator-image-${{ matrix.arch }}
path: operator-image-${{ matrix.arch }}.tar

e2e:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -180,10 +188,10 @@ jobs:
- name: Download operator image
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: operator-image
name: operator-image-amd64

- name: Load operator image
run: podman load -i operator-image.tar
run: podman load -i operator-image-amd64.tar

- name: Fix registries configuration
run: |
Expand All @@ -195,7 +203,7 @@ jobs:
run: make start-bink

- name: Deploy to bink cluster
run: make deploy-bink
run: make deploy-bink IMG=bootc-operator:dev-amd64

- name: Gather deploy logs
if: failure()
Expand All @@ -222,13 +230,29 @@ jobs:
env:
IMAGE: ghcr.io/${{ github.repository }}
steps:
- name: Download operator image
- name: Download operator images
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: operator-image
pattern: operator-image-*
merge-multiple: true

- name: Load operator image
run: podman load -i operator-image.tar
- name: Assemble manifest list
run: |
shopt -s failglob
refs=()
for tar in operator-image-*.tar; do
arch="${tar#operator-image-}"
arch="${arch%.tar}"
podman load -i "$tar"
refs+=("containers-storage:localhost/bootc-operator:dev-$arch")
done
# Guard against a missing artifact silently publishing a partial
# manifest list, which would leave some nodes unable to pull.
if [[ "${#refs[@]}" -lt 2 ]]; then
echo "expected at least 2 architectures, got ${#refs[@]}" >&2
exit 1
fi
podman manifest create bootc-operator:dev "${refs[@]}"

- name: Push to GHCR
env:
Expand All @@ -239,13 +263,20 @@ jobs:
REF_NAME: ${{ github.ref_name }}
run: |
podman login -u "${ACTOR}" -p "${GH_TOKEN}" ghcr.io
podman push bootc-operator:dev "${IMAGE}":dev
podman push bootc-operator:dev "${IMAGE}":"${SHA}"
tags=(dev "${SHA}")

if [[ "${REF}" == refs/tags/v* ]]; then
podman push bootc-operator:dev "${IMAGE}":"${REF_NAME}"
tags+=("${REF_NAME}")
fi

if [[ "${REF}" == refs/heads/main ]]; then
podman push bootc-operator:dev "${IMAGE}":latest
tags+=(latest)
fi

# v2s2 keeps the per-architecture manifests in the same format as
# the images published before this became a manifest list, so the
# only change downstream sees is the added list layer.
for tag in "${tags[@]}"; do
podman manifest push --all --format v2s2 \
bootc-operator:dev "docker://${IMAGE}:${tag}"
done
15 changes: 15 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,26 @@ make deploy-bink BINK_CLUSTER_NAME=dev
```shell
make build # Build all binaries (manager + daemon) to ./bin/
make buildimg # Build the container image (default: bootc-operator:dev)
make buildimg-all # Build a multi-arch manifest list (linux/amd64, linux/arm64)
```

The `bootc-operator` container image contains both the controller and daemon
binaries.

Released images are manifest lists covering `linux/amd64` and `linux/arm64`.
Both binaries are pure Go, so the Containerfile cross-compiles them for the
target architecture instead of emulating the toolchain; building for a
non-native architecture therefore costs about the same as a native build and
needs no qemu setup. To build a single non-native image, pass `PLATFORM`:

```shell
make buildimg PLATFORM=linux/arm64
```

Note that the e2e suite remains amd64-only, because the
[bink](https://github.com/bootc-dev/bink) node images it boots are published
for amd64 alone.

After modifying API types in `api/`, regenerate CRDs and code:

```shell
Expand Down
11 changes: 8 additions & 3 deletions Containerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM quay.io/fedora/fedora-minimal:44 AS buildroot
FROM --platform=$BUILDPLATFORM quay.io/fedora/fedora-minimal:44 AS buildroot
ARG DNF_FLAGS="-y --setopt=install_weak_deps=False"
RUN --mount=type=cache,id=dnf,target=/var/cache/libdnf5 \
dnf install ${DNF_FLAGS} golang
Expand All @@ -9,10 +9,15 @@ COPY go.mod go.sum ./
RUN --mount=type=cache,id=gomod,target=/root/go/pkg/mod \
go mod download
COPY . .
# The buildroot stage always runs on the build host's architecture, so cross
# compile via TARGETARCH rather than emulating the Go toolchain. Both binaries
# are pure Go, hence CGO_ENABLED=0. The Go build cache is content addressed and
# keyed on the target, so sharing it across architectures is safe.
ARG TARGETARCH
RUN --mount=type=cache,id=gomod,target=/root/go/pkg/mod \
--mount=type=cache,id=gobuild,target=/root/.cache/go-build \
go build -o manager ./cmd/controller/ && \
go build -o daemon ./cmd/daemon/
CGO_ENABLED=0 GOARCH=${TARGETARCH} go build -o manager ./cmd/controller/ && \
CGO_ENABLED=0 GOARCH=${TARGETARCH} go build -o daemon ./cmd/daemon/

FROM quay.io/fedora/fedora-minimal:44
COPY --from=builder /workspace/manager /workspace/daemon /usr/local/bin/
Expand Down
11 changes: 9 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Image URL to use all building/pushing image targets
IMG ?= bootc-operator:dev
CONTAINER_TOOL ?= podman
# Architectures published by buildimg-all. Both binaries are pure Go, so the
# Containerfile cross-compiles rather than emulating the toolchain.
PLATFORMS ?= linux/amd64,linux/arm64
# Bink cluster settings. deploy-bink and e2e share the same cluster by default.
# To use a separate dev cluster: make deploy-bink BINK_CLUSTER_NAME=dev
BINK_CLUSTER_NAME ?= e2e
Expand Down Expand Up @@ -89,8 +92,12 @@ build-daemon: ## Build daemon binary.
go build -o bin/daemon ./cmd/daemon/

.PHONY: buildimg
buildimg: ## Build container image.
$(CONTAINER_TOOL) build -t $(IMG) .
buildimg: ## Build container image. PLATFORM=linux/arm64 cross-builds for another arch.
$(CONTAINER_TOOL) build $(if $(PLATFORM),--platform $(PLATFORM)) -t $(IMG) .

.PHONY: buildimg-all
buildimg-all: ## Build a multi-arch manifest list image (override PLATFORMS to change).
$(CONTAINER_TOOL) build --platform $(PLATFORMS) --manifest $(IMG) .

.PHONY: build-update-image
build-update-image: ## Build a derived node image for update testing and push to bink registry.
Expand Down