|
1 | | -# ISOs |
| 1 | +# bootc generic-iso |
2 | 2 |
|
3 | | -## Generic |
| 3 | +This ISO contains a bootable bootc root filesystem in /LiveOS/squashfs.img, the ISO |
| 4 | +is bootable as an ISO or as an image written to a USB flash drive. |
4 | 5 |
|
5 | | -`image-builder` can build ISOs out of bootable containers. The image type to use to build ISOs is the `bootc-generic-iso` image type. `image-builder` takes the bootable container and explodes the relevant parts to put them into the correct places on the ISO this means that there is a small contract in place on what `image-builder` expects to exist in your bootable container: |
| 6 | +This ISO is created from a bootc container using image-builder. You create a |
| 7 | +custom container using podman, then run image-builder to turn it into an ISO. |
6 | 8 |
|
7 | | -1. A kernel must live in `/usr/lib/module/*/vmlinuz`. If there are multiple kernels the behavior is undefined. This kernel will be placed in `/images/pxeboot/vmlinuz` on the ISO filesystem. |
8 | | -2. An initramfs is expected to be next to the kernel with the filename `initramfs.img`. The initramfs is placed in `/images/pxeboot/initrd.img` on the ISO filesystem. |
9 | | -3. The UEFI vendor is sourced by a directory name in `/usr/lib/efi/shim/*EFI/$VENDOR`. If there are multiple directories the behavior is undefined. The `BOOT` directory is always ignored. |
10 | | -4. shim and grub2 EFI binaries (`shimx64.efi`, `mmx64.efi`, `gcdx64.efi`) are expected to be present in `/boot/efi/EFI/$VENDOR`. |
11 | | -5. `/usr/share/grub2/unicode.pf` and `/usr/lib/grub/i386-pc` are expected to present. These are normally provided by the `grub2-common` and `grub2-pc-modules` packages respectively. The latter is only necessary on `x86_64`. |
12 | | -5. Required executables in the container are: `podman`, `mksquashfs`, `xorriso`, `implantisomd5`, `grub2-mkimage` and `python`. If you are using a separate build container then these executables must exist in the build container. |
13 | | -6. The container image is converted to a `squashfs` filesystem and put into `/LiveOS/squashfs.img` in the ISO. |
| 9 | +## bootc container |
14 | 10 |
|
15 | | -You can [define additional configuration](./05-sources-of-configuration.md#isoyaml) for an ISO inside your container. |
| 11 | +The bootc container has a few requirements: |
16 | 12 |
|
17 | | -If a `--bootc-installer-payload-ref` argument is optionally passed to `image-builder` when building a `bootc-generic-iso` then the container reference is copied from the hosts container storage to `/var/lib/containers/storage` in the squashfs filesystem. |
| 13 | +* Be based on a bootc container, eg. quay.io/fedora/fedora-bootc:latest |
| 14 | +* Include the dracut-live, erofs-utils packages |
| 15 | +* Include grub2 ISO bootloader related tools |
| 16 | + - grub2-efi-*-cdboot xorriso isomd5sum shim |
| 17 | +* Configure dracut to add the dmsquash-live module |
| 18 | +* Configure ostree to not use composefs |
| 19 | +* Rebuild the initramfs so that it includes the dmsquash-live module |
| 20 | +* Optionally setup the ISO menus and kernel cmdline with iso.yaml |
18 | 21 |
|
19 | | -### Example Containerfile |
| 22 | +## Sample Fedora bootc container |
20 | 23 |
|
21 | | -This container file builds a `Fedora` "payload" installer (a `boot.iso`). It installs the container that's mentioned in the `/usr/share/anaconda/interactive-defaults.ks` kickstart file. |
| 24 | +This is a simple example using the `image-builder` cmdline tool and a local install of podman. |
22 | 25 |
|
23 | | -```Dockerfile |
24 | | -FROM quay.io/fedora/fedora-bootc:rawhide |
| 26 | +Save this in `Containerfile`: |
25 | 27 |
|
26 | | -RUN dnf install -qy \ |
27 | | - anaconda \ |
28 | | - anaconda-install-img-deps \ |
29 | | - anaconda-dracut \ |
30 | | - dracut-config-generic \ |
31 | | - dracut-network \ |
32 | | - net-tools \ |
33 | | - grub2-efi-x64-cdboot \ |
34 | | - plymouth \ |
35 | | - default-fonts-core-sans \ |
36 | | - default-fonts-other-sans \ |
37 | | - google-noto-sans-cjk-fonts |
| 28 | +``` |
| 29 | +FROM quay.io/fedora/fedora-bootc:latest |
| 30 | +RUN dnf -y install grub2-efi-*-cdboot xorriso isomd5sum dracut-live erofs-utils shim && dnf clean all |
| 31 | +RUN mkdir /boot/efi && cp -r /usr/lib/efi/shim/*/EFI /boot/efi && cp -r /usr/lib/efi/grub2/*/EFI/* /boot/efi/EFI/ |
| 32 | +
|
| 33 | +# Override using composefs for ostree (it is incompatible with the erofs rootfs) |
| 34 | +RUN cat <<EOF > /usr/lib/ostree/prepare-root.conf |
| 35 | +[composefs] |
| 36 | +enabled = no |
| 37 | +[sysroot] |
| 38 | +readonly = true |
| 39 | +EOF |
| 40 | +
|
| 41 | +# Include the dmsquash-live module in the initramfs |
| 42 | +RUN cat <<EOF > /usr/lib/dracut/dracut.conf.d/40-iso.conf |
| 43 | +compress="xz" |
| 44 | +add_dracutmodules+=" qemu qemu-net livenet dmsquash-live " |
| 45 | +early_microcode="no" |
| 46 | +EOF |
| 47 | +
|
| 48 | +# Override the default ISO menus |
| 49 | +RUN mkdir -p /usr/lib/image-builder/bootc |
| 50 | +RUN cat <<EOF > /usr/lib/image-builder/bootc/iso.yaml |
| 51 | +label: bootc-generic |
| 52 | +kernel_args: |
| 53 | + - console=ttyS0 |
| 54 | +grub2: |
| 55 | + timeout: 5 |
| 56 | + entries: |
| 57 | + - name: Boot Linux |
| 58 | + linux: \${kernelpath} \${root} |
| 59 | + initrd: \${initrdpath} |
| 60 | + - name: Boot Linux With debug |
| 61 | + linux: \${kernelpath} \${root} rd.debug=1 |
| 62 | + initrd: \${initrdpath} |
| 63 | +EOF |
38 | 64 |
|
39 | | -# these are necessary build tools. if you use a separate build container then |
40 | | -# these tools should be installed there |
41 | | -RUN dnf install -qy \ |
42 | | - xorrisofs \ |
43 | | - squashfs-tools |
| 65 | +# Rebuild the initrd |
| 66 | +RUN set -xe; kver=$(ls /usr/lib/modules); env DRACUT_NO_XATTR=1 dracut -vf /usr/lib/modules/$kver/initramfs.img "$kver" |
44 | 67 |
|
45 | | -RUN dnf clean all |
| 68 | +# Mask services that aren't compatible with running from an ISO |
| 69 | +RUN systemctl mask bootc-generic-growpart.service bootc-publish-rhsm-facts.service bootloader-update.service rpm-ostree-fix-shadow-mode.service |
46 | 70 |
|
47 | | -RUN mkdir -p /boot/efi && cp -ra /usr/lib/efi/*/*/EFI /boot/efi |
| 71 | +RUN bootc container lint |
| 72 | +``` |
48 | 73 |
|
49 | | -# --- |
| 74 | +Build this container using podman: |
| 75 | +``` |
| 76 | +podman build -f ./Containerfile -t bootc-iso |
| 77 | +``` |
50 | 78 |
|
51 | | -# some configuration for our ISO |
| 79 | +Run `image-builder` to create the ISO: |
| 80 | +``` |
| 81 | +image-builder build --bootc-default-fs ext4 --bootc-ref localhost/bootc-iso:latest generic-iso |
| 82 | +``` |
52 | 83 |
|
53 | | -RUN mkdir -p /usr/lib/image-builder/bootc |
| 84 | +If your container is on a remote system replace the |
| 85 | +`localhost/bootc-iso:latest` with the right url. |
54 | 86 |
|
55 | | -COPY <<EOT /usr/lib/image-builder/bootc/iso.yaml |
56 | | -label: "Fedora-bootc-Installer" |
57 | | -grub2: |
58 | | - entries: |
59 | | - - name: "Install Fedora (bootc)" |
60 | | - linux: "/images/pxeboot/vmlinuz inst.stage2=hd:LABEL=Fedora-bootc-Installer console=tty0 inst.graphical selinux=0 rhgb quiet" |
61 | | - initrd: "/images/pxeboot/initrd.img" |
62 | | -EOT |
63 | | - |
64 | | -# some configuration for anaconda |
65 | | - |
66 | | -COPY <<EOT /usr/share/anaconda/interactive-defaults.ks |
67 | | -bootc --source-imgref registry:quay.io/fedora/fedora-bootc:rawhide --target-imgref quay.io/fedora/fedora-bootc:rawhide |
68 | | -EOT |
69 | | - |
70 | | -# --- |
71 | | - |
72 | | -# these things are normally performed by `lorax` to make `anaconda` work; this is the |
73 | | -# bare minimum to get things to work |
74 | | - |
75 | | -RUN echo "install:x:0:0:root:/root:/usr/libexec/anaconda/run-anaconda" >> /etc/passwd && \ |
76 | | - echo "install::14438:0:99999:7:::" >> /etc/shadow && \ |
77 | | - passwd -d root |
78 | | - |
79 | | -RUN mv /usr/share/anaconda/list-harddrives-stub /usr/bin/list-harddrives && \ |
80 | | - mv /etc/yum.repos.d /etc/anaconda.repos.d && \ |
81 | | - ln -s /lib/systemd/system/anaconda.target /etc/systemd/system/default.target && \ |
82 | | - rm -v /usr/lib/systemd/system-generators/systemd-gpt-auto-generator |
83 | | - |
84 | | -RUN ln -s /usr/lib/systemd/system/anaconda-shell@.service /usr/lib/systemd/system/autovt@.service |
85 | | - |
86 | | -RUN mkdir /usr/lib/systemd/logind.conf.d |
87 | | -COPY <<EOT /usr/lib/systemd/logind.conf.d/anaconda-shell.conf |
88 | | -[Login] |
89 | | -ReserveVT=2 |
90 | | -EOT |
91 | | - |
92 | | -RUN mkdir "$(realpath /root)" && \ |
93 | | - kernel=$(kernel-install list --json pretty | jq -r '.[] | select(.has_kernel == true) | .version') && \ |
94 | | - DRACUT_NO_XATTR=1 dracut --force -v --zstd --reproducible --no-hostonly \ |
95 | | - --add "anaconda" \ |
96 | | - "/usr/lib/modules/${kernel}/initramfs.img" "${kernel}" |
97 | | - |
98 | | -RUN mkdir /etc/systemd/user/pipewire.service.d/ |
99 | | -COPY <<EOT /etc/systemd/user/pipewire.service.d/allowroot.conf |
100 | | -[Unit] |
101 | | -ConditionUser= |
102 | | -EOT |
103 | | - |
104 | | -RUN mkdir /etc/systemd/user/pipewire.socket.d/ |
105 | | -COPY <<EOT /etc/systemd/user/pipewire.socket.d/allowroot.conf |
106 | | -[Unit] |
107 | | -ConditionUser= |
108 | | -EOT |
| 87 | +## Sample CentOS 10 bootc container |
| 88 | + |
| 89 | +The CentOS container is slightly different from the Fedora container due to the |
| 90 | +bootloader files being in a different location. |
| 91 | + |
| 92 | +Replace the top 3 lines with: |
| 93 | +``` |
| 94 | +FROM quay.io/centos/centos-bootc:c10s |
| 95 | +RUN dnf -y install grub2-efi-*-cdboot xorriso isomd5sum dracut-live erofs-utils shim && dnf clean all |
| 96 | +RUN cp -r /usr/lib/bootupd/updates/EFI/* /boot/efi/EFI/ |
| 97 | +``` |
| 98 | + |
| 99 | +The remainder of the Containerfile is identical to the Fedora example. |
| 100 | + |
| 101 | +# User config |
| 102 | + |
| 103 | +When building the ISO you can use the `image-builder --blueprint user.toml` |
| 104 | +option to customize the users, including root. See the documentation at |
| 105 | +https://osbuild.org/docs/user-guide/blueprint-reference/#additional-users |
| 106 | + |
| 107 | +For example, to set the root password use a minimal blueprint like this: |
109 | 108 | ``` |
| 109 | +name = "setup-root" |
| 110 | +version = "1.0.0" |
| 111 | +
|
| 112 | +[[customizations.user]] |
| 113 | +name = "root" |
| 114 | +password = "root-password" |
| 115 | +``` |
| 116 | + |
| 117 | +And run `image-builder` like so: |
| 118 | +``` |
| 119 | +image-builder build --bootc-default-fs ext4 --bootc-ref localhost/bootc-iso:latest --blueprint setup-root.toml generic-iso |
| 120 | +``` |
| 121 | + |
| 122 | +# Troubleshooting |
110 | 123 |
|
111 | | -You can then build this into an ISO: |
| 124 | +You can inspect the container you built by running bash: |
112 | 125 |
|
113 | 126 | ``` |
114 | | -sudo podman build -t localhost/iso -f Containerfile |
115 | | -sudo image-builder build --bootc-ref localhost/iso --bootc-default-fs ext4 bootc-generic-iso |
| 127 | +podman run --rm -it localhost/bootc-iso:latest /usr/bin/bash |
116 | 128 | ``` |
117 | 129 |
|
118 | | -> [!WARNING] |
119 | | -> *A `bootc`-system installed through Anaconda will fail to start the `systemd-remount-fs.service`. See [here](https://forge.fedoraproject.org/atomic-desktops/tracker/issues/72#issuecomment-593808) and [here](https://bugzilla.redhat.com/show_bug.cgi?id=2332319) for more information.* |
| 130 | +Check the contents of `/usr/lib/ostree/prepare-root.conf` and |
| 131 | +`/usr/lib/dracut/dracut.conf.d/40-iso.conf` to make sure they were created |
| 132 | +correctly. You can also run `lsinitrd --mod /usr/lib/modules/*/initramfs.img` |
| 133 | +to check to make sure the new initramfs contains the dmsquash-live and ostree |
| 134 | +modules. |
120 | 135 |
|
| 136 | +## Fails to mount the OSTree root |
121 | 137 |
|
122 | | -For more examples, including for other operating systems, you can take a look at [this demonstration repository](https://github.com/ondrejbudai/bootc-isos). |
| 138 | +If you get an error like: |
123 | 139 |
|
124 | | -## Historical |
| 140 | +ostree-prepare-root[848]: ostree-prepare-root: Couldn't find specified OSTree root |
125 | 141 |
|
126 | | -### `bootc-installer` |
| 142 | +Check that the grub.cfg `ostree=...` entry in grub.cfg points to the path in the |
| 143 | +rootfs.img. The build process sets this uuid from the ostree directory so this really should not happen with an ISO build unless you change the ISO contents yourself. |
127 | 144 |
|
128 | | -There's an alternative image type called `bootc-installer` which makes more assumptions about the contents of the container. You should prefer using `bootc-generic-iso`. |
| 145 | +Or if the error looks like: |
129 | 146 |
|
130 | | -### `anaconda-iso` |
| 147 | +ostree-prepare-root: Failed to mount composefs: composefs: failed to mount: Input/output error |
131 | 148 |
|
132 | | -There was an alternative image type called `anaconda-iso` or `iso` in `bootc-image-builder` but this image type is not available in `image-builder`. See the [migration guide](./50-migration.md). |
| 149 | +Check the prepare-root.conf file to make sure composefs has been disabled. |
0 commit comments