docs/BUILDING_IMAGES: format text

This commit is contained in:
hulkoba 2024-02-26 13:47:00 +01:00
parent e9a55babcd
commit 59652fff30
No known key found for this signature in database
GPG Key ID: ACB6C4A3A4F2BE2F

View File

@ -9,12 +9,14 @@ SPDX-License-Identifier: LGPL-2.1-or-later
In many scenarios OS installations are shipped as pre-built images, that In many scenarios OS installations are shipped as pre-built images, that
require no further installation process beyond simple `dd`-ing the image to require no further installation process beyond simple `dd`-ing the image to
disk and booting it up. When building such "golden" OS images for disk and booting it up.
When building such "golden" OS images for
`systemd`-based OSes a few points should be taken into account. `systemd`-based OSes a few points should be taken into account.
Most of the points described here are implemented by the Most of the points described here are implemented by the
[`mkosi`](https://github.com/systemd/mkosi) OS image builder developed and [`mkosi`](https://github.com/systemd/mkosi) OS image builder developed and
maintained by the systemd project. If you are using or working on another image maintained by the systemd project.
If you are using or working on another image
builder it's recommended to keep the following concepts and recommendations in builder it's recommended to keep the following concepts and recommendations in
mind. mind.
@ -24,28 +26,25 @@ Typically the same OS image shall be deployable in multiple instances, and each
instance should automatically acquire its own identifying credentials on first instance should automatically acquire its own identifying credentials on first
boot. For that it's essential to: boot. For that it's essential to:
1. Remove the 1. Remove the [`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html)
[`/etc/machine-id`](https://www.freedesktop.org/software/systemd/man/machine-id.html) file or write the string `uninitialized\n` into it.
file or write the string `uninitialized\n` into it. This file is supposed to This file is supposed to carry a 128-bit identifier unique to the system.
carry a 128-bit identifier unique to the system. Only when it is reset it Only when it is reset it will be auto-generated on first boot and thus be truly unique.
will be auto-generated on first boot and thus be truly unique. If this file If this file is not reset, and carries a valid ID every instance of the system will come
is not reset, and carries a valid ID every instance of the system will come
up with the same ID and that will likely lead to problems sooner or later, up with the same ID and that will likely lead to problems sooner or later,
as many network-visible identifiers are commonly derived from the machine as many network-visible identifiers are commonly derived from the machine ID,
ID, for example, IPv6 addresses or transient MAC addresses. for example, IPv6 addresses or transient MAC addresses.
2. Remove the `/var/lib/systemd/random-seed` file (see 2. Remove the `/var/lib/systemd/random-seed` file(see
[`systemd-random-seed(8)`](https://www.freedesktop.org/software/systemd/man/systemd-random-seed.service.html)), [`systemd-random-seed(8)`](https://www.freedesktop.org/software/systemd/man/systemd-random-seed.service.html)),
which is used to seed the kernel's random pool on boot. If this file is which is used to seed the kernel's random pool on boot.
shipped pre-initialized, every instance will seed its random pool with the If this file is shipped pre-initialized, every instance will seed its random pool with the
same random data that is included in the image, and thus possibly generate same random data that is included in the image, and thus possibly generate
random data that is more similar to other instances booted off the same random data that is more similar to other instances booted off the same image than advisable.
image than advisable.
3. Remove the `/loader/random-seed` file (see 3. Remove the `/loader/random-seed` file (see
[`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html)) [`systemd-boot(7)`](https://www.freedesktop.org/software/systemd/man/systemd-boot.html))
from the UEFI System Partition (ESP), in case the `systemd-boot` boot loader from the UEFI System Partition (ESP), in case the `systemd-boot` boot loader is used in the image.
is used in the image.
4. It might also make sense to remove 4. It might also make sense to remove
[`/etc/hostname`](https://www.freedesktop.org/software/systemd/man/hostname.html) [`/etc/hostname`](https://www.freedesktop.org/software/systemd/man/hostname.html)
@ -69,24 +68,25 @@ The
logic used to generate logic used to generate
[Boot Loader Specification Type #1](https://uapi-group.org/specifications/specs/boot_loader_specification/#type-1-boot-loader-specification-entries) [Boot Loader Specification Type #1](https://uapi-group.org/specifications/specs/boot_loader_specification/#type-1-boot-loader-specification-entries)
entries by default uses the machine ID as stored in `/etc/machine-id` for entries by default uses the machine ID as stored in `/etc/machine-id` for
naming boot menu entries and the directories in the ESP to place kernel images naming boot menu entries and the directories in the ESP to place kernel images in.
in. This is done in order to allow multiple installations of the same OS on the This is done in order to allow multiple installations of the same OS on the
same system without conflicts. However, this is problematic if the machine ID same system without conflicts. However, this is problematic if the machine ID
shall be generated automatically on first boot: if the ID is not known before shall be generated automatically on first boot: if the ID is not known before
the first boot it cannot be used to name the most basic resources required for the first boot it cannot be used to name the most basic resources required for
the boot process to complete. the boot process to complete.
Thus, for images that shall acquire their identity on first boot only, it is Thus, for images that shall acquire their identity on first boot only, it is
required to use a different identifier for naming boot menu entries. To allow required to use a different identifier for naming boot menu entries.
this the `kernel-install` logic knows the generalized *entry* *token* concept, To allow this the `kernel-install` logic knows the generalized *entry* *token* concept,
which can be a freely chosen string to use for identifying the boot menu which can be a freely chosen string to use for identifying the boot menu
resources of the OS. If not configured explicitly it defaults to the machine resources of the OS.
ID. The file `/etc/kernel/entry-token` may be used to configure this string If not configured explicitly it defaults to the machineID.
explicitly. Thus, golden image builders should write a suitable identifier into The file `/etc/kernel/entry-token` may be used to configure this string explicitly.
Thus, golden image builders should write a suitable identifier into
this file, for example, the `IMAGE_ID=` or `ID=` field from this file, for example, the `IMAGE_ID=` or `ID=` field from
[`/etc/os-release`](https://www.freedesktop.org/software/systemd/man/os-release.html) [`/etc/os-release`](https://www.freedesktop.org/software/systemd/man/os-release.html)
(also see below). It is recommended to do this before the `kernel-install` (also see below).
functionality is invoked (i.e. before the package manager is used to install It is recommended to do this before the `kernel-install` functionality is invoked (i.e. before the package manager is used to install
packages into the OS tree being prepared), so that the selected string is packages into the OS tree being prepared), so that the selected string is
automatically used for all entries to be generated. automatically used for all entries to be generated.
@ -94,16 +94,16 @@ automatically used for all entries to be generated.
`systemd` is designed to be able to come up safely and robustly if the `/var/` `systemd` is designed to be able to come up safely and robustly if the `/var/`
file system or even the entire root file system (with exception of `/usr/`, file system or even the entire root file system (with exception of `/usr/`,
i.e. the vendor OS resources) is empty (i.e. "unpopulated"). With this in mind i.e. the vendor OS resources) is empty (i.e. "unpopulated").
it's relatively easy to build images that only ship a `/usr/` tree, and With this in mind it's relatively easy to build images that only ship a `/usr/` tree, and
otherwise carry no other data, populating the rest of the directory hierarchy otherwise carry no other data, populating the rest of the directory hierarchy
on first boot as needed. on first boot as needed.
Specifically, the following mechanisms are in place: Specifically, the following mechanisms are in place:
1. The `switch-root` logic in systemd, that is used to switch from the initrd 1. The `switch-root` logic in systemd, that is used to switch from the initrd
phase to the host will create the basic OS hierarchy skeleton if missing. It phase to the host will create the basic OS hierarchy skeleton if missing.
will create a couple of directories strictly necessary to boot up It will create a couple of directories strictly necessary to boot up
successfully, plus essential symlinks (such as those necessary for the successfully, plus essential symlinks (such as those necessary for the
dynamic loader `ld.so` to function). dynamic loader `ld.so` to function).
@ -136,14 +136,18 @@ Specifically, the following mechanisms are in place:
remains resolvable, even without `/etc/hosts` around. remains resolvable, even without `/etc/hosts` around.
With these mechanisms the hierarchies below `/var/` and `/etc/` can be safely With these mechanisms the hierarchies below `/var/` and `/etc/` can be safely
and robustly populated on first boot, so that the OS can safely boot up. Note and robustly populated on first boot, so that the OS can safely boot up.
that some auxiliary package are not prepared to operate correctly if their Note that some auxiliary package are not prepared to operate correctly if their
configuration data in `/etc/` or their state directories in `/var/` are configuration data in `/etc/` or their state directories in `/var/` are
missing. This can typically be addressed via `systemd-tmpfiles` lines that missing.
ensure the missing files and directories are created if missing. In particular,
configuration files that are necessary for operation can be automatically This can typically be addressed via `systemd-tmpfiles` lines that
ensure the missing files and directories are created if missing.
In particular, configuration files that are necessary for operation can be automatically
copied or symlinked from the `/usr/share/factory/etc/` tree via the `C` or `L` copied or symlinked from the `/usr/share/factory/etc/` tree via the `C` or `L`
line types. That said, we recommend that all packages safely fall back to line types.
That said, we recommend that all packages safely fall back to
internal defaults if their configuration is missing, making such additional internal defaults if their configuration is missing, making such additional
steps unnecessary. steps unnecessary.
@ -156,17 +160,17 @@ manual work might be required to make this scenario work.
Typically, if an image is `dd`-ed onto a target disk it will be minimal: Typically, if an image is `dd`-ed onto a target disk it will be minimal:
i.e. only consist of necessary vendor data, and lack "payload" data, that shall i.e. only consist of necessary vendor data, and lack "payload" data, that shall
be individual to the system, and dependent on host parameters. On first boot, be individual to the system, and dependent on host parameters.
the OS should take possession of the backing storage as necessary, dynamically On first boot, the OS should take possession of the backing storage as necessary, dynamically
using available space. Specifically: using available space. Specifically:
1. Additional partitions should be created, that make no sense to ship 1. Additional partitions should be created, that make no sense to ship
pre-built in the image. For example, `/tmp/` or `/home/` partitions, or even pre-built in the image.
`/var/` or the root file system (see above). For example, `/tmp/` or `/home/` partitions, or even `/var/` or the root file system (see above).
2. Additional partitions should be created that shall function as A/B 2. Additional partitions should be created that shall function as A/B
secondaries for partitions shipped in the original image. In other words: if secondaries for partitions shipped in the original image.
the `/usr/` file system shall be updated in an A/B fashion it typically In other words: if the `/usr/` file system shall be updated in an A/B fashion it typically
makes sense to ship the original A file system in the deployed image, but makes sense to ship the original A file system in the deployed image, but
create the B partition on first boot. create the B partition on first boot.
@ -191,10 +195,10 @@ it, then format it.
1. The 1. The
[`systemd-repart(8)`](https://www.freedesktop.org/software/systemd/man/systemd-repart.service.html) [`systemd-repart(8)`](https://www.freedesktop.org/software/systemd/man/systemd-repart.service.html)
component may manipulate GPT partition tables automatically on boot, growing component may manipulate GPT partition tables automatically on boot, growing
partitions or adding in partitions taking the backing storage size into partitions or adding in partitions taking the backing storage size into account.
account. It can also encrypt partitions automatically it creates (even bind It can also encrypt partitions automatically it creates (even bind
to TPM2, automatically) and populate partitions from various sources. It to TPM2, automatically) and populate partitions from various sources.
does this all in a robust fashion so that aborted invocations will not leave It does this all in a robust fashion so that aborted invocations will not leave
incompletely set up partitions around. incompletely set up partitions around.
2. The 2. The
@ -215,8 +219,8 @@ it, then format it.
While a lot of work has gone into ensuring `systemd` systems can safely boot While a lot of work has gone into ensuring `systemd` systems can safely boot
with unpopulated `/etc/` trees, it sometimes is desirable to set a couple of with unpopulated `/etc/` trees, it sometimes is desirable to set a couple of
basic settings *after* `dd`-ing the image to disk, but *before* first boot. For basic settings *after* `dd`-ing the image to disk, but *before* first boot.
this the tool For this the tool
[`systemd-firstboot(1)`](https://www.freedesktop.org/software/systemd/man/systemd-firstboot.html) [`systemd-firstboot(1)`](https://www.freedesktop.org/software/systemd/man/systemd-firstboot.html)
can be useful, with its `--image=` switch. It may be used to set very basic can be useful, with its `--image=` switch. It may be used to set very basic
settings, such as the root password or hostname on an OS disk image or settings, such as the root password or hostname on an OS disk image or
@ -225,36 +229,33 @@ installed block device.
## Distinguishing First Boot ## Distinguishing First Boot
For various purposes it's useful to be able to distinguish the first boot-up of For various purposes it's useful to be able to distinguish the first boot-up of
the system from later boot-ups (for example, to set up TPM hardware the system from later boot-ups (for example, to set up TPM hardware specifically, or register a system somewhere).
specifically, or register a system somewhere). `systemd` provides mechanisms to `systemd` provides mechanisms to implement that.
implement that. Specifically, the `ConditionFirstBoot=` and `AssertFirstBoot=` Specifically, the `ConditionFirstBoot=` and `AssertFirstBoot=` settings may be used to conditionalize units to only run on first boot.
settings may be used to conditionalize units to only run on first boot. See See [`systemd.unit(5)`](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConditionFirstBoot=)
[`systemd.unit(5)`](https://www.freedesktop.org/software/systemd/man/systemd.unit.html#ConditionFirstBoot=)
for details. for details.
A special target unit `first-boot-complete.target` may be used as milestone to A special target unit `first-boot-complete.target` may be used as milestone to
safely handle first boots where the system is powered off too early: if the safely handle first boots where the system is powered off too early:
first boot process is aborted before this target is reached, the following boot if the first boot process is aborted before this target is reached, the following boot
process will be considered a first boot, too. Once the target is reached, process will be considered a first boot, too.
subsequent boots will not be considered first boots anymore, even if the boot Once the target is reached, subsequent boots will not be considered first boots anymore, even if the boot
process is aborted immediately after. Thus, services that must complete fully process is aborted immediately after.
before a system shall be considered fully past the first boot should be ordered Thus, services that must complete fully before a system shall be considered fully past the first boot should be ordered before this target unit.
before this target unit.
Whether a system will come up in first boot state or not is derived from the Whether a system will come up in first boot state or not is derived from the
initialization status of `/etc/machine-id`: if the file already carries a valid initialization status of `/etc/machine-id`:
ID the system is already past the first boot. If it is not initialized yet it if the file already carries a valid ID the system is already past the first boot.
is still considered in the first boot state. For details see If it is not initialized yet it is still considered in the first boot state.
[`machine-id(5)`](https://www.freedesktop.org/software/systemd/man/machine-id.html). For details see [`machine-id(5)`](https://www.freedesktop.org/software/systemd/man/machine-id.html).
## Image Metadata ## Image Metadata
Typically, when operating with golden disk images it is useful to be able to Typically, when operating with golden disk images it is useful to be able to
identify them and their version. For this the two fields `IMAGE_ID=` and identify them and their version.
`IMAGE_VERSION=` have been defined in For this the two fields `IMAGE_ID=` and `IMAGE_VERSION=` have been defined in
[`os-release(5)`](https://www.freedesktop.org/software/systemd/man/os-release.html). These [`os-release(5)`](https://www.freedesktop.org/software/systemd/man/os-release.html).
fields may be accessed from unit files and similar via the `%M` and `%A` These fields may be accessed from unit files and similar via the `%M` and `%A` specifiers.
specifiers.
Depending on how the images are put together it might make sense to leave the Depending on how the images are put together it might make sense to leave the
OS distribution's `os-release` file as is in `/usr/lib/os-release` but to OS distribution's `os-release` file as is in `/usr/lib/os-release` but to