diff --git a/doc/01-usage.md b/doc/01-usage.md index 641ba87d..2cf113fb 100644 --- a/doc/01-usage.md +++ b/doc/01-usage.md @@ -178,7 +178,7 @@ $ sudo image-builder build --bootc-ref localhost/anaconda:latest --bootc-build-r #### `bootc-installer-payload-ref` -When `image-builder` builds an installer ISO there are two inputs. One is the installer (usually Anaconda) environment (passed as `--bootc-ref`) and the other is the bootable container that will be installed by the installer (passed as `--bootc-installer-payload-ref`). Both arguments are mandatory when building a `bootc-installer`. +When `image-builder` builds an installer ISO there are two inputs. One is the installer (usually Anaconda) environment (passed as `--bootc-ref`) and the other is the bootable container that will be installed by the installer (passed as `--bootc-installer-payload-ref`). Both arguments are mandatory when building a `bootc-installer`. To do this you'll need to provide your own installer image. For information about building your own installers read the [advanced bootc section on installers](./20-advanced/20-bootc/10-installers.md). ```console $ sudo podman pull quay.io/centos-bootc/centos:stream10 @@ -186,42 +186,6 @@ $ sudo image-builder build --bootc-ref localhost/anaconda:latest --bootc-install # ... ``` -Since there are no pre-provided installer container images at this moment, you can use a Containerfile similar to: - -```Dockerfile -FROM your-favorite-bootc-container:latest -RUN dnf install -y \ - anaconda \ - anaconda-install-env-deps \ - anaconda-dracut \ - dracut-config-generic \ - dracut-network \ - net-tools \ - squashfs-tools \ - grub2-efi-x64-cdboot \ - python3-mako \ - lorax-templates-* \ - biosdevname \ - prefixdevname \ - && dnf clean all - -# On Fedora 42 this is necessary to get files in the right places -# RUN dnf reinstall -y shim-x64 - -# On Fedora 43 and up this is necessary to get files in the right -# places -RUN mkdir -p /boot/efi && cp -ra /usr/lib/efi/*/*/EFI /boot/efi - -# lorax wants to create a symlink in /mnt which points to /var/mnt -# on bootc but /var/mnt does not exist on some images. -# -# If https://gitlab.com/fedora/bootc/base-images/-/merge_requests/294 -# gets merged this will be no longer needed -RUN mkdir /var/mnt -``` - -To produce your own Anaconda-based installer. - #### `bootc-default-fs` During the build of an image from a bootable container `image-builder` has to determine a partition table to use. For bootable containers we want the source of truth to be the container itself. The container usually contains (some) configuration to let image build tools such as `image-builder` know what to do. diff --git a/doc/20-advanced/20-bootc/05-sources-of-configuration.md b/doc/20-advanced/20-bootc/05-sources-of-configuration.md new file mode 100644 index 00000000..f36fc22e --- /dev/null +++ b/doc/20-advanced/20-bootc/05-sources-of-configuration.md @@ -0,0 +1,301 @@ +# Sources of Configuration + +In `bootc`-land it is preferred for the source of truth to be the container itself. For `image-builder` that means that certain instructions can be stored inside the container and will be used by `image-builder` when present. We get various bits and bobs from different places . This page describes what we get from where. + +## `bootc print-config` + +## Filesystem + +`image-builder` will use several files with different purposes from the container filesystem if they exist. These files are expected to exist in the `/usr/lib/image-builder/bootc` directory. + +For historical reasons `image-builder` will also see if these files exist in the `/usr/lib/bootc-image-builder` directory. The `/usr/lib/image-builder/bootc` directory has preference and any containers using the `/usr/lib/bootc-image-builder` path should be changed to use `/usr/lib/image-builder/bootc` instead. + +### `disk.yaml` + +A YAML file containing the partition layout to use when turning the container image into a disk image. The canonical location for this file is `/usr/lib/image-builder/bootc/disk.yaml`. + +If present this will replace the base partition tables that `image-builder` uses during build. Blueprint customizations can be applied on top by end-users that want to modify their deployments. + +A quick example that sets up a very default partition layout (BIOS boot, ESP, XBOOTLDR, and root partition) before explanation and more complex examples. + +> [!WARNING] +> *The BIOS boot partition is currently required by `bootupd`, hence we've included it here in every example. This might change in the future and be dependent on the container itself; see [this issue](https://github.com/coreos/bootupd/issues/1067).* + +```yaml +mount_configuration: "units" +partition_table: + type: "gpt" + partitions: + - size: "1 MiB" + type: "21686148-6449-6e6F-744e-656564454649" + bootable: true + - size: "200 MiB" + type: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" + payload_type: "filesystem" + payload: + type: "vfat" + mountpoint: "/boot/efi" + label: "ESP" + fstab_options: "defaults,uid=0,gid=0,umask=077,shortname=winnt" + fstab_freq: 0 + fstab_passno: 2 + - size: "2 GiB" + type: "bc13c2ff-59e6-4262-a352-b275fd6f7172" + payload_type: "filesystem" + payload: + type: "ext4" + label: "boot" + mountpoint: "/boot" + fstab_options: "defaults" + fstab_freq: 0 + fstab_passno: 0 + - size: "4 GiB" + type: "44479540-f297-41b2-9af7-d131d5f0458a" + payload_type: "filesystem" + payload: + type: "ext4" + label: "root" + mountpoint: "/" + fstab_options: "defaults" + fstab_freq: 0 + fstab_passno: 0 +``` + +*The type UUIDs used in this example come from the [Discoverable Partitions Specification](https://uapi-group.org/specifications/specs/discoverable_partitions_specification/).* + +`mount_configuration` is an enum and can hold the values `fstab`, `units`, or `none`. It dictates how the mountpoints are configured in the disk image. `fstab` will write an `/etc/fstab`, `units` will write systemd mount unit files, and `none` will do neither; leaving it up to tooling such as `systemd-gpt-auto-generator` to figure out what to mount where. + +`partition_table` is an object with the following properties: + +- `type`, an `enum` that can be `gpt` or `dos` and sets the partition table format to use. +- `partitions`, a list of objects each of which represents a partition. + +#### Partitions + +Each partition can have the following properties: + +- `size`, a string with units to set the size of the partition. +- `type`, the partition type GPT UUID *or* DOS ID. + +- `bootable`, an *optional* boolean indicating that this partition is legacy BIOS bootable (GPT) or active (DOS). +- `uuid`, an *optional* string containing the partition UUID itself. Should be omitted and will be based on a PRNG, fixing this value can lead to issues trying to mount the same disk multiple times. +- `label`, an *optional* `string` containing the partition name (**not** the filesystem label) for GPT. +- `attrs`, an *optional* array of unsigned integers that set partition attribute flags for GPT. + +- `payload_type`, an `enum` that contains one `filesystem`, `luks`, `lvm`, `btrfs`, `raw`. This field dictates what goes into the `payload` object that comes next. +- `payload`, an object based on the value of `payload_type`. `payload_type`s and their `payload` contents are explained below. + +##### Payloads + +###### Filesystem + +For a `payload_type: filesystem` the `payload` has the following properties: + +- `type` +- `mountpoint`, a `string` that tells where this partition should be mounted. + + +- `label`, an *optional* `string` that contains the filesystem label. +- `fstab_options` +- `fstab_freq` +- `fstab_passno` + +Here's an example defining a few partition with XFS filesystem(s): + +``` +mount_configuration: "units" +partition_table: + type: "gpt" + partitions: + - size: "1 MiB" + type: "21686148-6449-6e6F-744e-656564454649" + bootable: true + - size: "200 MiB" + type: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" + payload_type: "filesystem" + payload: + type: "vfat" + mountpoint: "/boot/efi" + label: "ESP" + fstab_options: "defaults,uid=0,gid=0,umask=077,shortname=winnt" + fstab_freq: 0 + fstab_passno: 2 + - size: "2 GiB" + type: "bc13c2ff-59e6-4262-a352-b275fd6f7172" + payload_type: "filesystem" + payload: + type: "xfs" + label: "boot" + mountpoint: "/boot" + - payload_type: "filesystem" + payload: + type: "xfs" + label: "root" + mountpoint: "/" +``` + +###### LVM + +> [!WARNING] +> *LVM configurations currently do not work with bootable containers in `image-builder`. See [here](https://github.com/osbuild/images/issues/2228).* + +For a `payload_type: lvm` the `payload` has the following properties: + +- `name` +- `description` +- `logical_volumes` a list of objects. + +The `logical_volumes` objects have the following properties: + +- `size`, a string with units to set the size of the partition. +- `name`, a `string` with the name of the volume group. + +- `payload_type` +- `payload` + +An example of using the `lvm` payload: + +``` +mount_configuration: "fstab" +partition_table: + type: "gpt" + partitions: + - size: "1 MiB" + bootable: true + type: "21686148-6449-6e6F-744e-656564454649" + - size: "200 MiB" + type: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" + payload_type: "filesystem" + payload: + type: "vfat" + mountpoint: "/boot/efi" + label: "ESP" + fstab_options: "defaults,uid=0,gid=0,umask=077,shortname=winnt" + fstab_freq: 0 + fstab_passno: 2 + - size: "2 GiB" + type: "bc13c2ff-59e6-4262-a352-b275fd6f7172" + payload_type: "filesystem" + payload: + type: "ext4" + label: "boot" + mountpoint: "/boot" + fstab_options: "defaults" + - size: "8 GiB" + type: "44479540-f297-41b2-9af7-d131d5f0458a" + payload_type: "lvm" + payload: + name: "systemVG" + logical_volumes: + - size: "4 GiB" + name: "LVroot" + payload_type: "filesystem" + payload: + type: "xfs" + label: "root" + mountpoint: "/" + fstab_options: "defaults" +``` + +*Note the nested payload to put a filesystem inside the `LVRoot` logical volume.* + +###### btrfs + +For a `payload_type: btrfs` the `payload` has the following properties: + +- `subvolumes`, a list of objects. + +The `subvolumes` objects have the following properties: + +- `name` +- `mountpoint` + +An example of using the `btrfs` payload: + +```yaml +mount_configuration: "units" +partition_table: + type: "gpt" + partitions: + - size: "1 MiB" + bootable: true + type: "21686148-6449-6e6F-744e-656564454649" + - size: "200 MiB" + type: "c12a7328-f81f-11d2-ba4b-00a0c93ec93b" + payload_type: "filesystem" + payload: + type: "vfat" + mountpoint: "/boot/efi" + label: "ESP" + fstab_options: "defaults,uid=0,gid=0,umask=077,shortname=winnt" + fstab_freq: 0 + fstab_passno: 2 + - size: "2 GiB" + type: "bc13c2ff-59e6-4262-a352-b275fd6f7172" + payload_type: "filesystem" + payload: + type: "ext4" + label: "boot" + mountpoint: "/boot" + fstab_options: "defaults" + fstab_freq: 0 + fstab_passno: 0 + - size: "4 GiB" + type: "44479540-f297-41b2-9af7-d131d5f0458a" + payload_type: "btrfs" + payload: + subvolumes: + - name: "root" + mountpoint: "/" + - name: "home" + mountpoint: "/home" + - name: "var" + mountpoint: "/var" +``` + +*To use `btrfs` your container must set its configured root filesystem to `btrfs`, or it must be passed when `image-builder` is called.* + +*To use `btrfs` your build host and container kernel must support `btrfs`.* + +###### LUKS + +> [!WARNING] +> *LUKS configurations currently do not work with bootable containers in `image-builder`. See [here](https://github.com/osbuild/images/issues/2228).* + +Allows for setting up disk encryption with luks. Contains other payloads (filesystems). + +For a `payload_type: luks` the `payload` has the following properties: + +- `label` +- `cipher` +- `passphrase` +- `pbkdf` +- `clevis` + +- `payload_type` +- `payload` + +An example of how you can use the `luks` payload. + +```yaml + +``` + +###### raw + +For a `payload_type: raw` the `payload` has the following properties: + +- + +### `iso.yaml` + +A YAML file containing instructions for constructing an ISO. This YAML file is only used for the `bootc-generic-iso` image type which makes as few assumptions as possible and thus needs extra instructions to tell it what to do. Read [more about the `bootc-generic-iso`](./10-isos.md) to see what you can do with this file. + +```yaml +label: "Fedora-bootc-Installer" +grub2: + entries: + - name: "Install Fedora (bootc)" + linux: "/images/pxeboot/vmlinuz inst.stage2=hd:LABEL=Fedora-bootc-Installer console=tty0 inst.text selinux=0" + initrd: "/images/pxeboot/initrd.img" +``` diff --git a/doc/20-advanced/20-bootc/10-isos.md b/doc/20-advanced/20-bootc/10-isos.md new file mode 100644 index 00000000..5da96b37 --- /dev/null +++ b/doc/20-advanced/20-bootc/10-isos.md @@ -0,0 +1,131 @@ +# ISOs + +## Generic + +`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: + +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. +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. +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. +4. shim and grub2 EFI binaries (`shimx64.efi`, `mmx64.efi`, `gcdx64.efi`) are expected to be present in `/boot/efi/EFI/$VENDOR`. +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. +6. The container image is converted to a `squashfs` filesystem and put into `/LiveOS/squashfs.img` in the ISO. + +You can [define additional configuration](./05-sources-of-configuration.md#isoyaml) for an ISO inside your container. + +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. + +### Example Containerfile + +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. + +```Dockerfile +FROM quay.io/fedora/fedora-bootc:rawhide + +RUN dnf install -qy \ + anaconda \ + anaconda-install-img-deps \ + anaconda-dracut \ + dracut-config-generic \ + dracut-network \ + net-tools \ + grub2-efi-x64-cdboot \ + plymouth \ + default-fonts-core-sans \ + default-fonts-other-sans \ + google-noto-sans-cjk-fonts + +# these are necessary build tools. if you use a separate build container then +# these tools should be installed there +RUN dnf install -qy \ + xorrisofs \ + squashfs-tools + +RUN dnf clean all + +RUN mkdir -p /boot/efi && cp -ra /usr/lib/efi/*/*/EFI /boot/efi + +# --- + +# some configuration for our ISO + +RUN mkdir -p /usr/lib/image-builder/bootc + +COPY <> /etc/passwd && \ + echo "install::14438:0:99999:7:::" >> /etc/shadow && \ + passwd -d root + +RUN mv /usr/share/anaconda/list-harddrives-stub /usr/bin/list-harddrives && \ + mv /etc/yum.repos.d /etc/anaconda.repos.d && \ + ln -s /lib/systemd/system/anaconda.target /etc/systemd/system/default.target && \ + rm -v /usr/lib/systemd/system-generators/systemd-gpt-auto-generator + +RUN ln -s /usr/lib/systemd/system/anaconda-shell@.service /usr/lib/systemd/system/autovt@.service + +RUN mkdir /usr/lib/systemd/logind.conf.d +COPY < [!WARNING] +> *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.* + + +For more examples, including for other operating systems, you can take a look at [this demonstration repository](https://github.com/ondrejbudai/bootc-isos). + +## Historical + +### `bootc-installer` + +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`. + +### `anaconda-iso` + +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). diff --git a/doc/20-advanced/20-bootc/50-migration.md b/doc/20-advanced/20-bootc/50-migration.md new file mode 100644 index 00000000..40373dac --- /dev/null +++ b/doc/20-advanced/20-bootc/50-migration.md @@ -0,0 +1 @@ +# Migrating from `bootc-image-builder` diff --git a/doc/20-advanced/20-bootc/index.md b/doc/20-advanced/20-bootc/index.md new file mode 100644 index 00000000..d0a49724 --- /dev/null +++ b/doc/20-advanced/20-bootc/index.md @@ -0,0 +1,5 @@ +# Advanced `bootc` Topics + +- [Sources of Configuration](./05-sources-of-configuration.md) +- [ISOs](./10-isos.md) +- [Migrating from `bootc-image-builder`](./50-migration.md)