From 08fc14eab585b2108839bca2e30a0ebd82ad63a9 Mon Sep 17 00:00:00 2001 From: Wesley van Tilburg Date: Sat, 21 Feb 2026 15:03:14 +0100 Subject: [PATCH] initial commit --- .gitignore | 10 ++ builder.sh | 64 +++++++++++ images/base/manifest.yaml | 43 +++++++ images/shared/base.yaml | 184 ++++++++++++++++++++++++++++++ images/shared/fedora-base.repo | 6 + images/shared/fedora-updates.repo | 6 + images/shared/group | 45 ++++++++ images/shared/passwd | 33 ++++++ 8 files changed, 391 insertions(+) create mode 100644 .gitignore create mode 100755 builder.sh create mode 100644 images/base/manifest.yaml create mode 100644 images/shared/base.yaml create mode 100644 images/shared/fedora-base.repo create mode 100644 images/shared/fedora-updates.repo create mode 100644 images/shared/group create mode 100644 images/shared/passwd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb2e9e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +/*.ociarchive +/.buildid +/cache/ +/debugdata/ +/fedora-comps/ +/fedora-lorax-templates/ +/iso/ +/logs/ +/repo/ +/tmp/ diff --git a/builder.sh b/builder.sh new file mode 100755 index 0000000..00eaebb --- /dev/null +++ b/builder.sh @@ -0,0 +1,64 @@ +#!/bin/bash +set -euxo pipefail + +# Usage: ./builder.sh +if [[ $# -lt 2 ]]; then + echo "Usage: $0 " + exit 1 +fi + +IMAGE="$1" +VERSION="$2" + +IMAGE_DIR="images/${IMAGE}" +MANIFEST="${IMAGE_DIR}/manifest.yaml" +OUTPUT="${IMAGE_DIR}/manifest.ociarchive" +REF="images/${IMAGE}/${VERSION}" + +# --- CHECKS --- +if [[ ! -d "$IMAGE_DIR" ]]; then + echo "Image directory not found: $IMAGE_DIR" + exit 1 +fi + +if [[ ! -f "$MANIFEST" ]]; then + echo "Manifest not found: $MANIFEST" + exit 1 +fi + +# --- PREPARE OSTREE REPO --- +mkdir -p repo cache +if [[ ! -f "repo/config" ]]; then + pushd repo >/dev/null + ostree init --repo=. --mode=bare-user + popd >/dev/null +fi + +ostree --repo=repo config set core.fsync false + +# --- VERSIONING --- +buildid="$(date '+%Y%m%d.0')" +timestamp="$(date --iso-8601=sec)" +echo "${buildid}" > .buildid + +echo "Composing ${VERSION}.${buildid} ..." + +# shared repos +cp images/shared/*.repo "${IMAGE_DIR}" + +# Ensure manifest has correct ref and releasever +sed -i '/^ref:/d' "$MANIFEST" +sed -i '/^releasever:/d' "$MANIFEST" +sed -i "1i releasever: ${VERSION}" "$MANIFEST" +sed -i "1i ref: ${REF}" "$MANIFEST" +# --- COMPOSE IMAGE --- +ARGS=( + "--cachedir=cache" + "--initialize" + "--max-layers=96" +) + +rpm-ostree compose image \ + "${ARGS[@]}" \ + "$MANIFEST" \ + "$OUTPUT" diff --git a/images/base/manifest.yaml b/images/base/manifest.yaml new file mode 100644 index 0000000..f58e40c --- /dev/null +++ b/images/base/manifest.yaml @@ -0,0 +1,43 @@ +metadata: + summary: Effectively just bootc, systemd, kernel, and dnf as a starting point. + +edition: "2024" #todo: figure out what this is used for + +variables: + passwd_mode: full + +# Be minimal +recommends: false + +# Default to `bash` in our container, the same as other containers we ship. +container-cmd: + - /sbin/init + +remove-from-packages: + # Generally we expect other tools to do this (e.g. Ignition or cloud-init) + - [systemd, /usr/lib/systemd/system/sysinit.target.wants/systemd-firstboot.service] + +include: + - ../shared/base.yaml + +packages: + # this is implied by dependencies but let's make it explicit + - coreutils + # We need dnf for building derived container images. In Fedora, this pulls + # in dnf5. In CentOS/RHEL, this pulls in dnf(4). We can simplify this back to + # just `dnf` once the `dnf` package is retired from Fedora. + - /usr/bin/dnf + # Even in minimal, we have this. If you don't want SELinux today, you'll need + # to build a custom image. + - selinux-policy-targeted + # And we want container-selinux because trying to layer it on later currently causes issues. + - container-selinux + # Needed for tpm2 bound luks + - tpm2-tools + +repos: + - fedora-base + - fedora-updates + +labels: + containers.bootc: "1" diff --git a/images/shared/base.yaml b/images/shared/base.yaml new file mode 100644 index 0000000..6163f4c --- /dev/null +++ b/images/shared/base.yaml @@ -0,0 +1,184 @@ +#This file merges all the required yaml files from (https://gitlab.com/fedora/bootc/base-images/-/tree/main/minimal) into one + +#==========================================================postprocess-conf.yaml======================================== +# We want content lifecycled with the image +opt-usrlocal: "root" + +# https://github.com/CentOS/centos-bootc/issues/167 +machineid-compat: true + +rpmdb: target +# We never want rpmdb.sqlite-shm as it's unreproducible +rpmdb-normalize: true + +ignore-removed-users: + - root +ignore-removed-groups: + - root +# By default users and groups are injected to nss-altfiles +# which is immutable. This list moves a selected set +# to /etc/group instead, which is mutable per system +# and allows local users to become part of these groups. +etc-group-members: + - wheel + - systemd-journal + - tss # https://issues.redhat.com/browse/BIFROST-618 + - kvm # https://issues.redhat.com/browse/RHEL-115278 + - adm + +#Only use the newer imports, not the one with backwards compatibility +#The files are retrieved when building to stay in sync with upstream +check-passwd: + type: "file" + filename: "passwd" +check-groups: + type: "file" + filename: "group" + +#==========================================================postprocess-conf.yaml======================================== + +#tmpfiles.yaml +postprocess: + - | + #!/bin/bash + set -xeuo pipefail + cat >/usr/lib/tmpfiles.d/bootc-base-rpmstate.conf <<'EOF' + # Workaround for https://bugzilla.redhat.com/show_bug.cgi?id=771713 + d /var/lib/rpm-state 0755 - - - + EOF + # Workaround for https://issues.redhat.com/browse/RHEL-106203 + rm -f /usr/lib/tmpfiles.d/home.conf + + - | + #!/bin/bash + set -xeuo pipefail + # Transforms /usr/lib/ostree-boot into a bootupd-compatible update payload + /usr/bin/bootupctl backend generate-update-metadata + + # Workaround for https://issues.redhat.com/browse/RHEL-78104 + - | + #!/bin/bash + set -xeuo pipefail + rm -vrf /usr/lib/ostree-boot/loader + + # Set up default root config + - | + #!/usr/bin/env bash + set -xeuo pipefail + mkdir -p /usr/lib/ostree + cat > /usr/lib/ostree/prepare-root.conf << EOF + [composefs] + enabled = yes + [sysroot] + readonly = true + EOF + + #initrams config + - | + #!/usr/bin/env bash + set -xeuo pipefail + mkdir -p /usr/lib/dracut/dracut.conf.d + cat > /usr/lib/dracut/dracut.conf.d/20-bootc-base.conf << 'EOF' + # We want a generic image; hostonly makes no sense as part of a server side build + hostonly=no + # Dracut will always fail to set security.selinux xattrs at build time + # https://github.com/dracut-ng/dracut-ng/issues/1561 + export DRACUT_NO_XATTR=1 + add_dracutmodules+=" kernel-modules dracut-systemd systemd-initrd base ostree " + EOF + cat > /usr/lib/dracut/dracut.conf.d/22-bootc-generic.conf << 'EOF' + # Extra modules that we want by default that are known to exist in the kernel + add_dracutmodules+=" virtiofs " + EOF + cat > /usr/lib/dracut/dracut.conf.d/49-bootc-tpm2-tss.conf << 'EOF' + # We want this for systemd-cryptsetup tpm2 locking + add_dracutmodules+=" tpm2-tss " + EOF + cat > /usr/lib/dracut/dracut.conf.d/59-altfiles.conf << 'EOF' + # https://issues.redhat.com/browse/RHEL-49590 + # On image mode systems we use nss-altfiles for passwd and group, + # this makes sure dracut uses them which also fixes kdump writing to NFS. + install_items+=" /usr/lib/passwd /usr/lib/group " + EOF + + - | + #!/usr/bin/env bash + set -xeuo pipefail + mkdir -p /usr/lib/systemd/system/local-fs.target.wants + if test '!' -f /usr/lib/systemd/system/local-fs.target.wants/tmp.mount; then + ln -sf ../tmp.mount /usr/lib/systemd/system/local-fs.target.wants + fi + sed -i -e 's, /root, /var/roothome,' /usr/lib/tmpfiles.d/provision.conf > /dev/null + sed -i -e '/^d- \/var\/roothome /d' /usr/lib/tmpfiles.d/provision.conf > /dev/null + + - | + #!/usr/bin/env bash + set -xeuo pipefail + source /usr/lib/os-release + mkdir -p /usr/lib/kernel/install.conf.d + echo -e "# kernel-install will not try to run dracut and allow rpm-ostree to\n\ + # take over. Rpm-ostree will use this to know that it is responsible\n\ + # to run dracut and ensure that there is only one kernel in the image\n\ + layout=ostree" | tee /usr/lib/kernel/install.conf /usr/lib/kernel/install.conf.d/00-bootc-kernel-layout.conf > /dev/null + # By default dnf keeps multiple versions of the kernel, with this + # configuration we tell dnf to treat the kernel as everything else. + # https://dnf.readthedocs.io/en/latest/conf_ref.html#main-options + # Let's add the config to a distribution configuration file if dnf5 + # is used, we append to /etc/dnf/dnf.conf if not. + # Also set protect_running_kernel=False, dnf/yum pre-dates Containers and + # uses uname to protect the running kernel even on Container builds. + if [ -d "/usr/share/dnf5/libdnf.conf.d/" ]; then + echo -e "[main]\ninstallonlypkgs=''" >> /usr/share/dnf5/libdnf.conf.d/20-ostree-installonlypkgs.conf + echo -e "[main]\nprotect_running_kernel=False" >> /usr/share/dnf5/libdnf.conf.d/20-ostree-protect_running_kernel.conf + else + echo "installonlypkgs=''" >> /etc/dnf/dnf.conf + echo "protect_running_kernel=False" >> /etc/dnf/dnf.conf + fi + + - | + #!/bin/bash + set -xeuo pipefail + # Override some of the default presets. + cat < usr/lib/systemd/system-preset/85-bootc.preset + # Disable dnf-makecache.timer on bootc/image mode systems + # https://github.com/coreos/fedora-coreos-tracker/issues/1896#issuecomment-2848251507 + disable dnf-makecache.timer + EOF + # Enable bootloader-update.service on F43+. + # https://github.com/coreos/fedora-coreos-tracker/issues/1468#issuecomment-2996654547 + # https://fedoraproject.org/wiki/Changes/AutomaticBootloaderUpdatesBootc + - | + #!/bin/bash + set -xeuo pipefail + source /usr/lib/os-release + if [ $ID == "fedora" ] && [ ${VERSION_ID} -ge 43 ]; then + echo "enable bootloader-update.service" >> /usr/lib/systemd/system-preset/85-bootc.preset + fi + # Undo RPM scripts enabling units; we want the presets to be canonical + # https://github.com/projectatomic/rpm-ostree/issues/1803 + - | + #!/bin/bash + set -xeuo pipefail + rm -rf /etc/systemd/system/* + systemctl preset-all + rm -rf /etc/systemd/user/* + systemctl --user --global preset-all + + + + +packages: + - kernel + # systemd. Also name systemd-pam because it was dropped to a recommends + # but we still want it for handling user logins/sessions. + - systemd systemd-pam + # bootc itself. + - bootc + # Required by bootc install, sgdisk has been replaced by Rust crate + # in bootc https://github.com/containers/bootc/pull/775 + - xfsprogs e2fsprogs dosfstools + - bootupd + +exclude-packages: + - kernel-debug-core + diff --git a/images/shared/fedora-base.repo b/images/shared/fedora-base.repo new file mode 100644 index 0000000..dc08ab3 --- /dev/null +++ b/images/shared/fedora-base.repo @@ -0,0 +1,6 @@ +[fedora-base] +name=Fedora $releasever $basearch Base +mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=fedora-$releasever&arch=$basearch +enabled=1 +gpgcheck=1 +metadata_expire=1d diff --git a/images/shared/fedora-updates.repo b/images/shared/fedora-updates.repo new file mode 100644 index 0000000..38e8c76 --- /dev/null +++ b/images/shared/fedora-updates.repo @@ -0,0 +1,6 @@ +[fedora-updates] +name=Fedora $releasever $basearch Updates +mirrorlist=https://mirrors.fedoraproject.org/metalink?repo=updates-released-f$releasever&arch=$basearch +enabled=1 +gpgcheck=1 +metadata_expire=1d diff --git a/images/shared/group b/images/shared/group new file mode 100644 index 0000000..84fd29d --- /dev/null +++ b/images/shared/group @@ -0,0 +1,45 @@ +root:x:0: +bin:x:1: +daemon:x:2: +sys:x:3: +adm:x:4: +tty:x:5: +disk:x:6: +lp:x:7: +mem:x:8: +kmem:x:9: +wheel:x:10: +cdrom:x:11: +mail:x:12: +man:x:15: +dialout:x:18: +floppy:x:19: +games:x:20: +rpcuser:x:29: +tape:x:33: +video:x:39: +dip:x:40: +ftp:x:50: +lock:x:54: +audio:x:63: +tcpdump:x:72: +nobody:x:99: +users:x:100: +input:x:104: +ceph:x:167: +avahi-autoipd:x:170: +systemd-journal:x:190: +dockerroot:x:986: +cockpit-ws:x:987: +systemd-bus-proxy:x:988: +systemd-resolve:x:989: +systemd-network:x:990: +systemd-timesync:x:991: +chrony:x:992: +sssd:x:993: +kube:x:994: +cgred:x:996: +etcd:x:997: +polkitd:x:998: +ssh_keys:x:999: +nfsnobody:x:65534: diff --git a/images/shared/passwd b/images/shared/passwd new file mode 100644 index 0000000..98df7c7 --- /dev/null +++ b/images/shared/passwd @@ -0,0 +1,33 @@ + +root:x:0:0:Super User:/root:/bin/bash +bin:x:1:1:bin:/bin:/usr/sbin/nologin +daemon:x:2:2:daemon:/sbin:/usr/sbin/nologin +adm:x:3:4:adm:/var/adm:/usr/sbin/nologin +lp:x:4:7:lp:/var/spool/lpd:/usr/sbin/nologin +sync:x:5:0:sync:/sbin:/bin/sync +shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown +halt:x:7:0:halt:/sbin:/sbin/halt +mail:x:8:12:mail:/var/spool/mail:/usr/sbin/nologin +operator:x:11:0:operator:/root:/usr/sbin/nologin +games:x:12:100:games:/usr/games:/usr/sbin/nologin +ftp:x:14:50:FTP User:/var/ftp:/usr/sbin/nologin +rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/usr/sbin/nologin +rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/usr/sbin/nologin +tcpdump:x:72:72::/:/usr/sbin/nologin +sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/usr/sbin/nologin +dbus:x:81:81:System Message Bus:/:/usr/sbin/nologin +nobody:x:99:99:Kernel Overflow User:/:/usr/sbin/nologin +ceph:x:167:167:Ceph daemons:/var/lib/ceph:/usr/sbin/nologin +avahi-autoipd:x:170:170:Avahi IPv4LL Stack:/var/lib/avahi-autoipd:/usr/sbin/nologin +cockpit-ws:x:988:987:User for cockpit-ws:/:/usr/sbin/nologin +systemd-bus-proxy:x:989:988:systemd Bus Proxy:/:/usr/sbin/nologin +systemd-resolve:x:990:989:systemd Resolver:/:/usr/sbin/nologin +systemd-network:x:991:990:systemd Network Management:/:/usr/sbin/nologin +systemd-timesync:x:993:991:systemd Time Synchronization:/:/usr/sbin/nologin +chrony:x:994:992::/var/lib/chrony:/usr/sbin/nologin +sssd:x:995:993:User for sssd:/run/sssd:/usr/sbin/nologin +kube:x:996:994:Kubernetes user:/:/usr/sbin/nologin +dockerroot:x:997:986:Docker User:/var/lib/docker:/usr/sbin/nologin +etcd:x:998:997:etcd user:/var/lib/etcd:/usr/sbin/nologin +polkitd:x:999:998:User for polkitd:/:/usr/sbin/nologin +nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/usr/sbin/nologin