initial debian support

This commit is contained in:
robojerk 2025-08-30 12:36:18 -07:00
parent 4c5a458148
commit 904a1d01ba
36 changed files with 986 additions and 372 deletions

View file

@ -1,69 +1,92 @@
# In order to make a base image as part of a Dockerfile, this container build uses
# nested containerization, so you must build with e.g.
# podman build --security-opt=label=disable --cap-add=all --device /dev/fuse <...>
# Multi-stage build for Debian minimal bootc base images
# Stage 1: Repository setup with apt-cache-ng proxy
FROM debian:sid AS repos
# Build argument for apt-cache-ng proxy (can be empty to disable)
ARG APT_CACHER_NG_PROXY="http://192.168.1.101:3142"
# Copy our repository configuration
COPY debian.repo /etc/apt/sources.list.d/
# Replace the proxy URL placeholder with the actual value
RUN if [ -n "$APT_CACHER_NG_PROXY" ]; then \
sed -i "s|__PROXY_URL__|$APT_CACHER_NG_PROXY|g" /etc/apt/sources.list.d/debian.repo; \
echo "Acquire::http::Proxy \"$APT_CACHER_NG_PROXY\";" > /etc/apt/apt.conf.d/99proxy; \
else \
# If no proxy, replace with direct URLs
sed -i "s|__PROXY_URL__/debian|http://deb.debian.org/debian|g" /etc/apt/sources.list.d/debian.repo; \
sed -i "s|__PROXY_URL__/debian-security|http://security.debian.org/debian-security|g" /etc/apt/sources.list.d/debian.repo; \
fi
# NOTE: This container build will output a single giant layer. It is strongly recommended
# to run the "rechunker" on the output of this build, see
# https://coreos.github.io/rpm-ostree/experimental-build-chunked-oci/
# Stage 2: Builder image with tools
FROM debian:sid AS builder
# Copy repository configuration from repos stage
COPY --from=repos /etc/apt/sources.list.d/ /etc/apt/sources.list.d/
COPY --from=repos /etc/apt/apt.conf.d/ /etc/apt/apt.conf.d/
# Override this repos container to control the base image package versions. For
# example, podman build --from=quay.io/fedora/fedora:41 will get you a system
# that uses Fedora 41 packages. Or inject arbitrary yum repos (COPR, etc) here.
#
# Note we also support --build-arg REPOS_IMAGE=quay.io/fedora/fedora:41 here
# since konflux doesn't yet support --from.
ARG REPOS_IMAGE=quay.io/fedora/fedora:rawhide
ARG BUILDER_IMAGE=quay.io/fedora/fedora:rawhide
FROM $REPOS_IMAGE as repos
# Install build dependencies (excluding apt-ostree since we'll copy it)
RUN apt-get update && apt-get install -y \
selinux-policy-default \
python3 \
polkitd \
pkexec \
libpolkit-gobject-1-0 \
ostree \
&& rm -rf /var/lib/apt/lists/*
# BOOTSTRAPPING: This can be any image that has rpm-ostree, selinux-policy-targeted
# and python3 (for bootc-base-imagectl).
FROM $BUILDER_IMAGE as builder
RUN dnf -y install rpm-ostree selinux-policy-targeted python3
ARG MANIFEST=fedora-standard
# The input git repository has .repo files committed to git rpm-ostree has historically
# emphasized that. But here, we are fetching the repos from the container base image.
# So copy the source, and delete the hardcoded ones in git, and use the container base
# image ones. We can drop the ones commited to git when we hard switch to Containerfile.
COPY . /src
# Avoid umask/permission leakage from the outer environment; ref e.g.
# - https://github.com/coreos/coreos-assembler/pull/4277
# - https://gitlab.com/fedora/bootc/base-images/-/merge_requests/254
# This invocation preserves only the executable bit, and specifically we want to remove:
# - setuid/setgid
# - world writability
# NOTE: This adds world-readability, which is what we intend here as all the content
# is public; there's no secrets in our container build.
RUN chmod -R a=rX,u+w /src
WORKDIR /src
RUN rm -vf /src/*.repo
RUN --mount=type=cache,rw,id=bootc-base-image-cache,target=/cache \
--mount=type=bind,rw,from=repos,src=/,dst=/repos <<EORUN
set -xeuo pipefail
# Put our manifests into the builder image in the same location they'll be in the
# final image.
./install-manifests
# And embed the rebuild script
install -m 0755 -t /usr/libexec ./bootc-base-imagectl
# Verify that listing works
/usr/libexec/bootc-base-imagectl list >/dev/null
# Run the build script in the same way we expect custom images to do, and also
# "re-inject" the manifests into the target, so secondary container builds can use it.
/usr/libexec/bootc-base-imagectl build-rootfs \
--cachedir=/cache --reinject --manifest=${MANIFEST} /repos /target-rootfs
EORUN
# Copy our local apt-ostree binary
COPY apt-ostree /usr/local/bin/
RUN chmod +x /usr/local/bin/apt-ostree
# This pulls in the rootfs generated in the previous step
FROM scratch
COPY --from=builder /target-rootfs/ /
# Copy our tool and manifests
COPY debian-bootc-base-imagectl /usr/local/bin/
COPY install-manifests /usr/local/bin/
RUN chmod +x /usr/local/bin/debian-bootc-base-imagectl /usr/local/bin/install-manifests
LABEL containers.bootc 1
# This is an ad-hoc way for us to reference bootc-image-builder in
# a way that in theory client tooling can inspect and find. Today
# it isn't widely used.
LABEL bootc.diskimage-builder quay.io/centos-bootc/bootc-image-builder
# https://pagure.io/fedora-kiwi-descriptions/pull-request/52
# Copy the manifest directories and files
COPY minimal/ /minimal/
COPY standard/ /standard/
COPY minimal-plus/ /minimal-plus/
COPY iot/ /iot/
COPY debian-includes/ /debian-includes/
COPY *.yaml /
# Install manifests to the expected location
RUN install-manifests
# Set working directory to root where manifests are installed
WORKDIR /
# Set environment variable for manifest directory
ENV MANIFESTDIR=/usr/share/doc/debian-bootc-base-imagectl/manifests
# Initialize OSTree repository
RUN mkdir -p /ostree/repo && ostree init --repo=/ostree/repo --mode=bare
# Create target directory for the build
RUN mkdir -p /build
# Build the minimal rootfs using our tool
RUN debian-bootc-base-imagectl build-rootfs --manifest=debian-13 --target=/build/minimal-rootfs
# Debug: Check what was created
RUN ls -la /build/
RUN ls -la /build/minimal-rootfs/ || echo "minimal-rootfs not found"
# Stage 3: Minimal base image
FROM scratch AS debian-minimal
# Copy the minimal rootfs from builder
COPY --from=builder /build/minimal-rootfs /
# Copy bootc configuration
COPY debian-bootc-config.json /etc/debian-bootc-config.json
# Set labels for bootc-image-builder (consistent with config file)
LABEL com.debian.bootc=true
LABEL ostree.bootable=true
LABEL containers.bootc=1
LABEL bootc.diskimage-builder=quay.io/centos-bootc/bootc-image-builder
LABEL debian.id=debian
LABEL debian.version-id=sid
LABEL org.opencontainers.image.title="Debian Minimal Bootc Base Image"
LABEL org.opencontainers.image.description="Minimal Debian base image for bootc ecosystem"
LABEL org.opencontainers.image.vendor="Debian Project"
LABEL org.opencontainers.image.source="https://github.com/debian/bootc-base-images"
# Set environment and stop signal from config
ENV container=oci
# Make systemd the default
STOPSIGNAL SIGRTMIN+3
CMD ["/sbin/init"]

20
Containerfile.enhanced Normal file
View file

@ -0,0 +1,20 @@
# Enhanced Debian bootc base image with real packages
FROM scratch AS debian-enhanced
# Copy the enhanced rootfs with real Debian packages
COPY enhanced-rootfs /
# Copy bootc configuration
COPY debian-bootc-config.json /etc/debian-bootc-config.json
# Set labels for bootc-image-builder (consistent with config file)
LABEL com.debian.bootc=true
LABEL ostree.bootable=true
LABEL containers.bootc=1
LABEL bootc.diskimage-builder=quay.io/centos-bootc/bootc-image-builder
LABEL debian.id=debian
LABEL debian.version-id=trixie
LABEL org.opencontainers.image.title="Debian Enhanced Bootc Base Image"
LABEL org.opencontainers.image.description="Enhanced Debian base image with real packages for bootc ecosystem"
LABEL org.opencontainers.image.vendor="Debian Project"
LABEL org.opencontainers.image.source="https://github.com/debian/bootc-base-images"
# Set environment and stop signal from config
ENV container=oci
STOPSIGNAL SIGRTMIN+3

View file

@ -0,0 +1,18 @@
# Final enhanced Debian bootc base image with real packages
FROM localhost/debian-bootc:enhanced AS debian-enhanced-final
# Copy bootc configuration
COPY debian-bootc-config.json /etc/debian-bootc-config.json
# Set labels for bootc-image-builder (consistent with config file)
LABEL com.debian.bootc=true
LABEL ostree.bootable=true
LABEL containers.bootc=1
LABEL bootc.diskimage-builder=quay.io/centos-bootc/bootc-image-builder
LABEL debian.id=debian
LABEL debian.version-id=trixie
LABEL org.opencontainers.image.title="Debian Enhanced Bootc Base Image"
LABEL org.opencontainers.image.description="Enhanced Debian base image with real packages for bootc ecosystem"
LABEL org.opencontainers.image.vendor="Debian Project"
LABEL org.opencontainers.image.source="https://github.com/debian/bootc-base-images"
# Set environment and stop signal from config
ENV container=oci
STOPSIGNAL SIGRTMIN+3

18
Containerfile.labels Normal file
View file

@ -0,0 +1,18 @@
# Add labels to enhanced Debian bootc base image
FROM localhost/debian-bootc:enhanced-temp AS debian-enhanced-labeled
# Copy bootc configuration
COPY debian-bootc-config.json /etc/debian-bootc-config.json
# Set labels for bootc-image-builder (consistent with config file)
LABEL com.debian.bootc=true
LABEL ostree.bootable=true
LABEL containers.bootc=1
LABEL bootc.diskimage-builder=quay.io/centos-bootc/bootc-image-builder
LABEL debian.id=debian
LABEL debian.version-id=trixie
LABEL org.opencontainers.image.title="Debian Enhanced Bootc Base Image"
LABEL org.opencontainers.image.description="Enhanced Debian base image with real packages for bootc ecosystem"
LABEL org.opencontainers.image.vendor="Debian Project"
LABEL org.opencontainers.image.source="https://github.com/debian/bootc-base-images"
# Set environment and stop signal from config
ENV container=oci
STOPSIGNAL SIGRTMIN+3

180
README.md
View file

@ -1,99 +1,143 @@
# Fedora bootc base images
# Debian bootc base images
Create and maintain base *bootable* container images from Fedora packages.
This repository contains the configuration and tooling to create minimal Debian base images for the bootc ecosystem. These images serve as templates that bootc-image-builder can use to create bootable disk images.
## Motivation
## Overview
The original Docker container model of using "layers" to model applications has
been extremely successful. This project aims to apply the same technique for
bootable host systems - using standard OCI/Docker containers as a transport and
delivery format for base operating system updates.
Debian bootc base images are minimal container images that contain only the essential packages and configuration needed for a bootable Debian system. They are designed to work with the bootc ecosystem tools like `bootc-image-builder` and `osbuild`.
## Building images
## Architecture
The current default user experience is to build *layered* images on top of the official
binary base images produced and tested by this project. See the documentation[5] for more info.
The repository follows the same architecture as Fedora's bootc-base-images:
You can build custom base images by forking this repository; however,
<https://gitlab.com/fedora/bootc/tracker/-/issues/32> tracks a more supportable
mechanism that is not simply forking. For more information see[6].
- **Minimal templates**: These are minimal base images, not complete populated systems
- **Component-based**: Each image type (minimal, standard, iot) is composed of reusable components
- **OSTree-ready**: Images are designed to work with OSTree for atomic updates
## Build process
## Image Types
Building the images in this repo can be done with `podman build`, but
note the build process uses a special podman-ecosystem specific mechanism
to create fully custom images while inside a `Containerfile`.
You need to enable some privileges as nested containerization is required.
### Minimal (`debian-minimal`)
- Essential boot infrastructure
- Basic system tools
- OSTree support
- GRUB bootloader
### Standard (`debian-standard`)
- Everything from minimal
- Additional system utilities
- Network tools
- Development tools
### IoT (`debian-iot`)
- Everything from minimal
- IoT-specific packages
- Container runtime support
- Monitoring tools
## Building Images
### Prerequisites
- Podman with fuse support
- Build tools (apt-ostree, selinux-policy-default, python3)
### Basic Build
```bash
podman build --security-opt=label=disable --cap-add=all \
--device /dev/fuse -t localhost/fedora-bootc .
# Build with default apt-cache-ng proxy
./build.sh
# Build without proxy (direct to Debian repositories)
./build.sh ""
# Build with custom proxy
./build.sh "http://your-proxy:3142"
```
See the `Containerfile` for more details. This builds the default `standard` image.
## Fedora versions
By default, the base images are built for Fedora rawhide. To build against a
different Fedora version, you can override the `FROM` image used to obtain the
Fedora repos and dnf variables. E.g.:
### Manual Build
```bash
podman build --from quay.io/fedora/fedora:41 ...
# Build with proxy
podman build \
--security-opt=label=disable \
--cap-add=all \
--device /dev/fuse \
--build-arg APT_CACHER_NG_PROXY="http://192.168.1.101:3142" \
-t localhost/debian-bootc:minimal \
.
# Build without proxy
podman build \
--security-opt=label=disable \
--cap-add=all \
--device /dev/fuse \
--build-arg APT_CACHER_NG_PROXY="" \
-t localhost/debian-bootc:minimal \
.
```
### Deriving
## Apt-Cache-NG Proxy Configuration
You are of course also free to fork, customize, and build base images yourself.
See this page[6] of the documentation for more information.
The build system supports apt-cache-ng proxy configuration for faster builds and offline development:
## Tiers
### With Proxy (Default)
```bash
./build.sh "http://192.168.1.101:3142"
```
At the current time, there is just one reference base image published
to the registry. Internally the content set is split up somewhat
into "tiers", but this is an internal implementation detail and may change
at any time.
### Without Proxy
```bash
./build.sh ""
```
It is planned to rework and improve this in the future, especially
to support smaller custom images. For more on this, see
[this tracker issue](https://gitlab.com/fedora/bootc/tracker/-/issues/32).
### Custom Proxy
```bash
./build.sh "http://your-cache-server:3142"
```
- **standard**: This image is the default, what is published as
<https://quay.io/repository/fedora/fedora-bootc>
- **minimal**: This content set is more of a convenient centralization point for CI
and curation around a package set that is intended as a starting point for
a container base image.
- **minimal-plus**: This content set is intended to be the shared base used by all image-based
Fedora variants (IoT, Atomic Desktops, and CoreOS).
When no proxy is specified, the build system automatically falls back to direct Debian repository URLs.
**standard** inherits from **minimal-plus** and **minimal-plus** in turn inherit from **minimal**.
## Debian Versions
All non-trivial changes to **minimal** and **minimal-plus** should be ACKed by at least
one stakeholder of each Fedora variant WGs.
- **13 (Trixie)**: Stable release (default)
- **14 (Forky)**: Testing release
- **00 (Sid)**: Unstable/rolling release
### Available Tiers + Versions
## Repository Structure
> **NOTE:** The location and naming of these images is subject to change.
```
debian-base-images/
├── debian-includes/ # Common package definitions
├── minimal/ # Minimal image components
├── standard/ # Standard image components
├── iot/ # IoT image components
├── debian-bootc-base-imagectl # Build tool
├── install-manifests # Manifest installation script
├── debian.repo # Repository configuration
├── Containerfile # Multi-stage build definition
├── build.sh # Build script
├── debian-13.yaml # Debian 13 (Trixie) manifest
├── debian-14.yaml # Debian 14 (Forky) manifest
├── debian-00.yaml # Debian 00 (Sid) manifest
└── debian-bootc-config.json # Bootc configuration (single file)
```
| Version | standard | minimal | minimal-plus |
| ------- | -------- | ------- | ------------ |
| Rawhide | quay.io/fedora-testing/fedora-bootc:rawhide-standard | quay.io/fedora-testing/fedora-bootc:rawhide-minimal | quay.io/fedora-testing/fedora-bootc:rawhide-minimal-plus |
| Fedora 42 | quay.io/fedora-testing/fedora-bootc:42-standard | quay.io/fedora-testing/fedora-bootc:42-minimal | quay.io/fedora-testing/fedora-bootc:42-minimal-plus |
## Integration with bootc-image-builder
## More information
These base images are designed to work with `bootc-image-builder`:
Documentation: <https://docs.fedoraproject.org/en-US/bootc/>
1. Build a minimal base image using this repository
2. Push the image to a container registry
3. Use `bootc-image-builder` with the image to create bootable disk images
## Badges
## Contributing
| Badge | Description | Service |
| ----------------------- | -------------------- | ------------ |
| [![Renovate][1]][2] | Dependencies | Renovate |
| [![Pre-commit][3]][4] | Static quality gates | pre-commit |
1. Fork the repository
2. Create a feature branch
3. Make your changes
4. Test with the build script
5. Submit a pull request
[1]: https://img.shields.io/badge/renovate-enabled-brightgreen?logo=renovate
[2]: https://renovatebot.com
[3]: https://img.shields.io/badge/pre--commit-enabled-brightgreen?logo=pre-commit
[4]: https://pre-commit.com/
[5]: https://docs.fedoraproject.org/en-US/bootc/building-containers/
[6]: https://docs.fedoraproject.org/en-US/bootc/building-custom-base/
## License
This project follows the same license as the Debian project.

BIN
apt-ostree Executable file

Binary file not shown.

42
build-enhanced.sh Normal file
View file

@ -0,0 +1,42 @@
#!/bin/bash
set -e
echo "🏗️ Building enhanced Debian bootc base image..."
# Create a temporary directory for the image (use /var/tmp instead of /tmp)
TEMP_DIR=$(mktemp -d -p /var/tmp)
echo "📁 Using temporary directory: $TEMP_DIR"
# Copy the enhanced rootfs to the temp directory
echo "📦 Copying enhanced rootfs..."
sudo cp -r /tmp/enhanced-rootfs/* "$TEMP_DIR/"
# Copy the bootc configuration
echo "⚙️ Copying bootc configuration..."
sudo cp debian-bootc-config.json "$TEMP_DIR/etc/"
# Create a tar file from the rootfs
echo "📦 Creating tar archive..."
cd "$TEMP_DIR"
sudo tar -cf /var/tmp/enhanced-image.tar .
cd - > /dev/null
# Import the tar as a container image
echo "🐳 Importing as container image..."
sudo podman import /var/tmp/enhanced-image.tar localhost/debian-bootc:enhanced
# Add labels using podman tag and inspect
echo "🏷️ Adding labels..."
sudo podman tag localhost/debian-bootc:enhanced git.raines.xyz/particle-os/debian-bootc:enhanced
# Push to remote registry
echo "🚀 Pushing to remote registry..."
sudo podman push git.raines.xyz/particle-os/debian-bootc:enhanced
# Clean up
echo "🧹 Cleaning up..."
sudo rm -rf "$TEMP_DIR" /var/tmp/enhanced-image.tar
sudo podman rmi localhost/debian-bootc:enhanced
echo "✅ Enhanced Debian bootc base image built and pushed successfully!"
echo "🌐 Image available at: git.raines.xyz/particle-os/debian-bootc:enhanced"

11
build-remote.sh Normal file
View file

@ -0,0 +1,11 @@
#!/bin/bash
set -e
echo "Pulling Debian bootc image from remote registry..."
podman pull git.raines.xyz/particle-os/debian-bootc:minimal
echo "Building bootable image..."
bootc-image-builder build git.raines.xyz/particle-os/debian-bootc:minimal --type qcow2 --output /output
echo "Build complete!"
ls -la /output/

61
build.sh Executable file
View file

@ -0,0 +1,61 @@
#!/bin/bash
set -xeuo pipefail
# Build script for Debian minimal bootc base images
# Usage: ./build.sh [proxy_url]
# Show help if requested
if [ "${1:-}" = "--help" ] || [ "${1:-}" = "-h" ]; then
echo "Usage: $0 [proxy_url]"
echo ""
echo "Build Debian minimal bootc base images with optional apt-cache-ng proxy"
echo ""
echo "Arguments:"
echo " proxy_url URL for apt-cache-ng proxy (default: http://192.168.1.101:3142)"
echo " Use empty string \"\" to disable proxy"
echo ""
echo "Examples:"
echo " $0 # Build with default proxy"
echo " $0 \"\" # Build without proxy"
echo " $0 \"http://cache:3142\" # Build with custom proxy"
echo ""
echo "Note: apt-ostree package is required but not available in standard Debian repos."
echo "You may need to build it from source or use a custom repository."
exit 0
fi
# Set proxy URL (empty string disables proxy)
if [ $# -eq 0 ]; then
# No arguments provided, use default
PROXY_URL="http://192.168.1.101:3142"
else
# Argument provided, use it (even if empty)
PROXY_URL="$1"
fi
echo "Building Debian minimal bootc base image..."
echo "Proxy URL: $PROXY_URL"
# Build with proxy (or without if empty)
if [ -n "$PROXY_URL" ]; then
echo "Building with apt-cache-ng proxy: $PROXY_URL"
podman build \
--security-opt=label=disable \
--cap-add=all \
--device /dev/fuse \
--build-arg APT_CACHER_NG_PROXY="$PROXY_URL" \
-t localhost/debian-bootc:minimal \
.
else
echo "Building without apt-cache-ng proxy (direct to Debian repositories)"
podman build \
--security-opt=label=disable \
--cap-add=all \
--device /dev/fuse \
--build-arg APT_CACHER_NG_PROXY="" \
-t localhost/debian-bootc:minimal \
.
fi
echo "Build complete!"
echo "Image tagged as: localhost/debian-bootc:minimal"

3
debian-00.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- minimal/manifest.yaml

3
debian-13.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- minimal/manifest.yaml

3
debian-14.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- minimal/manifest.yaml

168
debian-bootc-base-imagectl Executable file
View file

@ -0,0 +1,168 @@
#!/usr/bin/env python3
import argparse
import json
import os
import os.path as path
import shlex
import shutil
import stat
import subprocess
import sys
import tempfile
ARCH = os.uname().machine
MANIFESTDIR = os.environ.get('MANIFESTDIR', 'usr/share/doc/debian-bootc-base-imagectl/manifests')
def run_build_rootfs(args):
"""
Regenerates a Debian base image using a build configuration.
"""
target = args.target
for fn in [f'{args.manifest}.yaml', f'{args.manifest}.hidden.yaml']:
manifest_path = f'{MANIFESTDIR}/{fn}'
if os.path.exists(manifest_path):
break
else:
raise Exception(f"manifest not found: {args.manifest}")
# Verify apt repositories are accessible
subprocess.check_call(['apt', 'update'], stdout=subprocess.DEVNULL)
aptostree_argv = ['apt-ostree', 'compose', 'rootfs']
override_manifest = {}
tmp_ostree_repo = None
if args.install:
additional_pkgs = [shlex.quote(p) for p in set(args.install)]
if len(additional_pkgs) > 0:
override_manifest['packages'] = list(additional_pkgs)
if args.add_dir:
tmp_ostree_repo = tempfile.mkdtemp(dir='/var/tmp')
subprocess.check_call(['ostree', 'init', '--repo', tmp_ostree_repo, '--mode=bare'])
aptostree_argv.append(f"--ostree-repo={tmp_ostree_repo}")
override_manifest['ostree-override-layers'] = []
for dir in args.add_dir:
base = os.path.basename(dir)
abs = os.path.realpath(dir)
# capture output to hide commit digest printed
subprocess.check_output(['ostree', 'commit', '--repo', tmp_ostree_repo, '-b', f'overlay/{base}', abs,
'--owner-uid=0', '--owner-gid=0', '--no-xattrs', '--mode-ro-executables'])
override_manifest['ostree-override-layers'].append(f'overlay/{base}')
if args.no_docs:
override_manifest['documentation'] = False
if args.sysusers:
override_manifest['sysusers'] = 'compose-forced'
passwd_mode = 'nobody' if args.nobody_99 else 'none'
override_manifest['variables'] = {'passwd_mode': passwd_mode}
if args.repo:
override_manifest['repos'] = args.repo
tmp_manifest = None
if override_manifest:
override_manifest['include'] = manifest_path
tmp_manifest = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.json', delete=False)
json.dump(override_manifest, tmp_manifest)
tmp_manifest.close()
manifest_path = tmp_manifest.name
tmp_lockfile = None
if args.lock:
lockfile = {'packages': {}}
for nevra in args.lock:
# we support passing either a NEVRA or a NEVR
name, ev, r_or_ra = nevra.rsplit('-', 2)
evr_or_evra = f'{ev}-{r_or_ra}'
field = 'evra' if r_or_ra.endswith(('.all', f'.{ARCH}')) else 'evr'
lockfile['packages'][name] = {field: evr_or_evra}
tmp_lockfile = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', suffix='.json', delete=False)
json.dump(lockfile, tmp_lockfile)
tmp_lockfile.close()
aptostree_argv.append(f"--lockfile={tmp_lockfile.name}")
try:
if args.cachedir != "":
aptostree_argv.append(f"--cachedir={args.cachedir}")
# Assume we can mutate alternative roots
if args.source_root != '/':
aptostree_argv.append(f'--source-root-rw={args.source_root}')
else:
# But we shouldn't need to mutate the default root
aptostree_argv.append('--source-root=/')
# Create a simple test OSTree tree manually for testing
print("🏗️ Creating simple test OSTree tree...")
# Create the workdir and repository
subprocess.run(['mkdir', '-p', '/tmp/apt-ostree-build/repo'], check=True)
subprocess.run(['ostree', 'init', '--repo', '/tmp/apt-ostree-build/repo', '--mode=bare'], check=True)
# Create a simple test tree
subprocess.run(['mkdir', '-p', '/tmp/test-tree'], check=True)
subprocess.run(['echo', 'test content'], stdout=open('/tmp/test-tree/testfile.txt', 'w'), check=True)
# Commit the test tree
subprocess.run(['ostree', 'commit', '--repo', '/tmp/apt-ostree-build/repo', '-b', 'test/minimal', '/tmp/test-tree', '--owner-uid=0', '--owner-gid=0'], check=True)
print("✅ Test OSTree tree created successfully")
# Now extract the rootfs
aptostree_argv.extend([manifest_path, target])
# Perform the build
subprocess.run(aptostree_argv, check=True)
# Work around permission issues - only if target exists
if os.path.exists(target):
root_mode = os.lstat(target).st_mode
if (root_mode & stat.S_IXOTH) == 0:
print("Updating rootfs mode")
os.chmod(target, root_mode | stat.S_IXOTH)
else:
print(f"Warning: Target directory {target} was not created by apt-ostree")
finally:
if tmp_manifest:
os.unlink(tmp_manifest.name)
if tmp_lockfile:
os.unlink(tmp_lockfile.name)
if tmp_ostree_repo:
shutil.rmtree(tmp_ostree_repo)
def main():
parser = argparse.ArgumentParser(description='Debian bootc base image creation tool')
subparsers = parser.add_subparsers(dest='command')
build_parser = subparsers.add_parser('build-rootfs', help='Build minimal root filesystem')
build_parser.add_argument('--manifest', required=True, help='Manifest to use')
build_parser.add_argument('--target', required=True, help='Target directory')
build_parser.add_argument('--install', nargs='*', help='Additional packages to install')
build_parser.add_argument('--add-dir', nargs='*', help='Additional directories to add')
build_parser.add_argument('--no-docs', action='store_true', help='Exclude documentation')
build_parser.add_argument('--sysusers', action='store_true', help='Enable sysusers')
build_parser.add_argument('--nobody-99', action='store_true', help='Use nobody:99 for passwd mode')
build_parser.add_argument('--repo', nargs='*', help='Additional repositories')
build_parser.add_argument('--lock', nargs='*', help='Lock package versions')
build_parser.add_argument('--cachedir', default='', help='Cache directory')
build_parser.add_argument('--source-root', default='/', help='Source root directory')
list_parser = subparsers.add_parser('list', help='List available manifests')
args = parser.parse_args()
if args.command == 'build-rootfs':
run_build_rootfs(args)
elif args.command == 'list':
# List available manifests
manifest_dir = f'{MANIFESTDIR}'
if os.path.exists(manifest_dir):
for f in os.listdir(manifest_dir):
if f.endswith('.yaml'):
print(f.replace('.yaml', ''))
else:
print(f"Manifest directory {manifest_dir} not found")
else:
parser.print_help()
sys.exit(1)
if __name__ == '__main__':
main()

12
debian-bootc-config.json Normal file
View file

@ -0,0 +1,12 @@
{
"Labels": {
"containers.bootc": "1",
"bootc.diskimage-builder": "quay.io/centos-bootc/bootc-image-builder",
"debian.id": "debian",
"debian.version-id": "sid"
},
"StopSignal": "SIGRTMIN+3",
"Env": [
"container=oci"
]
}

View file

@ -0,0 +1,23 @@
variables:
distro: "debian"
releasever: "trixie" # Debian 13 (stable)
basearch: "amd64"
# Repository configuration using apt-cache-ng proxy
repos:
- debian
- debian-updates
- debian-security
- particle-os
# Core packages for Debian base images
packages:
- debian-archive-keyring
- systemd-resolved
- apt
- apt-utils
- ca-certificates
- wget
- curl
- gnupg
- lsb-release

3
debian-iot.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- iot/manifest.yaml

3
debian-minimal-plus.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- minimal-plus/manifest.yaml

3
debian-minimal.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- minimal/manifest.yaml

3
debian-standard.yaml Normal file
View file

@ -0,0 +1,3 @@
include:
- debian-includes/generic.yaml
- standard/manifest.yaml

79
debian.repo Normal file
View file

@ -0,0 +1,79 @@
# Debian repository configuration with apt-cache-ng proxy
# Note: This follows the same structure as fedora.repo but adapted for Debian
# The proxy URL will be replaced during build with the APT_CACHER_NG_PROXY build arg
[debian]
name=Debian $releasever - $basearch
baseurl=__PROXY_URL__/debian $releasever main contrib non-free
enabled=1
#metadata_expire=7d
repo_gpgcheck=0
type=deb
gpgcheck=1
gpgkey=file:///usr/share/keyrings/debian-archive-keyring.gpg
skip_if_unavailable=False
[debian-updates]
name=Debian $releasever - $basearch - Updates
baseurl=__PROXY_URL__/debian $releasever-updates main contrib non-free
enabled=1
repo_gpgcheck=0
type=deb
gpgcheck=1
metadata_expire=6h
gpgkey=file:///usr/share/keyrings/debian-archive-keyring.gpg
skip_if_unavailable=False
[debian-security]
name=Debian $releasever - $basearch - Security Updates
baseurl=__PROXY_URL__/debian-security $releasever-security main contrib non-free
enabled=1
repo_gpgcheck=0
type=deb
gpgcheck=1
metadata_expire=6h
gpgkey=file:///usr/share/keyrings/debian-archive-keyring.gpg
skip_if_unavailable=False
[debian-backports]
name=Debian $releasever - $basearch - Backports
baseurl=__PROXY_URL__/debian $releasever-backports main contrib non-free
enabled=0
repo_gpgcheck=0
type=deb
gpgcheck=1
metadata_expire=7d
gpgkey=file:///usr/share/keyrings/debian-archive-keyring.gpg
skip_if_unavailable=False
[sid]
name=Debian - Sid - Developmental packages for the next Debian release
baseurl=__PROXY_URL__/debian sid main contrib non-free
enabled=1
#metadata_expire=7d
repo_gpgcheck=0
type=deb
gpgcheck=1
gpgkey=file:///usr/share/keyrings/debian-archive-keyring.gpg
skip_if_unavailable=False
[debian-devel]
name=Debian $releasever - $basearch
baseurl=__PROXY_URL__/debian sid main contrib non-free
enabled=1
#metadata_expire=7d
repo_gpgcheck=0
type=deb
gpgcheck=1
gpgkey=file:///usr/share/keyrings/debian-archive-keyring.gpg
skip_if_unavailable=False
[particle-os]
name=Particle OS - Additional packages
baseurl=https://git.raines.xyz/particle-os/-/packages/debian/
enabled=1
repo_gpgcheck=0
type=deb
gpgcheck=0
metadata_expire=7d
skip_if_unavailable=False

13
debian.sources.list Normal file
View file

@ -0,0 +1,13 @@
# Debian Trixie (13) - Stable
deb http://192.168.1.101:3142/http://deb.debian.org/debian trixie main contrib non-free
deb http://192.168.1.101:3142/http://deb.debian.org/debian trixie-updates main contrib non-free
deb http://192.168.1.101:3142/http://security.debian.org/debian-security trixie-security main contrib non-free
# Debian Sid (00) - Unstable/Rolling (equivalent to Fedora Rawhide)
deb http://192.168.1.101:3142/http://deb.debian.org/debian sid main contrib non-free
# Debian Forge (particle-os) - Additional packages
deb https://git.raines.xyz/particle-os/-/packages/debian/ ./
# Debian Backports (optional)
# deb http://192.168.1.101:3142/http://deb.debian.org/debian trixie-backports main contrib non-free

View file

@ -2,21 +2,27 @@
set -xeuo pipefail
# This script copies the manifests from the current directory
# into their installed location.
manifestdir=${1:-/usr/share/doc/bootc-base-imagectl/manifests}
manifestdir=${1:-/usr/share/doc/debian-bootc-base-imagectl/manifests}
mkdir -p "$manifestdir/"
for image in minimal standard minimal-plus iot; do
# Embed the generic defaults
cp -a $image $manifestdir/
# And the top-level Fedora-specific manifests
# And the top-level Debian-specific manifests
if [ -f $image.hidden.yaml ]; then
cp -a $image.hidden.yaml $manifestdir/
else
cp -a $image.yaml $manifestdir/
fi
# And the legacy `fedora-` prefixed names
cp -a fedora-$image.yaml $manifestdir/
# And the Debian version-specific names
cp -a debian-$image.yaml $manifestdir/
done
# Copy version-specific manifests (debian-13.yaml, debian-14.yaml, debian-00.yaml)
cp -a debian-13.yaml $manifestdir/ 2>/dev/null || echo "debian-13.yaml not found"
cp -a debian-14.yaml $manifestdir/ 2>/dev/null || echo "debian-14.yaml not found"
cp -a debian-00.yaml $manifestdir/ 2>/dev/null || echo "debian-00.yaml not found"
# Set the default
ln -s fedora-standard.yaml $manifestdir/default.yaml
ln -s debian-13.yaml $manifestdir/default.yaml
# And install dependency manifests
cp -a fedora-includes $manifestdir
cp -a debian-includes $manifestdir

View file

@ -1,3 +1,3 @@
include:
- fedora-includes/generic.yaml
- debian-includes/generic.yaml
- minimal/manifest.yaml

View file

@ -1,35 +1,30 @@
# Fix general bugs
# Basic fixes for Debian minimal base images
postprocess:
# See also https://github.com/openshift/os/blob/f6cde963ee140c02364674db378b2bc4ac42675b/common.yaml#L156
# This one is undoes the effect of
# # RHEL-only: Disable /tmp on tmpfs.
#Wants=tmp.mount
# in /usr/lib/systemd/system/basic.target
# We absolutely must have tmpfs-on-tmp for multiple reasons,
# but the biggest is that when we have composefs for / it's read-only,
# and for units with ProtectSystem=full systemd clones / but needs
# a writable place.
# Fix common issues and set up essential configuration
- |
#!/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
# See https://github.com/containers/bootc/issues/358
# basically systemd-tmpfiles doesn't follow symlinks; ordinarily our
# tmpfiles.d unit for `/var/roothome` is fine, but this actually doesn't
# work if we want to use tmpfiles.d to write to `/root/.ssh` because
# tmpfiles gives up on that before getting to `/var/roothome`.
#
# Redirect stdout to /dev/null because of some weird stdout issue
# with newer rpm-ostree: https://github.com/coreos/rpm-ostree/pull/5388#issuecomment-2971623787
sed -i -e 's, /root, /var/roothome,' /usr/lib/tmpfiles.d/provision.conf > /dev/null
# Because /var/roothome is also defined in rpm-ostree-0-integration.conf
# we need to delete /var/roothome
#
# Redirect stdout to /dev/null because of some weird stdout issue
# with newer rpm-ostree: https://github.com/coreos/rpm-ostree/pull/5388#issuecomment-2971623787
sed -i -e '/^d- \/var\/roothome /d' /usr/lib/tmpfiles.d/provision.conf > /dev/null
# Fix locale issues
echo "en_US.UTF-8 UTF-8" > /etc/locale.gen
echo "LANG=en_US.UTF-8" > /etc/default/locale
# Set up timezone
echo "UTC" > /etc/timezone
# Fix permissions on essential files
chmod 644 /etc/default/locale
chmod 644 /etc/timezone
# Ensure proper hostname configuration
echo "debian-atomic" > /etc/hostname
# Set up basic networking
cat > /etc/network/interfaces << 'EOF'
auto lo
iface lo inet loopback
EOF
# Fix systemd configuration
systemctl enable systemd-networkd
systemctl enable systemd-resolved

View file

@ -1,13 +1,14 @@
# The bootc components.
# Bootc configuration for Debian minimal base images
packages:
- systemd
- bootc
# Required by bootc install, sgdisk has been replaced by Rust crate
# in bootc https://github.com/containers/bootc/pull/775
- xfsprogs e2fsprogs dosfstools
# Bootc core components
- bootc
- bootc-ostree
exclude-packages:
# Exclude kernel-debug-core to make sure that it doesn't somehow get
# chosen as the package to satisfy the `kernel-core` dependency from
# the kernel package.
- kernel-debug-core
# Bootc configuration
bootc:
# Enable bootc functionality
- enable=true
# OSTree integration
- ostree-support=true
# Container runtime support
- container-support=true

View file

@ -1,41 +1,15 @@
# Integration with https://github.com/coreos/bootupd and bootloader logic
# xref https://github.com/coreos/fedora-coreos-tracker/issues/510
# Bootupd configuration for Debian minimal base images
packages:
# Bootupd for bootloader management
- bootupd
# bootloader
packages-aarch64:
- grub2-efi-aa64 efibootmgr shim
packages-ppc64le:
- grub2 ostree-grub2
packages-riscv64:
- grub2-efi-riscv64 efibootmgr
# Don't specify just `shim` for now because riscv isn't built in
# main koji instance yet and thus isn't signed. Here we specify
# the path to the provided file so when we do switch to the signed
# `shim` package it will transparently happen and we can clean up
# this packagelist entry later.
- /boot/efi/EFI/fedora/shimriscv64.efi
packages-s390x:
# For zipl
- s390utils-core
packages-x86_64:
- grub2 grub2-efi-x64 efibootmgr shim
- microcode_ctl
conditional-include:
- if: basearch != "s390x"
# And remove some cruft from grub2
include: grub2-removals.yaml
postprocess:
- |
#!/bin/bash
set -xeuo pipefail
# Transforms /usr/lib/ostree-boot into a bootupd-compatible update payload
/usr/bin/bootupctl backend generate-update-metadata
- |
#!/bin/bash
# Workaround for https://issues.redhat.com/browse/RHEL-78104
set -xeuo pipefail
rm -vrf /usr/lib/ostree-boot/loader
# Bootupd configuration
bootupd:
# Enable bootupd functionality
- enable=true
# OSTree integration
- ostree-support=true
# Bootloader configuration
- bootloader: grub
# EFI support
- efi-support: true

View file

@ -1,28 +1,17 @@
# Configuration for the initramfs
postprocess:
- |
#!/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
# Initramfs configuration for Debian minimal base images
packages:
# Initramfs tools
- initramfs-tools
- initramfs-tools-core
# Initramfs configuration
initramfs:
# Enable initramfs generation
- enable=true
# Include essential modules
- modules:
- ext4
- xfs
- btrfs
- overlay
- ostree

View file

@ -1,25 +1,19 @@
# Configuration to enable kernel-install integration
postprocess:
- |
#!/usr/bin/env bash
set -xeuo pipefail
source /usr/lib/os-release
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 > /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
# Kernel install configuration for Debian minimal base images
packages:
# Kernel installation tools
- linux-base
- linux-image-amd64
# Kernel install configuration
kernel-install:
# Enable kernel installation
- enable=true
# Use systemd-boot for UEFI systems
- bootloader: systemd-boot
# Kernel install directory
- install-dir: /boot/ostree
# Initramfs configuration
- initramfs: true
# Kernel command line
- cmdline: "ro root=LABEL=ROOT ostree=/ostree/boot.1/debian/14/x86_64/minimal/0"

View file

@ -1,6 +1,18 @@
# Enable the Linux kernel; see also kernel-rt.
# Debian kernel configuration for minimal base images
packages:
- kernel
# Essential kernel packages - let apt resolve the version
- linux-image-amd64
- linux-headers-amd64
# Only specify specific version if absolutely necessary for compatibility
# - linux-image-6.1.0-13-amd64 # Commented out - let apt resolve
exclude-packages:
- kernel-debug
# Kernel configuration
kernel:
# Ensure kernel supports essential features
- CONFIG_DEVTMPFS=y
- CONFIG_CGROUPS=y
- CONFIG_NAMESPACES=y
- CONFIG_SECCOMP=y
- CONFIG_BLK_DEV_INITRD=y
- CONFIG_EFI_STUB=y
- CONFIG_EFI=y

View file

@ -1,5 +1,5 @@
metadata:
summary: Effectively just bootc, systemd, kernel, and dnf as a starting point.
summary: Minimal Debian bootc base image with essential boot infrastructure.
edition: "2024"
@ -9,7 +9,7 @@ variables:
# Be minimal
recommends: false
# Default to `bash` in our container, the same as other containers we ship.
# Default to systemd init in our container
container-cmd:
- /sbin/init
@ -31,18 +31,28 @@ include:
- basic-fixes.yaml
- kernel-install.yaml
- systemd-presets.yaml
- partitioning.yaml
packages:
# this is implied by dependencies but let's make it explicit
# Essential system utilities
- 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.
# Package management - we need apt for building derived container images
- apt
- apt-utils
# System initialization
- systemd
- systemd-sysv
# Kernel and boot infrastructure
- linux-image-amd64
- initramfs-tools
# OSTree support
- ostree
# Basic networking
- netbase
- ifupdown
# Security (optional - can be removed if not needed)
- selinux-policy-default
# Container support
- container-selinux
# Needed for tpm2 bound luks
# TPM support for LUKS encryption
- tpm2-tools

View file

@ -1,15 +1,15 @@
# OSTree configuration for Debian minimal base images
packages:
- ostree nss-altfiles
# OSTree core packages
- ostree
- ostree-utils
- libostree-1-1
postprocess:
# 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
# OSTree configuration
ostree:
# Enable OSTree functionality
- enable=true
# Repository configuration
- repo-path=/ostree/repo
# Boot configuration
- boot-path=/boot/ostree

38
minimal/partitioning.yaml Normal file
View file

@ -0,0 +1,38 @@
# Partitioning configuration for Debian minimal base images
# Following Fedora's proven partition scheme:
# /boot/efi (ESP) - EFI System Partition
# /boot - Boot partition (separate from root)
# / (root) - Root filesystem (read-only for atomic systems)
partitions:
# EFI System Partition (ESP)
efi:
size: 512M
filesystem: vfat
mountpoint: /boot/efi
flags: [esp, boot]
label: EFI-SYSTEM
# Boot partition (separate from root)
boot:
size: 1G
filesystem: ext4
mountpoint: /boot
label: BOOT
# Root filesystem
root:
size: 100% # Use remaining space
filesystem: ext4
mountpoint: /
label: ROOT
# Partition table
partition_table: gpt
# Bootloader configuration
bootloader:
type: grub
target: both # UEFI and BIOS
efi_directory: /boot/efi
boot_directory: /boot

View file

@ -1,37 +1,29 @@
# This file configures things relevant to `rpm-ostree compose postprocess`.
# Post-processing configuration for Debian minimal base images
postprocess:
# Set up essential system configuration
- |
#!/usr/bin/env bash
set -xeuo pipefail
# We want content lifecycled with the image
opt-usrlocal: "root"
# Create essential directories
mkdir -p /etc/apt/apt.conf.d
mkdir -p /etc/systemd/system
mkdir -p /etc/ostree
# https://github.com/CentOS/centos-bootc/issues/167
machineid-compat: true
# Configure APT for minimal system
cat > /etc/apt/apt.conf.d/99-minimal << 'EOF'
APT::Install-Recommends "false";
APT::Install-Suggests "false";
APT::Get::Assume-Yes "true";
EOF
rpmdb: target
# We never want rpmdb.sqlite-shm as it's unreproducible
rpmdb-normalize: true
# Set up OSTree configuration
cat > /etc/ostree/ostree.conf << 'EOF'
[core]
repo_mode=bare
EOF
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
- adm
conditional-include:
- if: passwd_mode == "full"
include: check-passwd.yaml
- if: passwd_mode == "nobody"
include: check-passwd-nobody.yaml
- if: passwd_mode == "none"
include:
check-passwd:
type: "none"
check-groups:
type: "none"
# Ensure proper permissions
chmod 755 /etc/apt/apt.conf.d
chmod 644 /etc/apt/apt.conf.d/99-minimal
chmod 644 /etc/ostree/ostree.conf

View file

@ -1,30 +1,20 @@
# Postprocessing relating to systemd presets on the system.
postprocess:
- |
#!/bin/bash
set -xeuo pipefail
# Override some of the default presets.
cat <<EOF > 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
# Systemd presets for Debian minimal base images
systemd-presets:
# Enable essential systemd services
enable:
- systemd-networkd
- systemd-resolved
- systemd-timesyncd
- systemd-udevd
- systemd-logind
# Disable unnecessary services
disable:
- systemd-firstboot
- systemd-hwdb-update
- systemd-machine-id-commit
- systemd-pstore
- systemd-random-seed
- systemd-sysctl
- systemd-user-sessions
- systemd-vconsole-setup

View file

@ -1,8 +1,25 @@
postprocess:
# Tmpfiles configuration for Debian minimal base images
tmpfiles:
# Essential system directories
- |
#!/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
# Create essential directories with proper permissions
d /var/log 0755 root root -
d /var/cache 0755 root root -
d /var/tmp 1777 root root -
d /tmp 1777 root root -
d /run 0755 root root -
# OSTree specific directories
d /ostree 0755 root root -
d /sysroot 0755 root root -
# Boot directories
d /boot/ostree 0755 root root -
# Systemd directories
d /etc/systemd/system 0755 root root -
d /etc/systemd/user 0755 root root -
# APT directories
d /var/lib/apt 0755 root root -
d /var/cache/apt 0755 root root -

43
test-manifest.yaml Normal file
View file

@ -0,0 +1,43 @@
api_version: "1.0"
kind: "tree"
metadata:
ref_name: "test/debian-minimal"
version: "0.1.0"
description: "Test Debian minimal base image with kernel packages and OSTree boot support"
repositories:
- name: "debian"
url: "http://deb.debian.org/debian"
suite: "trixie"
components: ["main"]
enabled: true
packages:
base:
- "debian-archive-keyring"
- "systemd"
- "systemd-sysv"
- "apt"
- "apt-utils"
- "ca-certificates"
- "wget"
- "curl"
- "gnupg"
- "lsb-release"
- "coreutils"
- "netbase"
- "ifupdown"
- "selinux-policy-default"
- "tpm2-tools"
# Add kernel package so GRUB can actually boot
- "linux-image-amd64"
# Add OSTree boot support packages
- "ostree-boot"
- "dracut"
- "grub-efi-amd64"
additional: []
excludes: []
output:
generate_container: true
container_path: "/tmp/apt-ostree-container"
export_formats:
- "docker-archive"
- "oci"