From 5a71d86c6c515b3af3377c97964a5fe32359725a Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sun, 16 Nov 2025 11:49:44 -0500 Subject: [PATCH 1/7] Justfile: Stop using --label flag to fix layer caching This broke caching with podman 5.6; it's fixed as of https://github.com/containers/buildah/commit/fb6ce9d but it's easy enough for us to just use the `LABEL` instruction anyways. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters --- Justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Justfile b/Justfile index 30c4ea9cd..24c700f90 100644 --- a/Justfile +++ b/Justfile @@ -17,7 +17,7 @@ variant := env("BOOTC_variant", "ostree") base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10") testimage_label := "bootc.testimage=1" -base_buildargs := "--jobs 4 --label=" + testimage_label +base_buildargs := "--jobs 4" buildargs := "--build-arg=base=" + base + " --build-arg=variant=" + variant # Build the container image from current sources. From c199a4900c242586e4d3ead840c6ddc0aaf6abca Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sun, 16 Nov 2025 11:49:26 -0500 Subject: [PATCH 2/7] xtask: Drop some dead code This was used at one point for composefs testing, but no longer. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters --- crates/xtask/src/xtask.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/xtask/src/xtask.rs b/crates/xtask/src/xtask.rs index 7c64cc8aa..bbe56ce6e 100644 --- a/crates/xtask/src/xtask.rs +++ b/crates/xtask/src/xtask.rs @@ -13,7 +13,6 @@ use camino::{Utf8Path, Utf8PathBuf}; use clap::{Args, Parser, Subcommand}; use fn_error_context::context; use rand::Rng; -use serde::Deserialize; use xshell::{cmd, Shell}; mod man; @@ -296,15 +295,6 @@ fn spec(sh: &Shell) -> Result<()> { println!("Generated: {s}"); Ok(()) } - -#[derive(Debug, Deserialize)] -#[allow(dead_code)] -#[serde(rename_all = "PascalCase")] -struct ImageInspect { - pub id: String, - pub digest: String, -} - fn impl_srpm(sh: &Shell) -> Result { { let _g = sh.push_dir("target"); From 0b6ae0e186331dda6872f2a10d881e9f9cf972e7 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sun, 16 Nov 2025 13:40:27 -0500 Subject: [PATCH 3/7] Justfile: Remove unused args for integration test image Squashes a podman build warning; variant and base only apply to the base image. Signed-off-by: Colin Walters --- Justfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Justfile b/Justfile index 24c700f90..3d0e9e79f 100644 --- a/Justfile +++ b/Justfile @@ -29,7 +29,7 @@ build: # This container image has additional testing content and utilities build-integration-test-image: build - cd hack && podman build {{base_buildargs}} -t localhost/bootc-integration-bin {{buildargs}} -f Containerfile . + cd hack && podman build {{base_buildargs}} -t localhost/bootc-integration-bin -f Containerfile . ./tests/build-sealed {{variant}} localhost/bootc-integration-bin localhost/bootc-integration # Keep these in sync with what's used in hack/lbi podman pull -q --retry 5 --retry-delay 5s quay.io/curl/curl:latest quay.io/curl/curl-base:latest registry.access.redhat.com/ubi9/podman:latest From 8de39f687a559412b36758e1696d59410fddda6c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sun, 16 Nov 2025 14:22:56 -0500 Subject: [PATCH 4/7] Justfile: Drop --jobs=4 See the comment for more info. Signed-off-by: Colin Walters --- Justfile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Justfile b/Justfile index 3d0e9e79f..1b2a4d19a 100644 --- a/Justfile +++ b/Justfile @@ -17,7 +17,16 @@ variant := env("BOOTC_variant", "ostree") base := env("BOOTC_base", "quay.io/centos-bootc/centos-bootc:stream10") testimage_label := "bootc.testimage=1" -base_buildargs := "--jobs 4" +# We used to have --jobs=4 here but sometimes that'd hit this +# ``` +# [2/3] STEP 2/2: RUN --mount=type=bind,from=context,target=/run/context < Using cache b068d42ac7491067cf5fafcaaf2f09d348e32bb752a22c85bbb87f266409554d +# --> b068d42ac749 +# + cd /run/context/ +# /bin/sh: line 3: cd: /run/context/: Permission denied +# ``` +# TODO: Gather more info and file a buildah bug +base_buildargs := "" buildargs := "--build-arg=base=" + base + " --build-arg=variant=" + variant # Build the container image from current sources. From c0ae7fb85fa83e817c0e64e583ebaaafd9504add Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 18 Nov 2025 15:35:29 -0500 Subject: [PATCH 5/7] build-sys: Drop some dead code - The ci/Dockerfile.fcos has been unused for some time and testing with FCOS derivatives is already done outside of CI here - Drop the bits which reference git in the Makefile, a new rule I'm trying to impose here is that nothing in the build system should rely on git (or at least not rely on being built from a git repository) Signed-off-by: Colin Walters --- Makefile | 7 ------- ci/Dockerfile.fcos | 11 ----------- 2 files changed, 18 deletions(-) delete mode 100644 ci/Dockerfile.fcos diff --git a/Makefile b/Makefile index 92bda3260..083d9cb15 100644 --- a/Makefile +++ b/Makefile @@ -25,10 +25,6 @@ prefix ?= /usr -SOURCE_DATE_EPOCH ?= $(shell git log -1 --pretty=%ct) -# https://reproducible-builds.org/docs/archives/ -TAR_REPRODUCIBLE = tar --mtime="@${SOURCE_DATE_EPOCH}" --sort=name --owner=0 --group=0 --numeric-owner --pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime - # Enable rhsm if we detect the build environment is RHEL-like. # We may in the future also want to include Fedora+derivatives as # the code is really tiny. @@ -94,9 +90,6 @@ install-initramfs-dracut: install-initramfs install-all: install install-ostree-hooks install -D -m 0755 target/release/tests-integration $(DESTDIR)$(prefix)/bin/bootc-integration-tests -bin-archive: all - $(MAKE) install DESTDIR=tmp-install && $(TAR_REPRODUCIBLE) --zstd -C tmp-install -cf target/bootc.tar.zst . && rm tmp-install -rf - build-unit-tests: cargo t --no-run diff --git a/ci/Dockerfile.fcos b/ci/Dockerfile.fcos deleted file mode 100644 index 9a90e886e..000000000 --- a/ci/Dockerfile.fcos +++ /dev/null @@ -1,11 +0,0 @@ -# This Dockerfile generates a container image that installs bootc into -# a Fedora CoreOS image. -FROM quay.io/coreos-assembler/fcos-buildroot:testing-devel as builder -WORKDIR /src -COPY . . -RUN make test-bin-archive - -FROM quay.io/fedora/fedora-coreos:testing-devel -COPY --from=builder /src/target/bootc.tar.zst /tmp -COPY ci/usr usr -RUN tar -xvf /tmp/bootc.tar.zst && ostree container commit From 44280e2672fdfcaa1ac5b3ddd4870bb7c666ead3 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Sun, 16 Nov 2025 11:48:43 -0500 Subject: [PATCH 6/7] Dockerfile: Use rpmbuild We were bit before by just doing a `COPY` of our binaries overtop of the base image because that doens't remove old files. Replace the pre-build approach with rpmbuild, and then change to do an rpm-based upgrade so that we fix that problem. Note that we still preserve incremental rebuilds by overriding some of the RPM build process. Assisted-by: Claude Code (Sonnet 4.5) Signed-off-by: Colin Walters --- .dockerignore | 3 + Dockerfile | 127 +++++------------------- Justfile | 24 +++++ contrib/packaging/bootc.spec | 50 +++++++++- contrib/packaging/build-rpm | 44 ++++++++ contrib/packaging/configure-rootfs | 46 +++++++++ contrib/packaging/configure-variant | 26 +++++ contrib/packaging/fedora-extra.txt | 2 + contrib/packaging/install-buildroot | 15 +++ contrib/packaging/install-rpm-and-setup | 24 +++++ 10 files changed, 258 insertions(+), 103 deletions(-) create mode 100755 contrib/packaging/build-rpm create mode 100755 contrib/packaging/configure-rootfs create mode 100755 contrib/packaging/configure-variant create mode 100755 contrib/packaging/install-buildroot create mode 100755 contrib/packaging/install-rpm-and-setup diff --git a/.dockerignore b/.dockerignore index 5f34ec97f..1f5579978 100644 --- a/.dockerignore +++ b/.dockerignore @@ -8,6 +8,9 @@ # Toplevel build bits !Makefile !Cargo.* +# License and doc files needed for RPM +!LICENSE-* +!README.md # We do build manpages from markdown !docs/ # We use the spec file diff --git a/Dockerfile b/Dockerfile index 82691c59c..27b548c25 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,34 +10,26 @@ ARG base=quay.io/centos-bootc/centos-bootc:stream10 FROM scratch as src COPY . /src +# And this image only captures contrib/packaging separately +# to ensure we have more precise cache hits. +FROM scratch as packaging +COPY contrib/packaging / + FROM $base as base -# We could inject other content here +# Mark this as a test image (moved from --label build flag to fix layer caching) +LABEL bootc.testimage="1" # This image installs build deps, pulls in our source code, and installs updated # bootc binaries in /out. The intention is that the target rootfs is extracted from /out # back into a final stage (without the build deps etc) below. -FROM base as build +FROM base as buildroot # Flip this off to disable initramfs code ARG initramfs=1 -# This installs our package dependencies, and we want to cache it independently of the rest. -# Basically we don't want changing a .rs file to blow out the cache of packages. So we only -# copy files necessary -COPY contrib/packaging /tmp/packaging -RUN < /usr/lib/bootc/install/80-rootfs-override.toml < /usr/lib/bootc/install/80-ext4-composefs.toml </dev/null); then + VERSION="${VERSION#v}" + VERSION="${VERSION//-/.}" + else + COMMIT=$(git rev-parse HEAD | cut -c1-10) + COMMIT_TS=$(git show -s --format=%ct) + TIMESTAMP=$(date -u -d @${COMMIT_TS} +%Y%m%d%H%M) + VERSION="${TIMESTAMP}.g${COMMIT}" + fi + echo "Building RPM with version: ${VERSION}" + podman build {{base_buildargs}} {{buildargs}} --build-arg=pkgversion=${VERSION} -t localhost/bootc-pkg --target=build . + +# Build a packages (e.g. RPM) into target/ +# Any old packages will be removed. +package: _packagecontainer + mkdir -p target + rm -vf target/*.rpm + podman run --rm localhost/bootc-pkg tar -C /out/ -cf - . | tar -C target/ -xvf - + # This container image has additional testing content and utilities build-integration-test-image: build cd hack && podman build {{base_buildargs}} -t localhost/bootc-integration-bin -f Containerfile . diff --git a/contrib/packaging/bootc.spec b/contrib/packaging/bootc.spec index 646ad619d..114cd514a 100644 --- a/contrib/packaging/bootc.spec +++ b/contrib/packaging/bootc.spec @@ -1,4 +1,5 @@ %bcond_without check +%bcond_with tests %if 0%{?rhel} >= 9 || 0%{?fedora} > 41 %bcond_without ostree_ext %else @@ -21,7 +22,8 @@ %endif Name: bootc -Version: 1.1.5 +# Ensure this local build overrides anything else. +Version: 99999.0.0 Release: 1%{?dist} Summary: Bootable container system @@ -84,17 +86,49 @@ Recommends: podman %description -n system-reinstall-bootc This package provides a utility to simplify reinstalling the current system to a given bootc image. +%if %{with tests} +%package tests +Summary: Integration tests for bootc +Requires: %{name} = %{version}-%{release} + +%description tests +This package contains the integration test suite for bootc. +%endif + %global system_reinstall_bootc_install_podman_path %{_prefix}/lib/system-reinstall-bootc/install-podman +%if 0%{?container_build} +# Source is already at /src, no subdirectory +%global _buildsubdir . +%endif + %prep +%if ! 0%{?container_build} %autosetup -p1 -a1 # Default -v vendor config doesn't support non-crates.io deps (i.e. git) cp .cargo/vendor-config.toml . %cargo_prep -N cat vendor-config.toml >> .cargo/config.toml rm vendor-config.toml +%else +# Container build: source already at _builddir (/src), nothing to extract +# RPM's %mkbuilddir creates a subdirectory; symlink it back to the source +cd .. +rm -rf %{name}-%{version}-build +ln -s . %{name}-%{version}-build +cd %{name}-%{version}-build +%endif %build +export SYSTEM_REINSTALL_BOOTC_INSTALL_PODMAN_PATH=%{system_reinstall_bootc_install_podman_path} +%if 0%{?container_build} +# Container build: use cargo directly with cached dependencies +export CARGO_HOME=/var/roothome/.cargo +cargo build -j%{_smp_build_ncpus} --release %{?with_rhsm:--features rhsm} \ + --bin=bootc --bin=system-reinstall-bootc \ + %{?with_tests:--bin tests-integration} +make manpages +%else # Build the main bootc binary %if %new_cargo_macros %cargo_build %{?with_rhsm:-f rhsm} @@ -104,7 +138,6 @@ rm vendor-config.toml # Build the system reinstallation CLI binary %global cargo_args -p system-reinstall-bootc -export SYSTEM_REINSTALL_BOOTC_INSTALL_PODMAN_PATH=%{system_reinstall_bootc_install_podman_path} %if %new_cargo_macros # In cargo-rpm-macros, the cargo_build macro does flag processing, # so we need to pass '--' to signify that cargo_args is not part @@ -118,18 +151,24 @@ export SYSTEM_REINSTALL_BOOTC_INSTALL_PODMAN_PATH=%{system_reinstall_bootc_insta %endif make manpages +%endif +%if ! 0%{?container_build} %cargo_vendor_manifest # https://pagure.io/fedora-rust/rust-packaging/issue/33 sed -i -e '/https:\/\//d' cargo-vendor.txt %cargo_license_summary %{cargo_license} > LICENSE.dependencies +%endif %install %make_install INSTALL="install -p -c" %if %{with ostree_ext} make install-ostree-hooks DESTDIR=%{?buildroot} %endif +%if %{with tests} +install -D -m 0755 target/release/tests-integration %{buildroot}%{_bindir}/bootc-integration-tests +%endif mkdir -p %{buildroot}/%{dirname:%{system_reinstall_bootc_install_podman_path}} cat >%{?buildroot}/%{system_reinstall_bootc_install_podman_path} < /tmp/rpmbuild/SPECS/bootc.spec + SPEC_FILE=/tmp/rpmbuild/SPECS/bootc.spec +else + SPEC_FILE="${SRC_DIR}/contrib/packaging/bootc.spec" +fi + +# Build RPM +rpmbuild -bb \ + --define "_topdir /tmp/rpmbuild" \ + --define "_builddir ${SRC_DIR}" \ + --define "container_build 1" \ + --with tests \ + --nocheck \ + "${SPEC_FILE}" + +# Copy built RPMs to output directory +ARCH=$(uname -m) +mkdir -p "${OUTPUT_DIR}" +cp /tmp/rpmbuild/RPMS/${ARCH}/*.rpm "${OUTPUT_DIR}/" +rm -rf /tmp/rpmbuild diff --git a/contrib/packaging/configure-rootfs b/contrib/packaging/configure-rootfs new file mode 100755 index 000000000..1e6d8ebd8 --- /dev/null +++ b/contrib/packaging/configure-rootfs @@ -0,0 +1,46 @@ +#!/bin/bash +# Configure rootfs type for bootc installation +set -xeuo pipefail + +VARIANT="${1:-}" +ROOTFS="${2:-}" + +# Support overriding the rootfs at build time +CONFIG_DIR="/usr/lib/bootc/install" +mkdir -p "${CONFIG_DIR}" + +# Do we have an explicit build-time override? Then write it. +if [ -n "$ROOTFS" ]; then + cat > "${CONFIG_DIR}/80-rootfs-override.toml" < "${CONFIG_DIR}/80-ext4-composefs.toml" < Date: Tue, 18 Nov 2025 13:59:57 -0500 Subject: [PATCH 7/7] build-sys: Always install initramfs module Now that we've cut over to always building + installing via an (RPM) package in our build system, we need to always install the dracut module. Signed-off-by: Colin Walters --- Makefile | 13 +++---------- .../dracut/usr/lib/dracut.conf.d/10-bootc-base.conf | 4 ++-- contrib/packaging/bootc.spec | 3 ++- contrib/packaging/install-rpm-and-setup | 9 +++++---- crates/initramfs/dracut/module-setup.sh | 4 +++- 5 files changed, 15 insertions(+), 18 deletions(-) diff --git a/Makefile b/Makefile index 083d9cb15..daffe5199 100644 --- a/Makefile +++ b/Makefile @@ -67,6 +67,9 @@ install: if [ "$$ID" = "fedora" ] || [[ "$$ID_LIKE" == *"fedora"* ]]; then \ install -D -m 0755 -t $(DESTDIR)/$(prefix)/lib/bootc contrib/scripts/fedora-bootc-destructive-cleanup; \ fi + install -D -m 0644 -t $(DESTDIR)/usr/lib/systemd/system crates/initramfs/*.service + install -D -m 0755 target/release/bootc-initramfs-setup $(DESTDIR)/usr/lib/bootc/initramfs-setup + install -D -m 0755 -t $(DESTDIR)/usr/lib/dracut/modules.d/51bootc crates/initramfs/dracut/module-setup.sh # Run this to also take over the functionality of `ostree container` for example. # Only needed for OS/distros that have callers invoking `ostree container` and not bootc. @@ -76,16 +79,6 @@ install-ostree-hooks: ln -sf ../../../bin/bootc $(DESTDIR)$(prefix)/libexec/libostree/ext/$$x; \ done -# Install code in the initramfs, off by default except in builds from git main right now -# Also the systemd unit hardcodes /usr so we give up the farce of supporting $(prefix) -install-initramfs: - install -D -m 0644 -t $(DESTDIR)/usr/lib/systemd/system crates/initramfs/*.service - install -D -m 0755 target/release/bootc-initramfs-setup $(DESTDIR)/usr/lib/bootc/initramfs-setup - -# Install initramfs files, including dracut module -install-initramfs-dracut: install-initramfs - install -D -m 0755 -t $(DESTDIR)/usr/lib/dracut/modules.d/51bootc crates/initramfs/dracut/module-setup.sh - # Install the main binary, the ostree hooks, and the integration test suite. install-all: install install-ostree-hooks install -D -m 0755 target/release/tests-integration $(DESTDIR)$(prefix)/bin/bootc-integration-tests diff --git a/baseimage/dracut/usr/lib/dracut.conf.d/10-bootc-base.conf b/baseimage/dracut/usr/lib/dracut.conf.d/10-bootc-base.conf index 221f2efd8..5352cb209 100644 --- a/baseimage/dracut/usr/lib/dracut.conf.d/10-bootc-base.conf +++ b/baseimage/dracut/usr/lib/dracut.conf.d/10-bootc-base.conf @@ -3,5 +3,5 @@ # (really hostonly=no should be the default if dracut detects that # it's in a container or so) hostonly=no -# We require ostree in the initramfs -add_dracutmodules+=" ostree " +# We require ostree and our own module in the initramfs +add_dracutmodules+=" ostree bootc " diff --git a/contrib/packaging/bootc.spec b/contrib/packaging/bootc.spec index 114cd514a..83043d344 100644 --- a/contrib/packaging/bootc.spec +++ b/contrib/packaging/bootc.spec @@ -125,7 +125,7 @@ export SYSTEM_REINSTALL_BOOTC_INSTALL_PODMAN_PATH=%{system_reinstall_bootc_insta # Container build: use cargo directly with cached dependencies export CARGO_HOME=/var/roothome/.cargo cargo build -j%{_smp_build_ncpus} --release %{?with_rhsm:--features rhsm} \ - --bin=bootc --bin=system-reinstall-bootc \ + --bin=bootc --bin=system-reinstall-bootc --bin=bootc-initramfs-setup \ %{?with_tests:--bin tests-integration} make manpages %else @@ -200,6 +200,7 @@ fi %{_bindir}/bootc %{_prefix}/lib/bootc/ %{_prefix}/lib/systemd/system-generators/* +%{_prefix}/lib/dracut/modules.d/51bootc/ %if %{with ostree_ext} %{_prefix}/libexec/libostree/ext/* %endif diff --git a/contrib/packaging/install-rpm-and-setup b/contrib/packaging/install-rpm-and-setup index 5eb382b12..449072e91 100755 --- a/contrib/packaging/install-rpm-and-setup +++ b/contrib/packaging/install-rpm-and-setup @@ -10,10 +10,11 @@ rpm -Uvh --oldpackage "${RPM_DIR}"/*.rpm rm -f "${RPM_DIR}"/*.rpm # Regenerate initramfs if we have initramfs-setup -if [ -x /usr/lib/bootc/initramfs-setup ]; then - kver=$(cd /usr/lib/modules && echo *) - env DRACUT_NO_XATTR=1 dracut -vf /usr/lib/modules/$kver/initramfs.img $kver -fi +kver=$(cd /usr/lib/modules && echo *) +# DRACUT_NO_XATTR=1 is the default in newer base images, and +# we have --add bootc here until the change to add the module in base +# images lands. +env DRACUT_NO_XATTR=1 dracut --add bootc -vf /usr/lib/modules/$kver/initramfs.img $kver # Only in this containerfile, inject a file which signifies # this comes from this development image. This can be used in diff --git a/crates/initramfs/dracut/module-setup.sh b/crates/initramfs/dracut/module-setup.sh index 39dfe2388..2e5187dfd 100755 --- a/crates/initramfs/dracut/module-setup.sh +++ b/crates/initramfs/dracut/module-setup.sh @@ -3,7 +3,9 @@ installkernel() { instmods erofs overlay } check() { - require_binaries /usr/lib/bootc/initramfs-setup || return 1 + # We are never installed by default; see 10-bootc-base.conf + # for how base images can opt in. + return 255 } depends() { return 0