Skip to content

Commit 4166967

Browse files
t-osterahesford
andcommitted
Add Dockerfile and Compose service to build ZBM images
- Dockerfile creates a basic Void installation with components necessary to install ZFSBootMenu and run generate-zbm, including a script at /zbm-build.sh that runs by default and automates the build. - The compose service builds the image and then starts it by bind-mounting the containing repo (at path ../..) at /zbm in the container. Co-authored-by: Andrew J. Hesford <[email protected]>
1 parent 687295a commit 4166967

File tree

6 files changed

+225
-0
lines changed

6 files changed

+225
-0
lines changed

contrib/docker/.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
config.yaml
2+
build
3+
hostid
4+
zpool.cache

contrib/docker/Dockerfile

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# This Dockerfile creates a container that will create an EFI executable and
2+
# separate kernel/initramfs components from a ZFSBootMenu repository. The
3+
# container will pre-populate its /zbm directory with a clone of the master
4+
# branch of the upstream ZFSBootMenu branch and build the images from that.
5+
#
6+
# To use a different ZFSBootMenu repository or version, bind-mound the
7+
# repository you want on /zbm inside the container.
8+
9+
# Use the official Void Linux container
10+
FROM voidlinux/voidlinux:latest
11+
12+
# Ensure everything is up-to-date
13+
RUN xbps-install -Suy xbps && xbps-install -uy
14+
15+
# Install components necessary to build the image
16+
RUN xbps-query -Rp run_depends zfsbootmenu | xargs xbps-install -y
17+
RUN xbps-install -y linux linux-headers zfs gummiboot-efistub
18+
19+
# Copy the build script
20+
COPY zbm-build.sh /zbm-build.sh
21+
22+
# To replace the default ZFSBootMenu tree, bind-mount over /zbm
23+
VOLUME /zbm
24+
25+
# Make sure a configuration exists or copy the default, then create the images
26+
CMD /zbm-build.sh

contrib/docker/README.md

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
# Containerized Image Building
2+
3+
Files in this directory provide a means for creating a container that is
4+
capable of building ZFSBootMenu kernel and initramfs components as well as a
5+
standalone UEFI bundle. The container image is built atop Void Linux and
6+
provides the basic components necessary to build an image from an arbitrary
7+
ZFSBootMenu repository, including a build script that runs by default when the
8+
container is started.
9+
10+
These images build and run with both Docker and Podman. Podman is recommended
11+
as it provides daemon-free container management and allows containers to run as
12+
unprivileged users. Sample commands below refer to the `podman` command.
13+
However, because `podman` and `docker` have compatible command-line interfaces,
14+
the commands should work just as well by substituting `docker` for `podman`.
15+
16+
# Creating a ZFSBootMenu Builder Image
17+
18+
The provided `Dockerfile` automates creation of the ZFSBootMenu builder image.
19+
From this directory, simply run
20+
21+
```sh
22+
podman build -t zbm .
23+
```
24+
25+
to create an image named `zbm`. (Podman automatically prepends `localhost` and
26+
appends `:latest` to unqualified tags, so the full image name will be
27+
`localhost/zbm:latest`.) Any suitable tag may be substituted for `zbm`.
28+
29+
The resulting image contains all ZFSBootMenu prerequisites. Hard dependencies
30+
of ZFSBootMenu are determined by querying the Void Linux `zfsbootmenu` package,
31+
which will generally provide up-to-date information. In rare cases, a build
32+
from the master branch may introduce new requirements that are not reflected in
33+
the latest release version packaged for Void; manually editing the `Dockerfile`
34+
to add new dependencies may be necessary until a new release is packaged.
35+
36+
The builder image does **not** contain a ZFSBootMenu installation or a copy of
37+
the upstream git repository. Instead, the image contains a build script,
38+
installed as `/zbm-build.sh`, that runs by default. The script ensures that a
39+
ZFSBootMenu repository is available in a running container and invokes
40+
`generate-zbm` to build images.
41+
42+
# Running a ZFSBootMenu Builder Container
43+
44+
When running a container from the ZFSBootMenu builder image, it is generally
45+
expected that some compatible volume (generally, a local directory) will be
46+
bind-mounted as a volume at the path `/zbm` inside the container. This volume
47+
may either be empty or contain a pre-existing ZFSBootMenu source tree.
48+
Specifically, if the volume is not empty, it must contain the following
49+
components of the ZFSBootMenu repository:
50+
51+
- `90zfsbootmenu`, the Dracut module encapsulating ZFSBootMenu functionality;
52+
- `bin/generate-zbm`, the executable script that creates ZFSBootMenu images;
53+
- `contrib/docker`, providing either `config.yaml` or `config.yaml.default`.
54+
55+
If the build script finds the volume mounted at `/zbm` empty, it will install
56+
the `git` package and clone the master branch of the upstream ZFSBootMenu
57+
repository. This makes the image capable of producing default images without
58+
needing a local clone of the repository. To build anything but the head commit
59+
of the upstream master branch, clone the repository, checkout an aribtrary
60+
commit or make local changes, and mount that repository at `/zbm`.
61+
62+
## Contents of `contrib/docker`
63+
64+
The build script expects to find a valid ZFSBootMenu configuration file at
65+
`/zbm/contrib/docker/config.yaml` within the container. If this file does not
66+
exist, the file `/zbm/contrib/docker/config.yaml.default` will be copied to the
67+
expected location. At least one of these files must exist or the build script
68+
will fail. The default configuration will store images in the directory
69+
`contrib/docker/build`, which will be created by `generate-zbm` if it does not
70+
already exist.
71+
72+
Builder containers do not have access to local files `/etc/zfs/zpool.cache` or
73+
`/etc/hostid`. If one or both of these components are desired in the output
74+
image (for example, to ensure consistency with the build host), copy the
75+
desired files to `contrib/docker/zpool.cache` or `contrib/docker/hostid`,
76+
respectively. If the build script finds these files, it will copy them into the
77+
container where the ZFSBootMenu Dracut module expects to find them. If one of
78+
these files is missing, any corresponding file already installed in the
79+
container will be *removed*.
80+
81+
## Build Examples
82+
83+
To use the previously created `zbm` image to produce ZFSBootMenu files from the
84+
default configuration using a local ZFSBootMenu repository `/sw/zfsbootmenu`,
85+
simply run
86+
87+
```sh
88+
podman run -v /sw/zfsbootmenu:/zbm /zbm
89+
```
90+
91+
After some console output, the container should terminate and the directory
92+
`/sw/zfsbootmenu/contrib/docker/build` should contain the UEFI bundle
93+
`vmlinuz.EFI` as well as the components `vmlinuz-bootmenu` (a stock Void Linux
94+
kernel) and corresponding ZFSBootMenu initramfs `initramfs-bootmenu.img`.
95+
96+
In the default configuration, the ZFSBootMenu images probably contain an
97+
arbitrary `/etc/hostid` that likely does not agree with the corresponding file
98+
on the host. To make sure that the hostid within the images remains consistent
99+
with the build host, first copy the file from the host to the `contrib/docker`
100+
directory:
101+
102+
```sh
103+
cp /etc/hostid /sw/zfsbootmenu/contrib/docker/hostid
104+
podman run -v /sw/zfsbootmenu:/zbm /zbm
105+
```
106+
107+
# Using Docker Compose
108+
109+
The file `docker-compose.yml` defines a Docker Compose service that will create
110+
a ZFSBootMenu builder image and mount the parent repository (at path `../..`)
111+
at `/zbm` in the build container. To use this service, simply run
112+
113+
```sh
114+
docker-compose up
115+
```
116+
117+
from this directory.

contrib/docker/config.yaml.default

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Global:
2+
# Enable image creation
3+
ManageImages: true
4+
# Make sure to look for dracut configuration in the repo
5+
DracutConfDir: /zbm/etc/zfsbootmenu/dracut.conf.d
6+
Components:
7+
# Dump kernel/initramfs components in the tree;
8+
# generate-zbm creates this directory if necessary
9+
ImageDir: /zbm/contrib/docker/build
10+
Enabled: true
11+
# Disable versioning, this is usually a one-off creation
12+
Versions: false
13+
syslinux:
14+
Enabled: false
15+
EFI:
16+
ImageDir: /zbm/contrib/docker/build
17+
Versions: false
18+
Enabled: true
19+
Kernel:
20+
# For the EFI bundle, turn off modesetting to avoid initializing GPUs
21+
# Also set loglevel=4 to provide some helpful warning output
22+
CommandLine: zfsbootmenu ro loglevel=4 nomodeset

contrib/docker/docker-compose.yml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# This builds the ZFSBootMenu builder and then runs it to create images
2+
version: "2"
3+
services:
4+
zfsbootmenu-compiler:
5+
build: "."
6+
# Mount the current repo (../..) where the builder expects it
7+
# Outputs will be stored in ../../contrib/docker/build
8+
volumes:
9+
- "../..:/zbm"

contrib/docker/zbm-build.sh

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
#!/bin/sh
2+
3+
error() {
4+
echo ERROR: "$@"
5+
exit 1
6+
}
7+
8+
# shellcheck disable=SC2010
9+
if ls -Aq /zbm | grep -q . >/dev/null 2>&1; then
10+
# If /zbm is not empty, make sure it looks like it has what we need
11+
[ -d /zbm/90zfsbootmenu ] || error "missing path /zbm/90zfsbootmenu"
12+
[ -d /zbm/contrib/docker ] || error "missing path /zbm/contrib/docker"
13+
[ -x /zbm/bin/generate-zbm ] || error "missing executable /zbm/bin/generate-zbm"
14+
else
15+
# If /zbm is empty, clone the upstream repo into it
16+
xbps-install -Sy git
17+
git clone --depth=1 https://github.com/zbm-dev/zfsbootmenu /zbm
18+
fi
19+
20+
# Make sure that dracut can find the ZFSBootMenu module
21+
ln -sf /zbm/90zfsbootmenu /usr/lib/dracut/modules.d/90zfsbootmenu
22+
23+
BUILDROOT="/zbm/contrib/docker"
24+
25+
if [ ! -e "${BUILDROOT}/config.yaml" ]; then
26+
# If there is no provided config, copy the default
27+
cp "${BUILDROOT}/config.yaml.default" "${BUILDROOT}/config.yaml"
28+
fi
29+
30+
if [ -r "${BUILDROOT}/hostid" ]; then
31+
# If a hostid is provided in the build root, use it
32+
cp "${BUILDROOT}/hostid" /etc/hostid
33+
else
34+
# Otherwise, make sure there is no hostid file
35+
rm -f /etc/hostid
36+
fi
37+
38+
if [ -r "${BUILDROOT}/zpool.cache" ]; then
39+
# If a zpool cache is provided, use it
40+
mkdir -p /etc/zfs
41+
cp "${BUILDROOT}/zpool.cache" /etc/zfs/zpool.cache
42+
else
43+
# Otherwise, make sure there is no cache file
44+
rm -f /etc/zfs/zpool.cache
45+
fi
46+
47+
exec /zbm/bin/generate-zbm --config "${BUILDROOT}/config.yaml"

0 commit comments

Comments
 (0)