Merge branch 'custom-base-more2' into 'wip-baseimage-rework'

Draft: Rework build system further

See merge request fedora/bootc/base-images!89
This commit is contained in:
Colin Walters (Red Hat) 2025-02-11 14:06:03 +00:00
commit 1a3bfca9fa
14 changed files with 165 additions and 51 deletions

View File

@ -16,8 +16,10 @@ build:
set -xeuo pipefail
curl -L --fail -o /etc/yum.repos.d/coreos-continuous.repo https://copr.fedorainfracloud.org/coprs/g/CoreOS/continuous/repo/fedora-42/group_CoreOS-continuous-fedora-42.repo
dnf -y install rpm-ostree
buildah build "${hostbuildopts[@]}" -f Containerfile.base --no-cache --security-opt=label=disable --cap-add=all --device /dev/fuse -t ${IMAGE_PREFIX}-base:tmp .
cd base
buildah build "${hostbuildopts[@]}" -f Containerfile --no-cache --security-opt=label=disable --cap-add=all --device /dev/fuse -t ${IMAGE_PREFIX}-base:tmp .
# Rechunk
rpm-ostree experimental compose build-chunked-oci --bootc --format-version=1 \
--from=${IMAGE_PREFIX}-base:tmp --output containers-storage:${IMAGE_PREFIX}-base
cd ..
buildah build "${hostbuildopts[@]}" -f Containerfile --no-cache --from ${IMAGE_PREFIX}-base -t ${IMAGE_PREFIX}-standard:tmp .

View File

@ -1,42 +1,18 @@
# This generates the default base image.
# This generates the "standard" base image, deriving from the minimal base.
# This is a local reference by default because we haven't shipped this image yet.
FROM localhost/fedora-bootc:base
# Drop our package sets into /usr/share/doc, so that other things can parse it
COPY packages*.txt /usr/share/doc/fedora-bootc/
# Overlay our defaults
# Copy in our configuration and build scripts. Most of the heavy lifting
# is in `stage-install` which we emit into /usr/share/doc so it can be
# used as a reference in other images.
COPY usr/ /usr/
RUN <<EORUN
set -euo pipefail
dnf_args=()
echo "Loading packages-excluded"
basedir=/usr/share/doc/fedora-bootc/
for x in $(grep -E -v '^#' ${basedir}/packages-excluded.txt); do
dnf_args+=(--exclude ${x})
done
echo "Loading packages"
package_files=(${basedir}/packages-recommended-minimal.txt ${basedir}/packages.txt)
pkgfile_for_arch=/usr/share/doc/fedora-bootc/packages-$(arch).txt
if test -f ${pkgfile_for_arch}; then
echo "Loading ${pkgfile_for_arch}"
package_files+=(${pkgfile_for_arch})
fi
base_pkgs=$(grep -hE -v '^#' ${package_files[@]})
dnf -y ${dnf_args[@]} install $base_pkgs
# Ensure we regenerate the initramfs with new content
# https://docs.fedoraproject.org/en-US/bootc/initramfs/
kver=$(cd /usr/lib/modules && echo *); dracut -vf /usr/lib/modules/$kver/initramfs.img $kver
# Undo RPM scripts enabling units; we want the presets to be canonical for the base image.
# https://github.com/projectatomic/rpm-ostree/issues/1803
rm -rf /etc/systemd/system/*
systemctl preset-all
rm -rf /etc/systemd/user/*
systemctl --user --global preset-all
dnf clean all
# Lots of cleaning
rm -vrf /var/log /var/cache /var/lib/dnf
set -xeuo pipefail
# This script installs our default packages. These scripts
# are not a stable API, but may become one in the future.
/usr/share/doc/bootc-image-standard/stage-install
# Cleanup
/usr/share/doc/bootc-image-standard/stage-clean
# And lint.
bootc container lint
EORUN

View File

@ -8,26 +8,26 @@
# If you want to configure the input rpm-md repositories, just override this
# container image.
FROM quay.io/fedora/fedora:rawhide as repos
# See https://github.com/coreos/rpm-ostree/issues/3397
RUN ln -sr /usr/lib/sysimage/rpm /usr/share/rpm
# BOOTSTRAPPING: This can be any image that has the following packages.
FROM registry.gitlab.com/fedora/bootc/base-images-dev/fedora-bootc-dev:rawhide as builder
RUN dnf -y install rpm-ostree selinux-policy-targeted sqlite
# We use stream10 to demonstrate that we support "cross builds".
FROM quay.io/centos/centos:stream10 as builder
RUN <<EORUN
set -xeuo pipefail
# For rpm-ostree v2025.5
curl -L -o /etc/yum.repos.d/coreos-continuous.repo https://copr.fedorainfracloud.org/coprs/g/CoreOS/continuous/repo/centos-stream-10/group_CoreOS-continuous-centos-stream-10.repo
dnf -y install rpm-ostree selinux-policy-targeted sqlite
EORUN
# Copy in our source code.
COPY . /src
WORKDIR /src
RUN --mount=type=bind,from=repos,src=/,dst=/repos <<EORUN
RUN --mount=type=bind,from=repos,src=/,dst=/repos,rw <<EORUN
set -xeuo pipefail
# Synchronize the dnf/rpm configs from the repos container.
for x in etc/dnf etc/yum.repos.d etc/pki/rpm-gpg; do
rm -rf /"$x" && cp -a /repos/${x} /$x
done
# And copy to the workdir; TODO fix this in rpm-ostree
cp /etc/yum.repos.d/*.repo base
rpm-ostree experimental compose rootfs --source-root=/repos base/manifest.yaml /target-rootfs
# Embed the configuration in the image itself, so that it can be used by later builds as well
cp -a base /target-rootfs/usr/lib/sysimage/base-image-manifests
# Copy the build configuration into the builder image, as if it's the final image
cp -a . /usr/lib/sysimage/base-image-manifest
# And embed the rebuild script
install -m 0755 -t /usr/libexec ./bootc-base-image-rebuild-self
# Finally, run the build script in the same way we expect custom images to do.
/usr/libexec/bootc-base-image-rebuild-self /repos /target-rootfs
EORUN
# This pulls in the rootfs generated in the previous step

2
base/Makefile Normal file
View File

@ -0,0 +1,2 @@
install:
install -m 0755 -t $(DESTDIR)/usr/libexec bootc-base-image-rebuild-self

View File

@ -0,0 +1,17 @@
#!/bin/bash
# This script regenerates this base image using a build
# configuration (list of packages, scripts) embedded in this current image.
# The actual *content* packages will come from the source root.
set -xeuo pipefail
source_root=$1
shift
target=$1
shift
if ! test -x /usr/bin/rpm-ostree; then
dnf -y install rpm-ostree
fi
rpm-ostree experimental compose rootfs --source-root-rw=$source_root /usr/lib/sysimage/base-image-manifest/manifest.yaml $target
# Finally, propagate the configuration and build script into the target root.
for f in /usr/lib/sysimage/base-image-manifest /usr/libexec/bootc-base-image-rebuild-self; do
cp -a $f $target/$f
done

View File

@ -0,0 +1,83 @@
# bootc-base-image-rebuild-self
A core premise of the bootc model is that rich
control over Linux system customization can be accomplished
with a "default" container build:
```
FROM <base image>
RUN ...
```
As of recently, it is possible to e.g. swap the kernel
and other fundamental components as part of default derivation.
## Understanding the base image content
Most, but not all content from the base image comes from RPMs.
There is some additional non-RPM content, as well as postprocessing
that operates on the filesystem root. At the current
time the implementation of the base image build uses `rpm-ostree`,
but this is considered an implementation detail subject to change.
## Rebuilding from externally controlled content
Some use cases want even more control - for example,
as an organization deploying a bootc system, I may want to ensure
the base image version carries a set of packages at
exactly specific versions (perhaps defined by a lockfile,
or an rpm-md repository). There are many tools which
manage snapshots of yum (rpm-md) repositories.
The `/usr/libexec/bootc-base-image-rebuild-self` which is
included in the base image is designed to enable this
level of control.
## Using bootc-base-image-rebuild-self
This tool takes just two arguments:
- A "repository configuration root" which should have an `/etc/yum.repos.d`
that defines the input RPM content.
- A path to the target root filesystem which will be generated
### Implementation
The current implementation uses `rpm-ostree` on a manifest (treefile)
embedded in the container image itself. The set of packages installed
is currently not configurable; however it is quite minimal and can
easily be customized further as we will see below.
The build tooling is designed to support "cross builds"; the
repository root could e.g. be CentOS Stream 10, while the
builder root is Fedora or RHEL, etc. In other words, one given
base image can be used as a "builder" to produce another
using different RPMs.
### Example: Generate a new image using CentOS Stream 10 content from RHEL
FROM quay.io/centos/centos:stream10 as repos
FROM registry.redhat.io/rhel10/rhel-bootc:10 as builder
RUN --mount=type=bind,from=repos,src=/,dst=/repos,rw /usr/libexec/bootc-base-image-rebuild-self /repos /target-rootfs
# This container image uses the "artifact pattern"; it has some
# basic configuration we expect to apply to multiple container images.
FROM quay.io/exampleos/baseconfig@sha256:.... as baseconfig
FROM scratch
COPY --from=builder /target-rootfs/ /
# Now we make other arbitrary changes. Copy our systemd units and
# other tweaks from the baseconfig container image.
COPY --from=baseconfig /usr/ /usr/
RUN <<EORUN
set -xeuo pipefail
# Install critical components
dnf -y install linux-firmware NetworkManager cloud-init cowsay
dnf clean all
bootc container lint
EORUN
LABEL containers.bootc 1
ENV container=oci
STOPSIGNAL SIGRTMIN+3
CMD ["/sbin/init"]

View File

@ -0,0 +1,5 @@
#!/bin/bash
set -xeuo pipefail
dnf clean all
# Lots of cleaning
rm -vrf /var/log /var/cache /var/lib/dnf

View File

@ -0,0 +1,29 @@
#!/bin/bash
set -euo pipefail
dn=$(dirname $0)
cd ${dn}
dnf_args=()
echo "Loading packages-excluded"
for x in $(grep -E -v '^#' packages-excluded.txt); do
dnf_args+=(--exclude ${x})
done
echo "Loading packages"
package_files=(packages-recommended-minimal.txt packages.txt)
pkgfile_for_arch=packages-$(arch).txt
if test -f ${pkgfile_for_arch}; then
echo "Loading ${pkgfile_for_arch}"
package_files+=(${pkgfile_for_arch})
fi
base_pkgs=$(grep -hE -v '^#' ${package_files[@]})
dnf -y ${dnf_args[@]} install $base_pkgs
# Ensure we regenerate the initramfs with new content
# https://docs.fedoraproject.org/en-US/bootc/initramfs/
kver=$(cd /usr/lib/modules && echo *); dracut -vf /usr/lib/modules/$kver/initramfs.img $kver
# Undo RPM scripts enabling units; we want the presets to be canonical for the base image.
# https://github.com/projectatomic/rpm-ostree/issues/1803
rm -rf /etc/systemd/system/*
systemctl preset-all
rm -rf /etc/systemd/user/*
systemctl --user --global preset-all