Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions containers/anaconda-bootc/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Anaconda installer container for bcvk
#
# This container provides anaconda for installing bootc container images
# using kickstart files. It's designed to run as an ephemeral VM that
# boots into anaconda.target.
#
# Build: podman build -t localhost/anaconda-bootc:latest .

FROM quay.io/fedora/fedora-bootc:42

# Install anaconda and required packages
COPY packages.txt /tmp/packages.txt
RUN dnf install -y $(grep -v '^#' /tmp/packages.txt | tr '\n' ' ') && \
dnf clean all && \
rm /tmp/packages.txt

# Install bcvk setup service that runs before anaconda
COPY bcvk-anaconda-setup.service /usr/lib/systemd/system/bcvk-anaconda-setup.service
COPY bcvk-anaconda-setup.sh /usr/libexec/bcvk-anaconda-setup.sh
RUN chmod +x /usr/libexec/bcvk-anaconda-setup.sh

# Set anaconda.target as default and enable our setup service
RUN systemctl set-default anaconda.target && \
systemctl enable bcvk-anaconda-setup.service
97 changes: 97 additions & 0 deletions containers/anaconda-bootc/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
# Anaconda Installer Container for bcvk

This container provides the anaconda installer for installing bootc container
images using kickstart files. It boots into `anaconda.target` and uses the
upstream anaconda systemd services.

## Overview

The container is based on `quay.io/fedora/fedora-bootc:42` with anaconda-tui
installed. It boots directly into `anaconda.target` and uses the upstream
`anaconda-direct.service` with a bcvk setup service that runs beforehand.

## Building

```bash
cd containers/anaconda-bootc
podman build -t localhost/anaconda-bootc:latest .
```

## How It Works

1. bcvk creates a target disk and generates a kickstart file
2. bcvk starts the VM with:
- Host container storage mounted read-only via virtiofs
- Kickstart file mounted via virtiofs at `/run/virtiofs-mnt-kickstart/`
- Target disk attached via virtio-blk
- Kernel args: `inst.notmux inst.ks=file:///run/virtiofs-mnt-kickstart/anaconda.ks`
3. The VM boots into `anaconda.target`
4. `bcvk-anaconda-setup.service` runs first to:
- Mount virtiofs shares for container storage and kickstart
- Configure `/etc/containers/storage.conf` with additionalImageStores
5. Upstream `anaconda-direct.service` runs anaconda (triggered by `inst.notmux`)
6. Kickstart `poweroff` directive powers off the VM after anaconda completes

## Integration with Upstream Anaconda

This container leverages upstream anaconda systemd infrastructure:

| Component | Source | Purpose |
|-----------|--------|---------|
| `anaconda.target` | Upstream | Default boot target for installation |
| `anaconda-direct.service` | Upstream | Runs anaconda without tmux |
| `bcvk-anaconda-setup.service` | bcvk | Sets up virtiofs mounts before anaconda (conditional on `bcvk.anaconda` kernel arg) |

## Kickstart Requirements

The user provides a kickstart with partitioning and locale settings.
bcvk injects:
- `ostreecontainer --transport=containers-storage --url=<image>`
- `%post` script to repoint bootc origin to the registry (unless `--no-repoint`)

**Important**: The target disk is available at `/dev/disk/by-id/virtio-output`.
bcvk also attaches a swap disk, so use `ignoredisk` to target the correct disk.

Example kickstart for BIOS boot:
```kickstart
text
lang en_US.UTF-8
keyboard us
timezone UTC --utc
network --bootproto=dhcp --activate

# Target only the output disk
ignoredisk --only-use=/dev/disk/by-id/virtio-output

zerombr
clearpart --all --initlabel

# Create required boot partitions (biosboot + /boot)
reqpart --add-boot
part / --fstype=xfs --grow

rootpw --lock
poweroff
```

## Installed Packages

See `packages.txt` for the full list. Key packages:
- **anaconda-tui**: Text-mode anaconda installer
- **pykickstart**: Kickstart file processing
- **Disk tools**: parted, gdisk, lvm2, cryptsetup
- **Filesystem tools**: e2fsprogs, xfsprogs, btrfs-progs
- **Container tools**: skopeo (bootc is in base image)

## Debugging

If installation fails, check the VM console output or journal:
```bash
# Run with console output
bcvk anaconda install --console ...

# Inside VM, check logs
journalctl -u bcvk-anaconda-setup
journalctl -u anaconda-direct
cat /tmp/anaconda.log
```
18 changes: 18 additions & 0 deletions containers/anaconda-bootc/bcvk-anaconda-setup.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[Unit]
Description=bcvk container storage setup for anaconda
# Run before anaconda starts, after basic system is up and target disk is available
Before=anaconda-direct.service anaconda.service
After=basic.target dev-disk-by\x2did-virtio\x2doutput.device
Requires=dev-disk-by\x2did-virtio\x2doutput.device
# Only run in bcvk anaconda environment (bcvk passes this kernel arg)
ConditionKernelCommandLine=bcvk.anaconda

[Service]
Type=oneshot
ExecStart=/usr/libexec/bcvk-anaconda-setup.sh
RemainAfterExit=yes
StandardOutput=journal+console
StandardError=journal+console

[Install]
WantedBy=anaconda.target
54 changes: 54 additions & 0 deletions containers/anaconda-bootc/bcvk-anaconda-setup.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/bash
# bcvk anaconda setup script
#
# This script runs before anaconda to set up:
# - virtiofs mounts for host container storage and kickstart
# - container storage configuration for additionalImageStores
#
# Anaconda itself is run by the upstream anaconda-direct.service
set -euo pipefail

echo "bcvk: Setting up container storage for anaconda..."

# Mount host container storage via virtiofs
AIS=/run/virtiofs-mnt-hoststorage
if ! mountpoint -q "${AIS}" 2>/dev/null; then
mkdir -p "${AIS}"
mount -t virtiofs mount_hoststorage "${AIS}" || {
echo "bcvk: ERROR: Failed to mount host container storage"
exit 1
}
fi

# Mount kickstart directory via virtiofs
KS_DIR=/run/virtiofs-mnt-kickstart
if ! mountpoint -q "${KS_DIR}" 2>/dev/null; then
mkdir -p "${KS_DIR}"
mount -t virtiofs mount_kickstart "${KS_DIR}" || {
echo "bcvk: ERROR: Failed to mount kickstart directory"
exit 1
}
fi

# Configure containers to use host storage as additional image store
mkdir -p /etc/containers
cat > /etc/containers/storage.conf << 'EOF'
[storage]
driver = "overlay"
[storage.options]
additionalimagestores = ["/run/virtiofs-mnt-hoststorage"]
EOF

# Verify kickstart exists
if [ ! -f "${KS_DIR}/anaconda.ks" ]; then
echo "bcvk: ERROR: Kickstart not found at ${KS_DIR}/anaconda.ks"
exit 1
fi

# Copy kickstart to where anaconda expects it
# Anaconda looks for /run/install/ks.cfg when inst.ks is specified
mkdir -p /run/install
cp "${KS_DIR}/anaconda.ks" /run/install/ks.cfg
echo "bcvk: Installed kickstart to /run/install/ks.cfg"

echo "bcvk: Setup complete. Kickstart: ${KS_DIR}/anaconda.ks"
19 changes: 19 additions & 0 deletions containers/anaconda-bootc/packages.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Anaconda installer packages
anaconda-tui
python3-kickstart
pykickstart

# Disk tools
parted
gdisk
lvm2
cryptsetup

# Filesystem tools
e2fsprogs
xfsprogs
btrfs-progs
dosfstools

# Container tools (bootc is in base image)
skopeo
2 changes: 2 additions & 0 deletions crates/integration-tests/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ pub(crate) use integration_tests::{
};

mod tests {
pub mod anaconda_install;
pub mod libvirt_base_disks;
pub mod libvirt_port_forward;
pub mod libvirt_run_anaconda;
pub mod libvirt_upload_disk;
pub mod libvirt_verb;
pub mod mount_feature;
Expand Down
Loading
Loading