xref: /linux/Documentation/dev-tools/container.rst (revision 23b0f90ba871f096474e1c27c3d14f455189d2d9)
1.. SPDX-License-Identifier: GPL-2.0-only
2.. Copyright (C) 2025 Guillaume Tucker
3
4====================
5Containerized Builds
6====================
7
8The ``container`` tool can be used to run any command in the kernel source tree
9from within a container.  Doing so facilitates reproducing builds across
10various platforms, for example when a test bot has reported an issue which
11requires a specific version of a compiler or an external test suite.  While
12this can already be done by users who are familiar with containers, having a
13dedicated tool in the kernel tree lowers the barrier to entry by solving common
14problems once and for all (e.g. user id management).  It also makes it easier
15to share an exact command line leading to a particular result.  The main use
16case is likely to be kernel builds but virtually anything can be run: KUnit,
17checkpatch etc. provided a suitable image is available.
18
19
20Options
21=======
22
23Command line syntax::
24
25  scripts/container -i IMAGE [OPTION]... CMD...
26
27Available options:
28
29``-e, --env-file ENV_FILE``
30
31    Path to an environment file to load in the container.
32
33``-g, --gid GID``
34
35    Group id to use inside the container.
36
37``-i, --image IMAGE``
38
39    Container image name (required).
40
41``-r, --runtime RUNTIME``
42
43    Container runtime name.  Supported runtimes: ``docker``, ``podman``.
44
45    If not specified, the first one found on the system will be used
46    i.e. Podman if present, otherwise Docker.
47
48``-s, --shell``
49
50    Run the container in an interactive shell.
51
52``-u, --uid UID``
53
54    User id to use inside the container.
55
56    If the ``-g`` option is not specified, the user id will also be used for
57    the group id.
58
59``-v, --verbose``
60
61    Enable verbose output.
62
63``-h, --help``
64
65    Show the help message and exit.
66
67
68Usage
69=====
70
71It's entirely up to the user to choose which image to use and the ``CMD``
72arguments are passed directly as an arbitrary command line to run in the
73container.  The tool will take care of mounting the source tree as the current
74working directory and adjust the user and group id as needed.
75
76The container image which would typically include a compiler toolchain is
77provided by the user and selected via the ``-i`` option.  The container runtime
78can be selected with the ``-r`` option, which can be either ``docker`` or
79``podman``.  If none is specified, the first one found on the system will be
80used while giving priority to Podman.  Support for other runtimes may be added
81later depending on their popularity among users.
82
83By default, commands are run non-interactively.  The user can abort a running
84container with SIGINT (Ctrl-C).  To run commands interactively with a TTY, the
85``--shell`` or ``-s`` option can be used.  Signals will then be received by the
86shell directly rather than the parent ``container`` process.  To exit an
87interactive shell, use Ctrl-D or ``exit``.
88
89.. note::
90
91   The only host requirement aside from a container runtime is Python 3.10 or
92   later.
93
94.. note::
95
96   Out-of-tree builds are not fully supported yet.  The ``O=`` option can
97   however already be used with a relative path inside the source tree to keep
98   separate build outputs.  A workaround to build outside the tree is to use
99   ``mount --bind``, see the examples section further down.
100
101
102Environment Variables
103=====================
104
105Environment variables are not propagated to the container so they have to be
106either defined in the image itself or via the ``-e`` option using an
107environment file.  In some cases it makes more sense to have them defined in
108the Containerfile used to create the image.  For example, a Clang-only compiler
109toolchain image may have ``LLVM=1`` defined.
110
111The local environment file is more useful for user-specific variables added
112during development.  It is passed as-is to the container runtime so its format
113may vary.  Typically, it will look like the output of ``env``.  For example::
114
115  INSTALL_MOD_STRIP=1
116  SOME_RANDOM_TEXT=One upon a time
117
118Please also note that ``make`` options can still be passed on the command line,
119so while this can't be done since the first argument needs to be the
120executable::
121
122  scripts/container -i docker.io/tuxmake/korg-clang LLVM=1 make  # won't work
123
124this will work::
125
126  scripts/container -i docker.io/tuxmake/korg-clang make LLVM=1
127
128
129User IDs
130========
131
132This is an area where the behaviour will vary slightly depending on the
133container runtime.  The goal is to run commands as the user invoking the tool.
134With Podman, a namespace is created to map the current user id to a different
135one in the container (1000 by default).  With Docker, while this is also
136possible with recent versions it requires a special feature to be enabled in
137the daemon so it's not used here for simplicity.  Instead, the container is run
138with the current user id directly.  In both cases, this will provide the same
139file permissions for the kernel source tree mounted as a volume.  The only
140difference is that when using Docker without a namespace, the user id may not
141be the same as the default one set in the image.
142
143Say, we're using an image which sets up a default user with id 1000 and the
144current user calling the ``container`` tool has id 1234.  The kernel source
145tree was checked out by this same user so the files belong to user 1234.  With
146Podman, the container will be running as user id 1000 with a mapping to id 1234
147so that the files from the mounted volume appear to belong to id 1000 inside
148the container.  With Docker and no namespace, the container will be running
149with user id 1234 which can access the files in the volume but not in the user
1501000 home directory.  This shouldn't be an issue when running commands only in
151the kernel tree but it is worth highlighting here as it might matter for
152special corner cases.
153
154.. note::
155
156   Podman's `Docker compatibility
157   <https://podman-desktop.io/docs/migrating-from-docker/managing-docker-compatibility>`__
158   mode to run ``docker`` commands on top of a Podman backend is more complex
159   and not fully supported yet.  As such, Podman will take priority if both
160   runtimes are available on the system.
161
162
163Examples
164========
165
166The TuxMake project provides a variety of prebuilt container images available
167on `Docker Hub <https://hub.docker.com/u/tuxmake>`__.  Here's the shortest
168example to build a kernel using a TuxMake Clang image::
169
170  scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 defconfig
171  scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 -j$(nproc)
172
173.. note::
174
175   When running a command with options within the container, it should be
176   separated with a double dash ``--`` to not confuse them with the
177   ``container`` tool options.  Plain commands with no options don't strictly
178   require the double dashes e.g.::
179
180     scripts/container -i docker.io/tuxmake/korg-clang make mrproper
181
182To run ``checkpatch.pl`` in a ``patches`` directory with a generic Perl image::
183
184  scripts/container -i perl:slim-trixie scripts/checkpatch.pl patches/*
185
186As an alternative to the TuxMake images, the examples below refer to
187``kernel.org`` images which are based on the `kernel.org compiler toolchains
188<https://mirrors.edge.kernel.org/pub/tools/>`__.  These aren't (yet) officially
189available in any public registry but users can build their own locally instead
190using this `experimental repository
191<https://gitlab.com/gtucker/korg-containers>`__ by running ``make
192PREFIX=kernel.org/``.
193
194To build just ``bzImage`` using Clang::
195
196  scripts/container -i kernel.org/clang -- make bzImage -j$(nproc)
197
198Same with GCC 15 as a particular version tag::
199
200  scripts/container -i kernel.org/gcc:15 -- make bzImage -j$(nproc)
201
202For an out-of-tree build, a trick is to bind-mount the destination directory to
203a relative path inside the source tree::
204
205  mkdir -p $HOME/tmp/my-kernel-build
206  mkdir -p build
207  sudo mount --bind $HOME/tmp/my-kernel-build build
208  scripts/container -i kernel.org/gcc -- make mrproper
209  scripts/container -i kernel.org/gcc -- make O=build defconfig
210  scripts/container -i kernel.org/gcc -- make O=build -j$(nproc)
211
212To run KUnit in an interactive shell and get the full output::
213
214  scripts/container -s -i kernel.org/gcc:kunit -- \
215      tools/testing/kunit/kunit.py \
216          run \
217          --arch=x86_64 \
218          --cross_compile=x86_64-linux-
219
220To just start an interactive shell::
221
222  scripts/container -si kernel.org/gcc bash
223
224To build the HTML documentation, which requires the ``kdocs`` image built with
225``make PREFIX=kernel.org/ extra`` as it's not a compiler toolchain::
226
227  scripts/container -i kernel.org/kdocs make htmldocs
228