Skip to content

Commit 5427883

Browse files
committed
Improve containerized builds
- "Tiered" configuration simplifies management and allows more targeted overrides, symlinking configs in `/etc/zfsbootmenu` in the container: 1. First tier comes from `etc/zfsbootmenu` (global defaults) 2. Second tier comes from `etc/zbm-builder` (container defaults) 3. Third tier comes from the build root (build specific) Configurations in later tiers override those with conflicting names in earlier tiers. - Tiered configuration now includes mkinitcpio configuration, allowing containers to build mkinitcpio images - Container configuration for mkinitcpio supports dracut-style snippets in `mkinitcpio.conf.d` - The builder now looks for an `rc.d` subdirectory in the build root and will invoke every executable file therein before generating images to provide a means to "terraform" the build container - The `zbm-builder.sh` wrapper now supports a configuration file to allow defaults to be specified; this requires a two-pass getopts to find and load the configuration file before parsing remaining options - A new option to `zbm-builder.sh`, `-R`, will remove any existing host files (`hostid` and `zpool.cache`) from the build root to make sure they are always up to date with the host versions - The container entrypoint now configures `generate-zbm` to write its output directly to the desired output directory rather than staging in a temporary output directory, allowing `generate-zbm` to manage version rollovers as it does in host installations - Remove superfluous arguments from container entrypoint to manage `hostid`, `zpool.cache` and `config.yaml`; the files either exist in the build root or the container will use defaults - Drop `docker-compose.yml` and now-obsolete `config.yaml.default` - Update documentation to better reflect current build procedure
1 parent 087892c commit 5427883

File tree

7 files changed

+316
-214
lines changed

7 files changed

+316
-214
lines changed

etc/zbm-builder/config.yaml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
Global:
2+
# Set InitCPIO to true to use mkinitcpio for ZBM images
3+
#InitCPIO: true
4+
# The build container *forces* Global.ManageImages
5+
Components:
6+
# Enable only current kernel/initramfs components and a backup
7+
Enabled: true
8+
Versions: false
9+
# The ZBM build container *forces* Components.ImageDir
10+
EFI:
11+
# Enable only current EFI executable and a backup file
12+
Enabled: true
13+
Versions: false
14+
# The ZBM build container *forces* EFI.ImageDir
15+
Kernel:
16+
# Set ZBM command-line options for the EFI bundle here
17+
CommandLine: zfsbootmenu ro quiet loglevel=4 nomodeset

etc/zbm-builder/mkinitcpio.conf

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# This is a specialization of the ZFSBootMenu mkinitcpio.conf file for use in
2+
# the ghcr.io/zbm-dev/zbm-builder container. Most documentation has been
3+
# omitted. For a description of this file, see the manual pages
4+
#
5+
# - zfsbootmenu(7)
6+
# - mkinitcpio(5)
7+
#
8+
# As well as a more thoroughly commented version at the location
9+
# etc/zfsbootmenu/mkinitcpio.conf in the zfsbootmenu git repository.
10+
11+
# No specific customizations for container builds
12+
MODULES=()
13+
BINARIES=()
14+
FILES=()
15+
16+
# Because generate-zbm adds the required 'zfsbootmenu' hook, omit it here.
17+
HOOKS=(base udev autodetect modconf block filesystems keyboard)
18+
19+
# In containers, it is helpful to allow some dynamic configuration. In
20+
# particular, the zbm-builder.sh helper script that configures and runs the
21+
# build container will automatically create configuration entries in the
22+
# subdirectories
23+
#
24+
# dracut.conf.d
25+
# mkinitcpio.conf.d
26+
#
27+
# of the build directory for any hook found in the subdirectories
28+
#
29+
# hooks.early_setup.d
30+
# hooks.setup.d
31+
# hooks.teardown.d
32+
#
33+
# of the same build directory. Support for mkinitcpio.conf.d mimics similar
34+
# support for dracut.conf.d built directly into dracut.
35+
#
36+
# Note that, inside the container, the build directory will be mounted at
37+
# /build, so reference those paths here.
38+
for _zbm_hook in /build/mkinitcpio.conf.d/*; do
39+
[ -r "${_zbm_hook}" ] || continue
40+
. "${_zbm_hook}"
41+
done
42+
unset _zbm_hook

releng/docker/README.md

Lines changed: 134 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,20 @@ specific commit based on the contents of `/etc/zbm-commit-hash`.
6363

6464
When running a container from the ZFSBootMenu builder image, it is generally
6565
expected that some compatible volume (generally, a local directory) will be
66-
bind-mounted as a volume at the path `/zbm` inside the container. This volume
67-
may either be empty or contain a pre-existing ZFSBootMenu source tree.
68-
Specifically, if the volume is not empty, it must contain the following
69-
components of the ZFSBootMenu repository:
70-
71-
- `dracut`, the Dracut module that populates an image with ZFSBootMenu;
72-
73-
- `zfsbootmenu`, the core ZFSBootMenu components;
74-
75-
- `bin/generate-zbm`, the executable script that creates ZFSBootMenu images;
76-
77-
If the build script finds the volume mounted at `/zbm` empty, it will fetch an
78-
archive of the official ZFSBootMenu repository on github.com. This makes the
79-
image capable of producing default images without needing a local clone of the
80-
repository. The specific commit, tag or branch to fetch can be specified at
81-
container run time.
66+
bind-mounted as a volume at the path `/build` inside the container. The volume
67+
may either be empty or contain a custom ZFSBootMenu configuration and will
68+
contain build products (a UEFI bundle, separate kernel and initramfs
69+
components, or both) in a `build` subdirectory.
70+
71+
The container entrypoint expects to run `generate-zbm` directly from a
72+
ZFSBootMenu source repository that is available at `/zbm` within the container.
73+
If the entrypoint finds `/zbm` nonexistent or devoid of files, it will fetch a
74+
copy of the upstream source repository and unpack it where expected. (The tag,
75+
commit or branch to fetch can be specified at runtime or a default will be
76+
chosen as encoded in the container image.) Any pre-existing and non-empty
77+
`/zbm` within the container must contain a copy of the source repository. This
78+
is useful, *e.g.*, to bind-mount a local clone of the repository into the
79+
container.
8280

8381
## Command-Line Arguments and Environment Variables
8482

@@ -88,43 +86,20 @@ command-line argument to see a summary of build options and their default
8886
options. The options are:
8987

9088
- `$BUILDROOT` specifies a default root for image builds. The build root is
91-
expected to hold a default default configuration file and output directory,
92-
as well as optional hostid and pool cache files. If an output directory,
93-
specific configuration and (when appropriate) hostid or pool cache are
94-
specified, then `$BUILDROOT` is not relevant.
89+
expected to hold configuration files and, optionally, an output directory,
90+
hostid and pool cache files. The value of `$BUILDROOT` is `/build` by
91+
default.
9592

9693
The environment variable or default can be overridden with the `-b` option.
9794

98-
- `$ZBMCONF` specifies the in-container path to a specific configuration file.
99-
The build script will override any `ImageDir` paths and remove any
100-
`Global.BootMountPoint` option but otherwise uses the configuration as-is.A
101-
102-
The environment variable or default can be overridded with the `-c` option.
103-
104-
- `$ZBMOUTPUT` specifies the in-container path to an output directory. As noted
105-
above, the build script overrides any `ImageDir` path in a configuration,
106-
pointing it instead to a temporary output directory. After the script
107-
successfully runs `generate-zbm`, it will copy any artifacts from the
108-
temporary build directory to `$ZBMOUTPUT`.
95+
- `$ZBMOUTPUT` specifies an alternative output directory for ZFSBootMenu build
96+
products. The container *always* overrides configurations to store build
97+
products (UEFI bundles and kernel components, as configured) in a temporary
98+
directory; these products will be copied to `$ZBMOUTPUT` after successful
99+
image creation. The value of `$ZBMOUTPUT` is `${BUILDROOT}/build` by default.
109100

110101
The environment variable or default can be overridded with the `-o` option.
111102

112-
- `$HOSTID` specifies the in-container path to a hostid file. If this file is
113-
specified, it will be copied to `/etc/hostid` inside the container for
114-
inclusion in ZFSBootMenu images. If not, any `/etc/hostid` in the container
115-
will be removed. (Note: unless the `zfsbootmenu` dracut module is configured
116-
with `release_mode=1`, the module may still create an `/etc/hostid` with
117-
potentially arbitrary contents in output images.
118-
119-
The environment variable or default can be overridded with the `-H` option.
120-
121-
- `$POOLCACHE` specifies the in-container path to a ZFS pool cache file. If
122-
this file is specified, it will be copied to `/etc/zfs/zpool.cache` inside
123-
the container for inclusion in ZFSBootMenu images. If not, any
124-
`/etc/zfs/zpool.cache` in the container will be removed.
125-
126-
The environment variable or default can be overridded with the `-C` option.
127-
128103
- `$ZBMTAG` specifies any "commit-ish" label recognized by `git` as a pointer
129104
to a specific git commit. This can be a branch name (to grab the head of that
130105
branch), tag or commit hash. If `/zbm` in the container is not pre-populated,
@@ -136,56 +111,133 @@ options. The options are:
136111

137112
The environment variable or default can be overridded with the `-t` option.
138113

139-
An additional command-line argument, `-e`, allows the ZFSBootMenu configuration
140-
to be modified with `yq-go eval` statements at container run time. Do not use
141-
this unless you review the build script and understand, without documentation,
142-
what will happen!
114+
A couple of additional arguments may only be set from the command line:
115+
116+
- `-e <statement>` provides a statement that will be evaluated via `yq-go eval`
117+
to modify the `generate-zbm` configuration file immediately before an image
118+
is built. This option may be specified more than once.
119+
120+
> Do not use this unless you review the build script and understand, without
121+
> documentation, what will happen!
122+
123+
- `-p <package>` specifies a Void Linux package to install in the container
124+
before images are generated. This option may be specified more than once.
125+
126+
## ZFSBootMenu Configuration and Execution
127+
128+
After the ZFSBootMenu container entrypoint fetches (or identifies) a copy of
129+
the ZFSBootMenu source repository, it "installs" the copy into the container by
130+
symlinking key components of the source repository into the container
131+
filesystem:
132+
133+
- If the source repository is sufficiently new, a symbolic link
134+
135+
/usr/share/zfsbootmenu -> /zbm/zfsbootmenu
136+
137+
will point to the core ZFSBootMenu library.
138+
139+
- For newer versions of ZFSBootMenu, the symbolic link
140+
141+
/usr/lib/dracut/modules.d/90zfsbootmenu -> /zbm/dracut
142+
143+
will point to the dracut module; for older versions, the link
144+
145+
/usr/lib/dracut/modules.d/90zfsbootmenu -> /zbm/90zfsbootmenu
146+
147+
will serve the same purpose.
148+
149+
- If the ZFSBootMenu repository contains a mkinitcpio module, a family of links
150+
151+
/usr/lib/initcpio/hooks/* -> /zbm/initcpio/hooks/*
152+
/usr/lib/initcpio/install/* -> /zbm/initcpio/install/*
153+
154+
for each file in `/zbm/initcpio/{hooks,install}` will be made to make
155+
`mkinitcpio` aware of the ZFSBootMenu module.
156+
157+
Configuration files are handled in a multi-pass approach that synthesizes a
158+
composite configuration from increasingly specific sources. In the first pass,
159+
generic upstream configurations are linked *if the source exists*:
160+
161+
/etc/zfsbootmenu/config.yaml -> /zbm/etc/zfsbootmenu/config.yaml
162+
/etc/zfsbootmenu/mkinitcpio.conf -> /zbm/etc/zfsbootmenu/mkinitcpio.conf
163+
/etc/zfsbootmenu/dracut.conf.d/* -> /zbm/etc/zfsbootmenu/dracut.conf.d/*
164+
/etc/zfsbootmenu/mkinitcpio.conf.d/* -> /zbm/etc/zfsbootmenu/mkinitcpio.conf.d/*
165+
166+
Next, container-specific defaults are linked *if the source exists*:
167+
168+
/etc/zfsbootmenu/config.yaml -> /zbm/etc/zbm-builder/config.yaml
169+
/etc/zfsbootmenu/mkinitcpio.conf -> /zbm/etc/zbm-builder/mkinitcpio.conf
170+
/etc/zfsbootmenu/dracut.conf.d/* -> /zbm/etc/zbm-builder/dracut.conf.d/*
171+
/etc/zfsbootmenu/mkinitcpio.conf.d/* -> /zbm/etc/zbm-builder/mkinitcpio.conf.d/*
172+
173+
Finally, build-specific configurations are linked *if the source exists*:
174+
175+
/etc/zfsbootmenu/config.yaml -> ${BUILDROOT}/config.yaml
176+
/etc/zfsbootmenu/mkinitcpio.conf -> ${BUILDROOT}/mkinitcpio.conf
177+
/etc/zfsbootmenu/dracut.conf.d/* -> ${BUILDROOT}/dracut.conf.d/*
178+
/etc/zfsbootmenu/mkinitcpio.conf.d/* -> ${BUILDROOT}/mkinitcpio.conf.d/*
179+
180+
Conflicting links will *replace* any links made by earlier passes. This allows
181+
each level of configurations to mask or augment earlier defaults.
182+
183+
> NOTE: `mkinitcpio` does not natively support configuration snippets in
184+
> `/etc/zfsbootmenu/mkinitcpio.conf.d`. ZFSBootMenu includes a default
185+
> `mkinitcpio.conf` that manually sources these snippets to emulate the
186+
> standard configuration behavior of dracut.
187+
188+
In addition, host-specific files are linked if each exists:
189+
190+
/etc/hostid -> ${BUILDROOT}/hostid
191+
/etc/zfs/zpool.cache -> ${BUILDROOT}/zfs/zpool.cache
192+
193+
When launched, the container entrypoint will run any executable files it finds
194+
in `${BUILDROOT}/rc.d`. This provides a means to "terraform" the build
195+
container before running `generate-zbm` and can be a useful way to, *e.g.*:
196+
197+
- Modify the `FONT` variable defined in `/etc/rc.conf`, which will be parsed by
198+
`mkinitcpio` to set a default console font in ZFSBootMenu images.
199+
200+
- Create additional links to directories in `$BUILDROOT`, such as
201+
202+
/etc/initcpio -> ${BUILDROOT}/initcpio
203+
204+
to provide additional `mkinitcpio` modules or
205+
206+
/etc/dropbear -> ${BUILDROOT}/dropbear
207+
208+
to provide host keys and configuration for the `dropbear` `mkinitcpio`
209+
module.
143210

144211
## Build Examples
145212

146213
To use the previously created `zbm` image to produce ZFSBootMenu files from the
147-
default configuration using a local ZFSBootMenu repository `/sw/zfsbootmenu`,
148-
simply run
214+
default configuration, simply run
149215

150216
```sh
151-
podman run -v /sw/zfsbootmenu:/zbm zbm
217+
podman run -v .:/build zbm
152218
```
153219

154220
After some console output, the container should terminate and the directory
155-
`/sw/zfsbootmenu/releng/docker/build` should contain the UEFI bundle
156-
`vmlinuz.EFI` as well as the components `vmlinuz-bootmenu` (a stock Void Linux
157-
kernel) and corresponding ZFSBootMenu initramfs `initramfs-bootmenu.img`.
158-
159-
In the default configuration, the ZFSBootMenu images probably contain an
160-
arbitrary `/etc/hostid` that likely does not agree with the corresponding file
161-
on the host. To make sure that the hostid within the images remains consistent
162-
with the build host, first copy the file from the host to the `releng/docker`
163-
directory:
164-
165-
```sh
166-
cp /etc/hostid /sw/zfsbootmenu/releng/docker/hostid
167-
podman run -v /sw/zfsbootmenu:/zbm zbm
168-
```
221+
`./build` should contain the UEFI bundle `vmlinuz.EFI` as well as the
222+
components `vmlinuz-bootmenu` (a stock Void Linux kernel) and corresponding
223+
ZFSBootMenu initramfs `initramfs-bootmenu.img`.
169224

170-
To create an image from the current `master` branch without having a local
171-
repository, store the output images in `/boot/efi/EFI/zfsbootmenu` and include
172-
the hostid of the current system, assuming a `zbm` builder container is tagged
173-
locally:
225+
To provide the hostid and pool cache files to the build container and run from
226+
the `/etc/zfsbootmenu/build` directory, copy the desired files and run the
227+
container with the appropriate volume mount:
174228

175229
```sh
176-
mkdir -p /boot/efi/EFI/zfsbootmenu
177-
podman run -v /boot/efi/EFI/zfsbootmenu:/output \
178-
-v /etc/hostid:/hostid:ro zbm -o /output -H /hostid
230+
cp /etc/hostid /etc/zfs/zpool.cache /etc/zfsbootmenu/build
231+
podman run -v /etc/zfsbootmenu/build:/build zbm
179232
```
180233

181-
# Using Docker Compose
182-
183-
The file `docker-compose.yml` defines a Docker Compose service that will create
184-
a ZFSBootMenu builder image and mount the parent repository (at path `../..`)
185-
at `/zbm` in the build container. To use this service, simply run
234+
To create an image from a local repository available at `/sw/zfsbootmenu` and
235+
again use a build root of `/etc/zfsbootmenu/build`, run
186236

187237
```sh
188-
docker-compose up
238+
podman run -v /etc/zfsbootmenu/build:/build -v /sw/zfsbootmenu:/zbm:ro zbm
189239
```
190240

191-
from this directory.
241+
Because the build container does not modify the repository found in `/zbm`, it
242+
is possible to mount that volume read-only (as indicated by the `:ro` suffix)
243+
without consequence.

0 commit comments

Comments
 (0)