Skip to content

Commit edf2794

Browse files
committed
Add dedicated bootc planner for container image builds
bootc container images are built without a running systemd and with a restricted filesystem layout: /var, /home, and /root do not exist during the build. The ostree planner assumes all of these are available, so it cannot be used for bootc image builds. Introduce a bootc planner that understands the full bootc lifecycle: Nix is installed into /nix at build time, moved to /usr/lib/nix for the image layer, and on first boot systemd-tmpfiles seeds /var/lib/nix while a bind-mount exposes it at /nix. sysusers.d ensures build users survive across boots since /etc/passwd entries from the build may not persist. Auto-detection checks for /usr/bin/bootc before the ostree check since bootc images are also ostree-based and would otherwise match the wrong planner. Closes: #155
1 parent 9d7731e commit edf2794

File tree

7 files changed

+468
-57
lines changed

7 files changed

+468
-57
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ jobs:
313313
distro:
314314
- ubuntu-v22_04
315315
- ubuntu-v24_04
316+
- fedora-v42-bootc
316317
steps:
317318
- name: Checkout repository
318319
uses: actions/checkout@v6

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ curl -sSfL https://artifacts.nixos.org/nix-installer | sh -s -- install
2424
| -------------------------------------------------------------------- | :---------------: | :---------: | :---------------: |
2525
| Linux (`x86_64` and `aarch64`) | ✓ (via [systemd]) || Stable |
2626
| MacOS (`x86_64` and `aarch64`) || | Stable (see note) |
27+
| ostree (Fedora Silverblue, etc.) | ✓ (via [systemd]) || Stable |
2728
| [Valve Steam Deck][steam-deck] (SteamOS) || | Stable |
2829
| [Windows Subsystem for Linux][wsl] 2 (WSL2) (`x86_64` and `aarch64`) | ✓ (via [systemd]) || Stable |
2930
| [Podman] Linux containers | ✓ (via [systemd]) || Stable |
@@ -205,6 +206,40 @@ podman rmi $IMAGE
205206
With some container tools, such as [Docker], you can omit `sandbox = false`.
206207
Omitting this will negatively impact compatibility with container tools like [Podman].
207208

209+
### On ostree-based systems (Fedora Silverblue, etc.)
210+
211+
Immutable Linux distributions based on [ostree](https://ostreedev.github.io/ostree/) have a
212+
read-only root filesystem, so `/nix` cannot be created directly. The `ostree` planner handles
213+
this by setting up a bind mount from a persistence directory (`/var/home/nix` by default) to
214+
`/nix` via systemd units.
215+
216+
On a running ostree system the installer auto-detects the right planner, so the default command
217+
works:
218+
219+
```shell
220+
curl -sSfL https://artifacts.nixos.org/nix-installer | sh -s -- install
221+
```
222+
223+
#### In bootc container builds
224+
225+
When building [bootc](https://bootc-dev.github.io/) container images, `systemd` is not running
226+
during the build and `/var` does not exist. The `bootc` planner handles this by installing Nix
227+
into `/nix` (which becomes part of the image layer). On first boot, `systemd-tmpfiles` copies
228+
`/nix` to `/var/lib/nix` and a bind-mount makes it available at `/nix`.
229+
230+
The `bootc` planner is auto-detected when `/usr/bin/bootc` is present, or can be selected
231+
explicitly:
232+
233+
```dockerfile
234+
# Containerfile
235+
FROM quay.io/fedora/fedora-bootc:42
236+
RUN curl -sSfL https://artifacts.nixos.org/nix-installer | sh -s -- install bootc \
237+
--extra-conf "sandbox = false" --no-confirm
238+
```
239+
240+
After the image boots, systemd will create `/nix`, bind-mount `/var/lib/nix` onto it, and start
241+
the Nix daemon automatically.
242+
208243
### In GitHub Actions
209244

210245
[The nix installer action repository](https://github.com/NixOS/nix-installer-action/) provides a GitHub Action for installing Nix in CI workflows.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
FROM default
2+
COPY nix-installer /nix-installer
3+
RUN chmod +x /nix-installer/bin/nix-installer
4+
# In a container build there is no systemd, so we use the bootc planner which
5+
# installs Nix into /nix (part of the image layer). On first boot,
6+
# systemd-tmpfiles copies it to /var/lib/nix and a bind-mount exposes it.
7+
RUN /nix-installer/bin/nix-installer install bootc --logger pretty --log-directive nix_installer=trace --extra-conf "sandbox = false" --no-confirm -vvv
8+
ENV PATH="${PATH}:/nix/var/nix/profiles/default/bin"
9+
RUN nix-build --no-substitute -E 'derivation { name = "foo"; system = "x86_64-linux"; builder = "/bin/sh"; args = ["-c" "echo foobar > $out"]; }'
10+
# Verify build-time artifacts:
11+
RUN test -d /nix/store || { echo "FAIL: /nix/store does not exist"; exit 1; }
12+
RUN test -f /etc/sysusers.d/nix-installer.conf || { echo "FAIL: /etc/sysusers.d/nix-installer.conf missing"; exit 1; }
13+
RUN test -f /etc/tmpfiles.d/nix-installer.conf || { echo "FAIL: /etc/tmpfiles.d/nix-installer.conf missing"; exit 1; }
14+
RUN grep -q 'After=systemd-tmpfiles-setup.service' /etc/systemd/system/nix.mount || { echo "FAIL: nix.mount missing After=systemd-tmpfiles-setup.service"; cat /etc/systemd/system/nix.mount; exit 1; }

nix/tests/container-test/default.nix

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,35 @@ let
2424
tester = ./default/Dockerfile;
2525
system = "x86_64-linux";
2626
};
27+
28+
# Fedora 42 WSL rootfs – used for the bootc planner container test
29+
# (no systemd) reproducing
30+
# https://github.com/NixOS/nix-installer/issues/155
31+
# Re-compressed from .tar.xz to .tar.zst because podman import is
32+
# extremely slow at xz decompression inside a VM.
33+
"fedora-v42-bootc" =
34+
let
35+
xzTarball = builtins.fetchurl {
36+
url = "https://dl.fedoraproject.org/pub/fedora/linux/releases/42/Container/x86_64/images/Fedora-WSL-Base-42-1.1.x86_64.tar.xz";
37+
sha256 = "138vibdf0qcln3r0f116qvmq5vx8im9cy0xv2ml7r8ccsw2kvywr";
38+
};
39+
pkgs = forSystem "x86_64-linux" ({ pkgs, ... }: pkgs);
40+
in
41+
{
42+
tarball =
43+
pkgs.runCommand "fedora-42-rootfs.tar.zst"
44+
{
45+
nativeBuildInputs = with pkgs; [
46+
xz
47+
zstd
48+
];
49+
}
50+
''
51+
xz -dc ${xzTarball} | zstd -o $out
52+
'';
53+
tester = ./bootc/Dockerfile;
54+
system = "x86_64-linux";
55+
};
2756
};
2857

2958
makeTest =

0 commit comments

Comments
 (0)