The public Image Factory at
factory.talos.dev builds images only from the official Talos Linux system extension catalog.
A custom extension is not in that catalog, so this guide builds its images with the imager container instead.
See Boot assets for the difference between the two.Extension structure
A system extension is a container image containing amanifest.yaml file at the root and a rootfs directory holding the files to install:
rootfs is laid out as it should appear on the installed machine.
The manifest.yaml file carries the extension’s metadata; Create an extension below shows a complete one.
rootfs restrictions
The contents of rootfs are restricted:
- no special files (FIFOs, devices, and so on)
- no world-writeable files or directories
/etc/cri/conf.d/usr/lib/firmware/usr/lib/modules/usr/lib/udev/rules.d/usr/local/usr/lib/ld-linux-x86-64.so.2and/usr/lib/ld-linux-aarch64.so.1, the glibc loaders/usr/bin/ldconfig,/etc/ld.so.confand/etc/ld.so.cache, also glibc/usr/share/glvnd,/usr/share/egland/etc/vulkan, for OpenGL and Vulkan/usr/bin/nvidia-modprobe,/usr/bin/nvidia-pcc,/usr/bin/nvidia-smi,/usr/bin/nvidia-ctkand/usr/bin/nvidia-cdi-hook/usr/bin/nvme
test step to pkg.yaml to check the rootfs against these rules at build time:
path "..." is not allowed in extensions for a file outside the permitted paths.
Without this step nothing checks the layout: the extension builds, and imager packages it into an image without complaint.
Kernel module signing
A kernel module has to be signed by the kernel it will run on, so an extension that ships one is built against a custom kernel. The next two sections build that kernel. Extensions that ship binaries, firmware, or configuration files do not need one, and can start at Create an extension.Create a package hello
Talos is built from the pkgs repo and the first step will be to add your custom package to that repo to be built with Talos. You can look at other packages in that repository for examples of what should be included. The only file required to create a package is apkg.yaml file in a folder.
Let’s create an example package to walk through each step.
Clone the repo and create a folder.
.kres.yaml file in the root of the repository.
We use this file for templating and generating Makefiles.
Put your out-of-tree kernel module below the comment for dependent packages.
make target to build your module and a directory to store your module configuration.
The next step is to create a pkg.yaml file to tell bldr how to create a container with the files you need.
The bldr tool has assumptions about directory structure and steps you can read about in the GitHub repo.
This example does not build a kernel module, but it can be used as a basis for your own packages.
Please also see existing pkg.yaml files in the pkgs repo
Build the package and kernel
After you’ve created apkg.yaml file you can test building your package with the make target you generated earlier.
Because Talos requires kernel modules to be signed with a signing key only available during the Talos kernel build process we need to build the kernel and package at the same time.
We also need a container registry available to store the built assets.
Follow the steps in developing Talos to create a docker builder and run a local container registry before running this command.
$KERNEL_IMAGE and $PKG_IMAGE variables.
Create an extension
System extensions are the way to add software and files to a Talos Linux root filesystem. Just like packages they are built as containers and then layered with Talos to create a bootable squashfs image. The process is very similar to creating a package. Start by cloning the extensions repo:.kres.yaml file.
manifest.yaml file for the metadata of your extension in the my-module folder.
pkg.yaml file describes how the extension is built.
An extension that ships files rather than kernel modules depends only on the base stage.
Place the file you want to install in the my-module folder, next to pkg.yaml.
The folder is mounted into the container at /pkg, so the file can be installed into /rootfs from there:
pkg.yaml which works similarly to our pkg.yaml file for our package, but this time starts from the base image we built in the first step.
vars.yaml file to store a version variable in the my-module folder.
This isn’t strictly required, but it is a convention used which will let the automated build work.
Build extension
You now have a complete extension config and can build it. This needs the Docker builder and local registry from Developing Talos.${EXTENSION_IMAGE}.
Test the extension
Now we need to create installation media to boot Talos. We will use imager to include our extension. An extension that ships no kernel modules can use the releasedimager directly, with no Talos checkout and no custom kernel:
This writes the installer image to _out/installer-amd64.tar, and you can continue from the crane push step below.
An extension that ships a kernel module needs an installer built against the kernel from the earlier steps.
Clone the Talos repo.
$BASE_INSTALLER_IMAGE.
Create an installer image from your extension and the installer-base you just created with the following command.
_out/ folder of our repository.
Load and push the container image to a registry with crane.
Make sure you replace $REGISTRY, $USER, and $TAG with the values you want.
crane:
Test the installer with fresh install
Now you can boot a machine from generic Talos installation media. This is only used to get access to the API so we can apply a configuration that will use our installer image. We’ll assume this machine has an IP address of 192.168.100.100 Generate a configuration that uses your installer image..ko file you built in the package and put in the /modules directory.
An extension without kernel modules needs no patch: apply the configuration on its own, without -p.