Skip to content

Instantly share code, notes, and snippets.

@dm0-
Last active September 28, 2023 10:03
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save dm0-/0db058ba3a85d55aca99c93a642b8a20 to your computer and use it in GitHub Desktop.
Save dm0-/0db058ba3a85d55aca99c93a642b8a20 to your computer and use it in GitHub Desktop.
Automatically update custom kernel modules on CoreOS
{
"ignition": { "version": "2.0.0" },
"systemd": {
"units": [
{
"name": "auto-update-kmods.service",
"enable": true,
"contents": "[Unit]\nDescription=Install custom kernel modules\nAfter=lib-modules.mount network-online.target\nRequires=lib-modules.mount network-online.target\nConditionPathExists=!/opt/modules/%v\nConditionPathExistsGlob=/lib/modules/auto-update-kmods.d/*.sh\n\n[Service]\nType=oneshot\nExecStart=/bin/bash -ex /lib/modules/auto-update-kmods.sh\n\n[Install]\nWantedBy=multi-user.target\n"
},
{
"name": "lib-modules.mount",
"enable": true,
"contents": "[Unit]\nDescription=Custom Kernel Modules\nBefore=local-fs.target\nConditionPathExists=/opt/modules\nConditionPathExists=/opt/modules.wd\n\n[Mount]\nType=overlay\nWhat=overlay\nWhere=/lib/modules\nOptions=lowerdir=/lib/modules,upperdir=/opt/modules,workdir=/opt/modules.wd\n\n[Install]\nWantedBy=local-fs.target\n"
}
]
},
"storage": {
"files": [
{
"filesystem": "root",
"mode": 420,
"path": "/opt/modules.wd/dummy",
"contents": { "source": "data:text/plain;base64,VGhpcyBmaWxlIHdhcyB3cml0dGVuIGp1c3QgdG8gbWFrZSBJZ25pdGlvbiBjcmVhdGUgaXRzIHBhcmVudCBkaXJlY3RvcnkuICBJdCBjYW4gYmUgZGVsZXRlZC4K" }
},
{
"filesystem": "root",
"mode": 420,
"path": "/opt/modules/auto-update-kmods.sh",
"contents": { "source": "data:text/plain;base64,IyEvYmluL2Jhc2ggLWV4Ci4gL3Vzci9zaGFyZS9jb3Jlb3MvcmVsZWFzZQoKIyBUcnkgdG8gZGV0ZXJtaW5lIHdoaWNoIGNoYW5uZWwgY29udGFpbnMgdGhpcyBDb3JlT1MgdmVyc2lvbi4KZm9yIGdyb3VwIGluIHN0YWJsZSBiZXRhIGFscGhhCmRvCiAgICAgICAgdXJsPSJodHRwOi8vJGdyb3VwLnJlbGVhc2UuY29yZS1vcy5uZXQvJENPUkVPU19SRUxFQVNFX0JPQVJELyRDT1JFT1NfUkVMRUFTRV9WRVJTSU9OL2NvcmVvc19kZXZlbG9wZXJfY29udGFpbmVyLmJpbi5iejIiCiAgICAgICAgY3VybCAtLWZhaWwgLS1oZWFkIC0tbG9jYXRpb24gLS1zaWxlbnQgIiR1cmwiID4vZGV2L251bGwgJiYgYnJlYWsKZG9uZQoKIyBEb3dubG9hZCwgZGVjb21wcmVzcywgYW5kIHZlcmlmeSB0aGUgZGV2ZWxvcGVyIGNvbnRhaW5lciBpbWFnZS4KZ3BnMiAtLXJlY3Yta2V5cyAwNDEyN0QwQkZBQkVDODg3MUZGQjJDQ0U1MEUwODg1NTkzRDJEQ0I0CmN1cmwgLS1mYWlsIC0tbG9jYXRpb24gIiR1cmwiIHwKICAgIHRlZSA+KGJ6aXAyIC0tZGVjb21wcmVzcyA+IGNvcmVvc19kZXZlbG9wZXJfY29udGFpbmVyLmJpbikgfAogICAgZ3BnMiAtLXZlcmlmeSA8KGN1cmwgLS1sb2NhdGlvbiAtLXNpbGVudCAiJHVybC5zaWciKSAtCgojIFJ1biB0aGUgYnVpbGQgc2NyaXB0cyBpbiB0aGUgY29udGFpbmVyIHdpdGggdGhlIGhvc3QgbW9kdWxlcyBkaXJlY3RvcnkuCnN5c3RlbWQtbnNwYXduIFwKICAgIC0tYmluZD0vbGliL21vZHVsZXMgXAogICAgLS1pbWFnZT1jb3Jlb3NfZGV2ZWxvcGVyX2NvbnRhaW5lci5iaW4gXAogICAgL2Jpbi9iYXNoIC1leCA8PC0gJ0VPRicKCS4gL3Vzci9zaGFyZS9jb3Jlb3MvcmVsZWFzZQoJCgkjIENoZWNrIG91dCB0aGUgY3VycmVudCBDb3JlT1MgdmVyc2lvbidzIGVidWlsZHMuCgllbWVyZ2UtZ2l0Y2xvbmUKCWdpdCAtQyAvdmFyL2xpYi9wb3J0YWdlL2NvcmVvcy1vdmVybGF5IFwKCSAgICBjaGVja291dCAiYnVpbGQtJHtDT1JFT1NfUkVMRUFTRV9WRVJTSU9OJSUuKn0iIHx8CgkgICAgOiAgIyBTdGF5IG9uIG1hc3RlciBpZiB0aGlzIHZlcnNpb24gaGFzbid0IGJyYW5jaGVkIHlldC4KCQoJIyBQcmVwYXJlIHRoZSBMaW51eCBrZXJuZWwgc291cmNlIGZvciBidWlsZGluZyBleHRlcm5hbCBtb2R1bGVzLgoJZW1lcmdlIC1nS3YgY29yZW9zLXNvdXJjZXMKCWd6aXAgLWNkIC9wcm9jL2NvbmZpZy5neiA+IC91c3Ivc3JjL2xpbnV4Ly5jb25maWcKCW1ha2UgLUMgL3Vzci9zcmMvbGludXggbW9kdWxlc19wcmVwYXJlCgkKCSMgUnVuIGFueSBidWlsZCBzY3JpcHRzLgoJc2hvcHQgLXMgbnVsbGdsb2IKCWZvciBwcm9qZWN0IGluIC9saWIvbW9kdWxlcy9hdXRvLXVwZGF0ZS1rbW9kcy5kLyouc2gKCWRvCgkgICAgICAgICguICIkcHJvamVjdCIpCglkb25lCgkKCSMgVXBkYXRlIHRoZSBrZXJuZWwgbW9kdWxlIGRlcGVuZGVuY3kgZmlsZXMuCglkZXBtb2QKCUVPRgoKIyBEZWxldGUgdGhlIGRldmVsb3BlciBjb250YWluZXIgdG8gc2F2ZSBzcGFjZS4Kcm0gLS1mb3JjZSBjb3Jlb3NfZGV2ZWxvcGVyX2NvbnRhaW5lci5iaW4K" }
},
{
"filesystem": "root",
"mode": 420,
"path": "/opt/modules/auto-update-kmods.d/zfs.sh",
"contents": { "source": "data:text/plain;base64,IyBUaGlzIGlzIGFuIGV4YW1wbGUgZHJvcC1pbiBzY3JpcHQgdG8gYXV0b21hdGljYWxseSBidWlsZCBaRlMga2VybmVsIG1vZHVsZXMuCiMgSXQgc2hvdWxkIGJlIHNhdmVkIGluIGF1dG8tdXBkYXRlLWttb2RzLmQgYXMgZS5nLiB6ZnMuc2ggaW4gb3JkZXIgdG8gcnVuLgoKdmVyc2lvbj0wLjYuNS44CnNwbHVybD0iaHR0cHM6Ly9naXRodWIuY29tL3pmc29ubGludXgvemZzL3JlbGVhc2VzL2Rvd25sb2FkL3pmcy0kdmVyc2lvbi9zcGwtJHZlcnNpb24udGFyLmd6Igp6ZnN1cmw9Imh0dHBzOi8vZ2l0aHViLmNvbS96ZnNvbmxpbnV4L3pmcy9yZWxlYXNlcy9kb3dubG9hZC96ZnMtJHZlcnNpb24vemZzLSR2ZXJzaW9uLnRhci5neiIKc2lndXJsPSJodHRwczovL2dpdGh1Yi5jb20vemZzb25saW51eC96ZnMvcmVsZWFzZXMvZG93bmxvYWQvemZzLSR2ZXJzaW9uL3pmcy0kdmVyc2lvbi5zaGEyNTYuYXNjIgoKIyBEb3dubG9hZCB0aGUgU1BMIGFuZCBaRlMgc291cmNlIHRhcmJhbGxzLgpjdXJsIC0tZmFpbCAtLWxvY2F0aW9uIC0tb3V0cHV0ICJzcGwtJHZlcnNpb24udGFyLmd6IiAiJHNwbHVybCIKY3VybCAtLWZhaWwgLS1sb2NhdGlvbiAtLW91dHB1dCAiemZzLSR2ZXJzaW9uLnRhci5neiIgIiR6ZnN1cmwiCgojIFZlcmlmeSB0aGUgc2lnbmVkIFNIQS0yNTYgc3VtcyBvZiB0aGUgc291cmNlcyBiZWZvcmUgZG9pbmcgYW55dGhpbmcuCmdwZzIgLS1yZWN2LWtleXMgMjlENTYxMEVBRTI5NDFFMzU1QTJGRThBQjk3NDY3QUFDNzdCOTY2NwpjdXJsIC0tZmFpbCAtLWxvY2F0aW9uIC0tb3V0cHV0ICJ6ZnMtJHZlcnNpb24uc2hhMjU2LmFzYyIgIiRzaWd1cmwiCmdwZzIgLS12ZXJpZnkgInpmcy0kdmVyc2lvbi5zaGEyNTYuYXNjIgpzaGEyNTZzdW0gLS1jaGVjayAiemZzLSR2ZXJzaW9uLnNoYTI1Ni5hc2MiCgojIEJ1aWxkIGFuZCBpbnN0YWxsIFNQTC4KdGFyIC14ZiAic3BsLSR2ZXJzaW9uLnRhci5neiIKKGNkICJzcGwtJHZlcnNpb24iICYmIC4vY29uZmlndXJlKQptYWtlIC1DICJzcGwtJHZlcnNpb24iIC1qJChucHJvYykgYWxsCm1ha2UgLUMgInNwbC0kdmVyc2lvbiIgaW5zdGFsbAoKIyBCdWlsZCBhbmQgaW5zdGFsbCBaRlMuCnRhciAteGYgInpmcy0kdmVyc2lvbi50YXIuZ3oiCihjZCAiemZzLSR2ZXJzaW9uIiAmJiAuL2NvbmZpZ3VyZSkKbWFrZSAtQyAiemZzLSR2ZXJzaW9uIiAtaiQobnByb2MpIGFsbAptYWtlIC1DICJ6ZnMtJHZlcnNpb24iIGluc3RhbGwK" }
}
]
}
}

Automatically update custom kernel modules on CoreOS

The purpose of this document is to provide notes and example code for compiling and installing custom kernel modules on CoreOS whenever a new kernel version is detected. (That includes the first boot.) A sample Ignition configuration for automating this is attached, as well as the plain files that will be written by Ignition for readability.

Note that the writable location used by these files is /opt/modules. If this is not an acceptable path, it can be replaced globally in the Ignition file.

There are three main components to this setup.

Writable overlay

Since /lib/modules is read-only on CoreOS, a writable overlay must be mounted over it to install additional modules. A mount unit lib-modules.mount mounts the overlay as part of local-fs.target.

Developer container

Each CoreOS version includes a container of development tools for that specific release. This container is downloaded for running the scripts that perform the actual module compilation. It is started by auto-update-kmods.service, which calls auto-update-kmods.sh when no custom modules are found for the currently running kernel. Other unit dependencies should take this service into account.

Build scripts

The auto-update-kmods.sh script runs any user-provided scripts in the drop-in directory auto-update-kmods.d in lexical order. These scripts should contain the download, compile, and install commands for the desired custom modules. An example script, zfs.sh, is provided as a reference.

[Unit]
Description=Install custom kernel modules
After=lib-modules.mount network-online.target
Requires=lib-modules.mount network-online.target
ConditionPathExists=!/opt/modules/%v
ConditionPathExistsGlob=/lib/modules/auto-update-kmods.d/*.sh
[Service]
Type=oneshot
ExecStart=/bin/bash -ex /lib/modules/auto-update-kmods.sh
[Install]
WantedBy=multi-user.target
#!/bin/bash -ex
. /usr/share/coreos/release
# Try to determine which channel contains this CoreOS version.
for group in stable beta alpha
do
url="http://$group.release.core-os.net/$COREOS_RELEASE_BOARD/$COREOS_RELEASE_VERSION/coreos_developer_container.bin.bz2"
curl --fail --head --location --silent "$url" >/dev/null && break
done
# Download, decompress, and verify the developer container image.
gpg2 --recv-keys 04127D0BFABEC8871FFB2CCE50E0885593D2DCB4
curl --fail --location "$url" |
tee >(bzip2 --decompress > coreos_developer_container.bin) |
gpg2 --verify <(curl --location --silent "$url.sig") -
# Run the build scripts in the container with the host modules directory.
systemd-nspawn \
--bind=/lib/modules \
--image=coreos_developer_container.bin \
/bin/bash -ex <<- 'EOF'
. /usr/share/coreos/release
# Check out the current CoreOS version's ebuilds.
emerge-gitclone
git -C /var/lib/portage/coreos-overlay \
checkout "build-${COREOS_RELEASE_VERSION%%.*}" ||
: # Stay on master if this version hasn't branched yet.
# Prepare the Linux kernel source for building external modules.
emerge -gKv coreos-sources
gzip -cd /proc/config.gz > /usr/src/linux/.config
make -C /usr/src/linux modules_prepare
# Run any build scripts.
shopt -s nullglob
for project in /lib/modules/auto-update-kmods.d/*.sh
do
(. "$project")
done
# Update the kernel module dependency files.
depmod
EOF
# Delete the developer container to save space.
rm --force coreos_developer_container.bin
[Unit]
Description=Custom Kernel Modules
Before=local-fs.target
ConditionPathExists=/opt/modules
ConditionPathExists=/opt/modules.wd
[Mount]
Type=overlay
What=overlay
Where=/lib/modules
Options=lowerdir=/lib/modules,upperdir=/opt/modules,workdir=/opt/modules.wd
[Install]
WantedBy=local-fs.target
# This is an example drop-in script to automatically build ZFS kernel modules.
# It should be saved in auto-update-kmods.d as e.g. zfs.sh in order to run.
version=0.6.5.8
splurl="https://github.com/zfsonlinux/zfs/releases/download/zfs-$version/spl-$version.tar.gz"
zfsurl="https://github.com/zfsonlinux/zfs/releases/download/zfs-$version/zfs-$version.tar.gz"
sigurl="https://github.com/zfsonlinux/zfs/releases/download/zfs-$version/zfs-$version.sha256.asc"
# Download the SPL and ZFS source tarballs.
curl --fail --location --output "spl-$version.tar.gz" "$splurl"
curl --fail --location --output "zfs-$version.tar.gz" "$zfsurl"
# Verify the signed SHA-256 sums of the sources before doing anything.
gpg2 --recv-keys 29D5610EAE2941E355A2FE8AB97467AAC77B9667
curl --fail --location --output "zfs-$version.sha256.asc" "$sigurl"
gpg2 --verify "zfs-$version.sha256.asc"
sha256sum --check "zfs-$version.sha256.asc"
# Build and install SPL.
tar -xf "spl-$version.tar.gz"
(cd "spl-$version" && ./configure)
make -C "spl-$version" -j$(nproc) all
make -C "spl-$version" install
# Build and install ZFS.
tar -xf "zfs-$version.tar.gz"
(cd "zfs-$version" && ./configure)
make -C "zfs-$version" -j$(nproc) all
make -C "zfs-$version" install
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment