linuxkit/docs/kernels.md
Avi Deitcher 18e7eea86f
riscv64 kernel (#4106)
* add riscv64 kernels to kernel/Makefile and kernel/Dockerfile.*, riscv64 kernel config, bump alpine version for kernel builds

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* update bcc to v0.32.0 to include needed fixes

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* bump kernel builder alpine base to version including llvm19

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* in kernel-bcc, automatically determine python path

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* in kernel-perf, suppress newer gcc errors

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* riscv path in kernel build was incorrect

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* remove bcc compilation from kernel

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* update usages of kernel/6.6.13 to kernel/6.6.71

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* next run of updating kernel config

Signed-off-by: Avi Deitcher <avi@deitcher.net>

* update test dependencies on kernel hash version

Signed-off-by: Avi Deitcher <avi@deitcher.net>

---------

Signed-off-by: Avi Deitcher <avi@deitcher.net>
2025-02-21 11:10:35 +02:00

654 lines
26 KiB
Markdown

# Linux kernels
LinuxKit kernel images are distributed as hub images which contain the
kernel, kernel modules, kernel config file, and optionally, kernel
headers to compile kernel modules against. The repository containing
the official LinuxKit kernels is at
[linuxkit/kernels](https://hub.docker.com/r/linuxkit/kernel/).
The LinuxKit kernels are based on the latest stable releases and are
updated frequently to include bug and security fixes. For some
kernels we do carry additional patches, which are mostly back-ported
fixes from newer kernels. The full kernel source with patches can be
found on [github](https://github.com/linuxkit/linux).
## Kernel Image Naming and Tags
We publish the following kernel images:
* primary kernel
* debug kernel
* tools for the specific kernel build - bcc and perf
* builder image for the specific kernel build, useful for compiling compatible kernel modules
### Primary Kernel Images
Each kernel image is tagged with:
* the full kernel version, e.g. `linuxkit/kernel:6.6.13`. This is a multi-arch index, and should be used whenever possible.
* the full kernel version plus hash of the files it was created from (git tree hash of the `./kernel` directory), e.g. `6.6.13-c0d96951e9892a7447a8e7965d2d6bd7e621c3fd`. This is a multi-arch index.
* the full kernel version plus architecture, e.g. `linuxkit/kernel:6.6.13-amd64` or `linuxkit/kernel:6.6.13-arm64`. Each of these is architecture specific.
* the full kernel version plus hash of the files it was created from (git tree hash of the `./kernel` directory) plus architecture, e.g. `6.6.13-c0d96951e9892a7447a8e7965d2d6bd7e621c3fd-arm64`.
### Debug Kernel Images
With each kernel image, we also publish kernels with additional debugging enabled.
These have the same image name and the same tags as the primary kernel, with the `-dbg`
suffix added immediately after the version. E.g.
* `linuxkit/kernel:6.6.13-dbg`
* `linuxkit/kernel:6.6.13-dbg-c0d96951e9892a7447a8e7965d2d6bd7e621c3fd`
* `linuxkit/kernel:6.6.13-dbg-amd64`
* `linuxkit/kernel:6.6.13-dbg-c0d96951e9892a7447a8e7965d2d6bd7e621c3fd-amd64`
### Tools
With each kernel image, we also publish images with various tools. As of this writing,
those tools are `perf` and `bcc`.
The tools images are named `linuxkit/kernel-<tool>`, followed by the same tags as the
primary kernel. For example:
* `linuxkit/kernel-perf:6.6.13`
* `linuxkit/kernel-perf:6.6.13-c0d96951e9892a7447a8e7965d2d6bd7e621c3fd`
* `linuxkit/kernel-perf:6.6.13-amd64`
* `linuxkit/kernel-perf:6.6.13-c0d96951e9892a7447a8e7965d2d6bd7e621c3fd-amd64`
## Additional Contributions
In addition to the official images, there are also some
[scripts](../contrib/foreign-kernels) which repackage kernels packages
from some Linux distributions into LinuxKit kernel packages. These are
mostly provided for testing purposes.
Note now linuxkit also embraces Preempt-RT Linux kernel to support more
use cases for the promising IoT scenarios. All -rt patches are grabbed from
https://www.kernel.org/pub/linux/kernel/projects/rt/. But so far we just
enable it over 4.14.x.
## Loading kernel modules
Most kernel modules are autoloaded with `mdev` but if you need to `modprobe` a module manually you can use the `modprobe` package in the `onboot` section like this:
```
- name: modprobe
image: linuxkit/modprobe:<hash>
command: ["modprobe", "-a", "iscsi_tcp", "dm_multipath"]
```
## Compiling external kernel modules
This section describes how to build external (out-of-tree) kernel
modules. You need the following to build external modules. All of
these are to be built for a specific version of the kernel. For
the examples, we will assume 5.10.104; replace with your desired
version.
* source available to your modules - you need to get those on your own
* kernel development headers - available in the `linuxkit/kernel` image as `kernel-dev.tar`, e.g. `linuxkit/kernel:5.10.104`
* OS with sources and compiler - this **must** be the exact same version as that used to compile the kernel
As described above, the `linuxkit/kernel` images include `kernel-dev.tar` which contains
the headers and other files required to compile kernel modules against
the specific version of the kernel. Currently, the headers are not
included in the initial RAM disk, but it is possible to compile custom
modules offline and then include the modules in the initial RAM disk.
The source is available as the same name as the `linuxkit/kernel` image, with the addition of `-builder` on the tag.
For example:
* `linuxkit/kernel:5.10.92` has builder `linuxkit/kernel:5.10.92-builder`
* `linuxkit/kernel:5.15.15` has builder `linuxkit/kernel:5.15.15-builder`
With the above in hand, you can create a multi-stage `Dockerfile` build to compile your modules.
There is an [example](../test/cases/020_kernel/113_kmod_5.10.x), but
basically one can use a multi-stage build to compile the kernel
modules:
```dockerfile
FROM linuxkit/kernel:5.10.104 AS ksrc
FROM linuxkit/kernel:5.10.104-builder AS build
RUN apk add build-base
COPY --from=ksrc /kernel-dev.tar /
RUN tar xf kernel-dev.tar
# copy module source code and compile
```
To use the kernel module, we recommend adding a final stage to the
Dockerfile above, which copies the kernel module from the `build`
stage and performs a `insmod` as the entry point. You can add this
package to the `onboot` section in your YAML
file. [test.yml](../test/cases/020_kernel/113_kmod_5.10.x/test.yml)
contains an example for the configuration.
### Builder Backups
As described above, the OS builder is referenced via `<kernel-image>-builder`, e.g.
`linuxkit/kernel:5.15.15-builder`.
As a fallback, in case the `-builder` image is not available or you cannot access it from your development environment,
you have 3 total places to determine the correct version of the OS image with sources and compiler:
* `-builder` tag added to the kernel version, e.g. `linuxkit/kernel:5.10.104-builder`
* labels on the kernel image, e.g. `docker inspect linuxkit/kernel:5.10.104 | jq -r '.[].Config.Labels["org.mobyproject.linuxkit.kernel.buildimage"]'`
* `/kernel-builder` file in the kernel image
You **should** use `-builder` tag as the `AS build` in your `Dockerfile`, but you **can** use
the direct source, extracted from the labels or `/kernel-builder` file in the kernel image, in the `AS build`.
For example, in the case of `5.10.104`, the label and `/kernel-builder` file show `linuxkit/alpine:2be490394653b7967c250e86fd42cef88de428ba`,
so you can use either `linuxkit/alpine:2be490394653b7967c250e86fd42cef88de428ba` or
`linuxkit/kernel:5.10.104-builder` to build the modules.
Thus, the following are equivalent:
```dockerfile
FROM linuxkit/kernel:5.10.104 AS ksrc
FROM linuxkit/kernel:5.10.104-builder AS build
```
```dockerfile
FROM linuxkit/kernel:5.10.104 AS ksrc
FROM linuxkit/alpine:2be490394653b7967c250e86fd42cef88de428ba AS build
```
## Building and Modifying
This section describes how to build kernels, and how to modify existing ones.
Throughout the document, the terms used are:
* kernel version: actual semver version of a kernel, e.g. `6.6.13` or `5.15.27`
* kernel series: major.minor version of a kernel, e.g. `6.6.x` or `5.15.x`
Throughout this document, the architecture used is the kernel-recognized one, available
on most systems as `uname -m`, e.g. `aarch64` or `x86_64`. You may be familiar with the alpine
or golang one, e.g. `amd64` or `amd64`, which are not used here.
**Note:** After changing _and committing any changes_ to the kernel directory or any
subdirectories, you must update tests, examples and other dependencies. This is done
via:
```bash
make update-kernel-yamls
```
Each series of kernels has a dedicated directory in [../kernel/](../kernel),
e.g. [6.6.x](../kernel/6.6.x) or [5.15.x](../kernel/5.15.x).
Variants, like rt kernels, have their own directory as well, e.g. [5.11.x-rt](../kernel/5.11.x-rt).
However, for variants, the patches from _both_ the common kernel, e.g. [5.11.x](../kernel/5.11.x),
and the variant, e.g. [5.11.x-rt](../kernel/5.11.x-rt), are applied, and the configs from _both_ are combined.
Within the series-dedicated directory, there are:
* kernel config file for each architecture named `config-<arch>`, e.g. [6.6.13/config-x86_64](../kernel/6.6.13/config-x86_64), one per target architecture.
* optional patches directory, e.g. [6.6.13/patches](../kernel/6.6.13/patches), which contains patches to apply to the kernel source
The config file and patches are applied during the kernel build process.
**Note**: We try to keep the differences between kernel versions and
architectures to a minimum, so if you make changes to one
configuration also try to apply it to the others. The script [kconfig-split.py](../scripts/kconfig-split.py) can be used to compare kernel config files. For example:
```sh
../scripts/kconfig-split.py 5.15.x/config-aarch64 5.15.x/config-x86_64
```
creates a file with the common and the x86_64 and arm64 specific
config options for the 5.15.x kernel series.
**Note**: The CI pipeline does *not* push out kernel images.
Anyone modifying a kernel should:
1. Follow the steps below for the desired changes and commit them.
1. Run appropriate `make build` or variants to ensure that it works.
1. Open a PR with the changes. This may fail, as the CI pipeline may not have access to the modified kernels.
1. A maintainer should run `make push` to push out the images.
1. Run (or rerun) the tests.
#### Build options
The targets and variants for building are as follows:
* `make build` - make all kernels in the version list and their variants
* `make build-<version>` - make all variants of a specific kernel version
* `make buildkernel-<version>` - make all variants of a specific kernel version
* `make buildplainkernel-<version>` - make just the provided version's kernel
* `make builddebugkernel-<version>` - make just the provided version's debug kernel
* `make buildtools-<version>` - make just the provided version's tools
To push:
* `make push` - push all kernels in the version list and their variants
* `make push-<version>` - push all variants of a specific kernel version
Finally, for convenience:
* `make list` - list all kernels in the version list
By default, it builds for all supported architectures. To build just for a specific
architecture:
```sh
make build ARCH=amd64
```
The variable `ARCH` should use the golang variants only, i.e. `amd64` and `arm64`.
To build for multiple architectures, call it multiple times:
```sh
make build ARCH=amd64
make build ARCH=arm64
```
When building for a specific architecture, the build process will use your local
Docker, passing it `--platforms` for the architecture. If you have a builder on a different
architecture, e.g. you are running on an Apple Silicon Mac (arm64) and want to build for
`x86_64` without emulating (which can be very slow), you can use the `BUILDER` variable:
```sh
make build ARCH=x86_64 BUILDER=remote-amd64-builder
```
Builder also supports a builder pattern. If `BUILDER` contains the string `{{.Arch}}`,
it will be replaced with the architecture being built.
For example:
```sh
make build ARCH=x86_64 BUILDER=remote-{{.Arch}}-builder
make build ARCH=aarch64 BUILDER=remote-{{.Arch}}-builder
```
will build `x86_64` on `remote-amd64-builder` and `aarch64` on `remote-arm64-builder`.
Finally, if no `BUILDER` is specified, the build will look for a builder named
`linuxkit-linux-{{.Arch}}-builder`, e.g. `linuxkit-linux-amd64-builder` or
`linuxkit-linux-arm64-builder`. If that builder does not exist, it will fall back to
your local Docker setup.
### Modifying the kernel config
The process of modifying the kernel configuration is as follows:
1. Create a `linuxkit/kconfig` container image: `make kconfig`. This is not pushed out. By default, this will be for your local architecture, but you can override it with `make kconfig ARCH=${ARCH}`, e.g. `make kconfig ARCH=arm64`. The image is tagged with the architecture, e.g. `linuxkit/kconfig:arm64`.
1. Run a container based on `linuxkit/kconfig`.
1. In the container, modify the config to suit your needs using normal kernel tools like `make defconfig` or `make menuconfig`.
1. Save the config from the image.
The `linuxkit/kconfig` image contains the patched sources
for all support kernels and architectures in `/linux-<major>.<minor>.<rev>`.
The kernel source also has the kernel config copied to the default kernel config location,
so that `make menuconfig` and `make defconfig` work correctly.
Run the container as follows:
```sh
docker run --rm -ti -v $(pwd):/src linuxkit/kconfig:aarch64
# or
docker run --rm -ti -v $(pwd):/src linuxkit/kconfig:x86_64
# or
docker run --rm -ti -v $(pwd):/src linuxkit/kconfig:riscv64
```
This will give you a interactive shell where you can modify the kernel
configuration you want, while mounting the directory, so that you can save the
modified config.
To create or modify the config, you must cd to the correct directory,
e.g.
```sh
cd /linux-6.6.13
# or
cd /linux-5.15.27
```
Now you can build the config.
When `make defconfig` or `make menuconfig` is done,
the modified config file will be in `.config`; save the file back to `/src`,
e.g.
```sh
cp .config /src/6.6.x/config-x86_64
```
You can also configure other architectures other than the native
one. For example to configure the arm64 kernel on x86_64, use:
```sh
make ARCH=arm64 defconfig
make ARCH=arm64 oldconfig # or menuconfig
```
It is important to note that sometimes the configuration can be subtly different
when running `make defconfig` across architectures. Of note is that `make ARCH=riscv` on
x86_64 or aarch64 comes out slightly differently than when run natively on riscv64.
Feel free to try it cross, but do not be surprised if it generates outputs that are not the same.
Note that the generated file **must** be final. When you actually build the kernel,
it will check that running `make defconfig` will have no changes. If there are changes,
the build will fail.
The easiest way to check it is to rerun `make defconfig` inside the kconfig container.
1. Finish your creation of the config file, as above.
1. Copy the `.config` file to the target location, as above.
1. Copy the `.config` file to the source location for defconfig, e.g. `cp .config arch/x86/configs/x86_64_config` or `cp. config /linux/arch/arm64/configs/defconfig`
1. Run `make defconfig` again, and check that there are no changes, e.g. `diff .config arch/x86/configs/x86_64_config` or `diff .config /linux/arch/arm64/configs/defconfig`
If there are no differences, then you can commit the new config file.
Finally, test that you can build the kernel with that config as `make build-<version>`, e.g. `make build-5.15.148`.
## Adding a new kernel version
If you want to add a new kernel version within an existing series, e.g. `5.15.27` already exists
and you want to add (or replace it with) `5.15.148`, apply the following process.
1. Determine the series, i.e. the kernel major.minor version, followed by `x`. E.g. for `5.15.148`, the series is `5.15.x`.
1. Modify the `KERNEL_VERSION` in the `build-args` file in the series directory to the new version. E.g. `5.15.x/build-args`.
1. Create a new `linuxkit/kconfig` container image: `make kconfig`. This is not pushed out.
1. Run a container based on `linuxkit/kconfig`.
```sh
docker run --rm -ti -v $(pwd):/src linuxkit/kconfig
```
1. In the container, change directory to the kernel source directory for the new version, e.g. `cd /linux-5.15.148`.
1. Run `make defconfig` to create the default config file.
1. If the config file has changed, copy it out of the container and check it in, e.g. `cp .config /src/5.15.x/config-x86_64`.
1. Repeat for other architectures.
1. Commit the changed config files.
1. Test that you can build the kernel with that config as `make build-<version>`, e.g. `make build-5.15.148`.
## Adding a new kernel series
To add a new kernel series, you need to:
1. Create new directory for the series, e.g. `6.7.x`
1. Create config files for each architecture in that directory
1. Optionally, create a `patches/` subdirectory in that directory with any patches to add
1. Create a `build-args` file in that directory with at least the following settings:
```bash
KERNEL_VERSION=<version>
KERNEL_SERIES=<series>
BUILD_IMAGE=linuxkit/alpine:<builder>
```
Since the last major series likely is the best basis for the new one, subject to additional modifications, you can use
the previous one as a starting point.
1. Make the directory for the new series, e.g. `mkdir 7.0.x`
1. Create a new `linuxkit/kconfig` container image: `make kconfig`. This is not pushed out.
1. Run a container based on `linuxkit/kconfig`.
```sh
docker run --rm -ti -v $(pwd):/src linuxkit/kconfig
```
1. In the container, change directory to the kernel source directory for the new version, e.g. `cd /linux-7.0.5`.
1. Copy the existing config file for the previous series, e.g. `cp /src/6.6.x/config-x86_64 .config`.
1. Run `make oldconfig` to create the config file for the new series from the old one. Answer any questions.
1. Save the newly generated config file `.config` to the source directory, e.g. `cp .config /src/7.0.x/config-x86_64`.
1. Repeat for other architectures.
1. Commit the new config files.
1. Test that you can build the kernel with that config as `make build-<version>`, e.g. `make build-7.0.5`.
In addition, there are tests that are applied to a specific kernel version, notably the tests in
[020_kernel](../test/cases/020_kernel/). You will need to add a new test case for the new series,
copying an existing one and modifying it as needed.
## Building and using custom kernels
To build and test locally modified kernels, e.g., to try a different
kernel config or new patches, the existing kernel build system in
the [`kernel`](../kernel/) directory can be re-used. For example,
assuming the current 4.9 kernel is 4.9.33, you can build a local
kernel with:
```sh
make build_4.9.x
```
This will create a local kernel image called
`linuxkit/kernel:4.9.33-<hash>-dirty` assuming you haven't committed
you local changes. You can then use this in your YAML file as:
```
kernel:
image: linuxkit/kernel:4.9.33-<hash>-dirty
```
If you have committed your local changes, the `-dirty` will not be
appended. Then you can also override the Hub organisation to use the
image elsewhere with (and also disable image signing):
```sh
make ORG=<your hub org>
```
The image will be uploaded to Hub and can be use in a YAML file as
`<your hub org>/kernel:4.9.33` or as `<your hub
org>/kernel:4.9.33-<hash>`.
The kernel build system has some provision to allow local
customisation to the build.
If you want to override/add some kernel config options, you can add a
file called `config-4.9.x-x86_64-foo` and then invoke the build with `make
EXTRA=-foo build_4.9.x-foo` and this will build an image with the
additional kernel config options enabled.
If you want additional patches being applied, just copy them to the
`patches-4.X.x` and the build process will pick them up.
## Working with Linux kernel patches for LinuxKit
We may apply patches to the Linux kernel used in LinuxKit, primarily to
cherry-pick some upstream patches or to add some additional
functionality, not yet accepted upstream.
Patches are located in `kernel/patches-<kernel version>` and should follow these rules:
- Patches *must* be in `git am` format, i.e. they should contain a
complete and sensible commit message.
- Patches *must* contain a Developer's Certificate of Origin.
- Patch files *must* have a numeric prefix to ensure the ordering in
which they are applied.
- If patches are cherry-picked, they *must* be cherry-picked with `-x`
to contain the original commit ID.
- If patches are from a different git tree (other than the stable
tree), or from a mailing list posting they should contain an
`Origin:` line with a link to the source.
This document outlines the recommended procedure to handle
patches. The general process is to apply them to a branch of the
[Linux stable tree](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/)
and then export them with `git format-patch`.
If you want to add or remove patches currently used, please also ping
@rneugeba on the PR so that we can update our internal Linux tree to
ensure that patches are carried forward if we update the kernel in the
future.
### Preparation
Patches are applied to point releases of the linux stable tree. You
need an up-to-date copy of that tree:
```sh
git clone git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git
```
Add it as a remote to a clone of the [LinuxKit clone](https://github.com/linuxkit/linux).
We use the following variables:
- `KITSRC`: Base directory of LinuxKit repository
- `LINUXSRC`: Base directory of Linux stable kernel repository
e.g.:
```sh
KITSRC=~/src/linuxkit/linuxkit
LINUXSRC=~/src/linuxkit/linux
```
to refer to the location of the LinuxKit and Linux kernel trees.
### Updating the patches to a new kernel version
There are different ways to do this, but we recommend applying the
patches to the current version and then rebase to the new version. We
define the following variables to refer to the current base tag and
the new tag you want to rebase the patches to:
```sh
CURTAG=v4.9.14
NEWTAG=v4.9.15
```
If you don't already have a branch, it's best to import the current
patch set and then rebase:
```sh
cd $LINUXSRC
git checkout -b ${NEWTAG}-linuxkit ${CURTAG}
git am ${KITSRC}/kernel/patches/*.patch
git rebase ${NEWTAG}-linuxkit ${NEWTAG}
```
The `git am` should not have any conflicts and if the rebase has
conflicts resolve them, then `git add <files>` and `git rebase
--continue`.
If you already have linux tree with a `${CURTAG}-linuxkit` branch, you
can rebase by creating a new branch from the current branch and then
rebase:
```sh
cd $LINUXSRC
git checkout ${CURTAG}-linuxkit
git branch ${NEWTAG}-linuxkit ${CURTAG}-linuxkit
git rebase --onto ${NEWTAG} ${NEWTAG} ${NEWTAG}-linuxkit
```
Again, resolve any conflicts as described above.
### Adding/Removing patches
If you want to add or remove patches make sure you have an up-to-date
branch with the currently applied patches (see above). Then either any
normal means (`git cherry-pick -x`, `git am`, or `git commit`, etc) to
add new patches. For cherry-picked patches also please add a `Origin:`
line after the DCO lines with a reference the git tree the patch was
cherry-picked from.
If the patch is not cherry-picked try to include as much information
in the commit message as possible as to where the patch originated
from. The canonical form would be to add a `Origin:` line after the
DCO lines, e.g.:
```
Origin: https://patchwork.ozlabs.org/patch/622404/
```
### Export patches to LinuxKit
To export patches to LinuxKit, you should use `git format-patch` from
the Linux tree, e.g., something along these lines:
```sh
cd $LINUXSRC
rm $KITSRC/kernel/patches-4.9.x/*
git format-patch -o $KITSRC/kernel/patches-4.9.x v4.9.15..HEAD
```
Then, create a PR for LinuxKit.
## Using `perf`
The `kernel-perf` package contains a statically linked `perf` binary
under `/usr/bin` which is matched with the kernel of the same tag.
The simplest way to use the `perf` utility is to add the package to
the `init` section in the YAML file. This adds the binary to the root
filesystem.
To use the binary, you can either bind mount it into the `getty` or
`ssh` service container or you can access the root filesystem from the
`getty` container via `nsenter`:
```sh
nsenter -m/proc/1/ns/mnt ash
```
Alternatively, you can add the `kernel-perf` package as stage in a
multi-stage build to add it to a custom package.
## ZFS
The kernel build Makefile has support for building the ZFS kernel
modules. Note, the modules are currently not distributed as standard
LinuxKit packages and if you wish to use them you have to compile them
yourself:
```sh
cd kernel
make ORG=<foo> push_zfs_4.9.x # or different kernel version
```
will build and push a `zfs-kmod-4.9.<version>` image to Docker Hub
under the `ORG` specified. This package contains the all the standard
kernel modules from the kernel specified plus the `spl` and `zfs`
kernel modules, with `depmod` run over them, so they can be
`modprobe`ed. To use the modules do something like this in your YAML
file:
```
kernel:
image: linuxkit/kernel:4.9.<version>
cmdline: "console=tty0 console=ttyS0 console=ttyAMA0"
init:
- <foo>/zfs-kmod:4.9.<version>
...
```
Then, you also need to make sure the Alpine `zfs` utilities are
available in the container where your want to run `zfs` commands. The
Alpine `zfs` utilities are available in `linuxkit/alpine` and the
version of the kernel module should match the version of the
tools. The container where you run the `zfs` tools might also need
`CAP_SYS_MODULE` to be able to load the kernel modules.
## Kernels in examples and tests
All of the linuxkit `.yml` files use the images from `linuxkit/kernel:<tag>`.
When updating the kernel, you run commands to update the tests. The updates to any file that contains
references to `linuxkit/kernel` in this repository work as follows:
- Semver tags are replaced by the most recent kernel version. For example, `linuxkit/kernel:5.10.104` will become `6.6.13` when available, and then `6.6.15`, and then `7.0.1`, etc. The highest semver always is used.
- Semver+hash tags are replaced by the most recent hash and patch version for that series. For example, `linuxkit/kernel:5.10.104-abcdef1234` will become `5.10.104-aaaa54232` (same semver, newer hash), and then `5.10.105-bbbb12345` (newer semver, newer hash), etc. The highest semver+hash always is used.
This is not an inherent characteristic of `linuxkit` tool, which **never** will change your `.yml` files. It is part of
the update process for yml files _in this repository_.
The net of the above is the following rule:
* If you want a reference to a specific kernel series, e.g. a test or example that works only with `5.10.x`, then use a specific hash, e.g. `linuxkit/kernel:5.10.104-abcdef1234`. The hash and patch version will update, but not more. The most common use case for this is kernel version-specific tests.
* If you want a reference to the most recent kernel, whatever version it is, then use a semver tag, e.g. `linuxkit/kernel:6.6.13`. The most common use case for this is examples that work with any kernel version, which is the vast majority of cases.
You can get the current hash by executing the following:
```bash
$ cd kernel
$ make tag-plain-kernel-<version>
# for example:
$ make tag-plain-kernel-6.6.13
linuxkit/kernel:6.6.13-3a8b3faf92390265b1fbee792b9a3fe14d14c26e
```