xref: /linux/Documentation/dev-tools/container.rst (revision d26ab84593e63bc5395ed9b518502830fda3367c)
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``-c, --config-file CONFIG_FILE``
30
31    Path to the config file.  If not specified, the default is to look for
32    ``.container.toml`` in the current working directory.
33
34``-e, --env-file ENV_FILE``
35
36    Path to an environment file to load in the container.
37
38``-g, --gid GID``
39
40    Group ID to use inside the container.
41
42``-i, --image IMAGE``
43
44    Container image name (required).
45
46``-p, --config-profile CONFIG_PROFILE``
47
48    Profile section to use in the config file.  This will override any values
49    defined in the ``DEFAULT`` section.
50
51``-r, --runtime RUNTIME``
52
53    Container runtime name.  Supported runtimes: ``podman``, ``docker``.
54
55    If not specified, the first one found on the system will be used
56    i.e. Podman if present, otherwise Docker.
57
58``-s, --shell``
59
60    Run the container in an interactive shell.
61
62``-u, --uid UID``
63
64    User ID to use inside the container.
65
66    If the ``-g`` option is not specified and no group ID is defined in the
67    configuration file, the user ID will also be set as the group ID.
68
69``-v, --verbose``
70
71    Enable verbose output.
72
73``-h, --help``
74
75    Show the help message and exit.
76
77
78Usage
79=====
80
81It's entirely up to the user to choose which image to use and the ``CMD``
82arguments are passed directly as an arbitrary command line to run in the
83container.  The tool will take care of mounting the source tree as the current
84working directory and adjust the user and group ID as needed.
85
86The container image which would typically include a compiler toolchain is
87provided by the user and selected via the ``-i`` option.  The container runtime
88can be selected with the ``-r`` option, which can be either ``podman`` or
89``docker``.  If none is specified, the first one found on the system will be
90used while giving priority to Podman.  Support for other runtimes may be added
91later depending on their popularity among users.
92
93By default, commands are run non-interactively.  The user can abort a running
94container with SIGINT (Ctrl-C).  To run commands interactively with a TTY, the
95``--shell`` or ``-s`` option can be used.  Signals will then be received by the
96shell directly rather than the parent ``container`` process.  To exit an
97interactive shell, use Ctrl-D or ``exit``.
98
99A :ref:`configuration file<config_file>` may be used to facilitate running
100containers for various use cases.  It also removes the burden of repeatedly
101providing the same options on the command line.
102
103.. note::
104
105   The only host requirement aside from a container runtime is Python 3.11 or
106   later.
107
108.. note::
109
110   Out-of-tree builds are not fully supported yet.  The ``O=`` option can
111   however already be used with a relative path inside the source tree to keep
112   separate build outputs.  A workaround to build outside the tree is to use
113   ``mount --bind``, see the examples section further down.
114
115
116Environment Variables
117=====================
118
119Environment variables are not propagated to the container so they have to be
120either defined in the image itself or via the ``-e`` option using an
121environment file.  In some cases it makes more sense to have them defined in
122the Containerfile used to create the image.  For example, a Clang-only compiler
123toolchain image may have ``LLVM=1`` defined.
124
125The local environment file is more useful for user-specific variables added
126during development.  It is passed as-is to the container runtime so its format
127may vary.  Typically, it will look like the output of ``env``.  For example::
128
129  INSTALL_MOD_STRIP=1
130  SOME_RANDOM_TEXT=One upon a time
131
132Please also note that ``make`` options can still be passed on the command line,
133so while this can't be done since the first argument needs to be the
134executable::
135
136  scripts/container -i docker.io/tuxmake/korg-clang LLVM=1 make  # won't work
137
138this will work::
139
140  scripts/container -i docker.io/tuxmake/korg-clang make LLVM=1
141
142
143User IDs
144========
145
146This is an area where the behaviour will vary slightly depending on the
147container runtime.  The goal is to run commands as the user invoking the tool.
148With Podman, a namespace is created to map the current user ID to a different
149one in the container (1000 by default).  With Docker, while this is also
150possible with recent versions it requires a special feature to be enabled in
151the daemon so it's not used here for simplicity.  Instead, the container is run
152with the current user ID directly.  In both cases, this will provide the same
153file permissions for the kernel source tree mounted as a volume.  The only
154difference is that when using Docker without a namespace, the user ID may not
155be the same as the default one set in the image.
156
157Say, we're using an image which sets up a default user with ID 1000 and the
158current user calling the ``container`` tool has ID 1234.  The kernel source
159tree was checked out by this same user so the files belong to user 1234.  With
160Podman, the container will be running as user ID 1000 with a mapping to ID 1234
161so that the files from the mounted volume appear to belong to ID 1000 inside
162the container.  With Docker and no namespace, the container will be running
163with user ID 1234 which can access the files in the volume but not in the user
1641000 home directory.  This shouldn't be an issue when running commands only in
165the kernel tree but it is worth highlighting here as it might matter for
166special corner cases.
167
168Group IDs (GID) follow the same logic as user IDs (UID).  When specifying a UID
169via the ``--uid`` option or in the configuration file, the GID takes the same
170value as the UID by default.  A specific GID can be set via ``--gid`` or the
171configuration file.
172
173.. note::
174
175   Podman's `Docker compatibility
176   <https://podman-desktop.io/docs/migrating-from-docker/managing-docker-compatibility>`__
177   mode to run ``docker`` commands on top of a Podman backend is more complex
178   and not fully supported yet.  As such, Podman will take priority if both
179   runtimes are available on the system.
180
181
182Examples
183========
184
185The TuxMake project provides a variety of prebuilt container images available
186on `Docker Hub <https://hub.docker.com/u/tuxmake>`__.  Here's the shortest
187example to build a kernel using a TuxMake Clang image::
188
189  scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 defconfig
190  scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 -j$(nproc)
191
192.. note::
193
194   When running a command with options within the container, it should be
195   separated with a double dash ``--`` to not confuse them with the
196   ``container`` tool options.  Plain commands with no options don't strictly
197   require the double dashes e.g.::
198
199     scripts/container -i docker.io/tuxmake/korg-clang make mrproper
200
201To run ``checkpatch.pl`` in a ``patches`` directory with a generic Perl image::
202
203  scripts/container -i perl:slim-trixie scripts/checkpatch.pl patches/*
204
205As an alternative to the TuxMake images, the examples below refer to
206``kernel.org`` images which are based on the `kernel.org compiler toolchains
207<https://mirrors.edge.kernel.org/pub/tools/>`__.  These aren't (yet) officially
208available in any public registry but users can build their own locally instead
209using this `experimental repository
210<https://gitlab.com/gtucker/korg-containers>`__ by running ``make
211PREFIX=kernel.org/``.
212
213To build just ``bzImage`` using Clang::
214
215  scripts/container -i kernel.org/clang -- make bzImage -j$(nproc)
216
217Same with GCC 15 as a particular version tag::
218
219  scripts/container -i kernel.org/gcc:15 -- make bzImage -j$(nproc)
220
221For an out-of-tree build, a trick is to bind-mount the destination directory to
222a relative path inside the source tree::
223
224  mkdir -p $HOME/tmp/my-kernel-build
225  mkdir -p build
226  sudo mount --bind $HOME/tmp/my-kernel-build build
227  scripts/container -i kernel.org/gcc -- make mrproper
228  scripts/container -i kernel.org/gcc -- make O=build defconfig
229  scripts/container -i kernel.org/gcc -- make O=build -j$(nproc)
230
231To run KUnit in an interactive shell and get the full output::
232
233  scripts/container -s -i kernel.org/gcc:kunit -- \
234      tools/testing/kunit/kunit.py \
235          run \
236          --arch=x86_64 \
237          --cross_compile=x86_64-linux-
238
239To just start an interactive shell::
240
241  scripts/container -si kernel.org/gcc bash
242
243To build the HTML documentation, which requires the ``kdocs`` image built with
244``make PREFIX=kernel.org/ extra`` as it's not a compiler toolchain::
245
246  scripts/container -i kernel.org/kdocs make htmldocs
247
248.. _config_file:
249
250Configuration File
251==================
252
253By default, the tool will look for a configuration file named
254``.container.toml`` in the current working directory.  If not found, it will be
255silently ignored as it's not required.  Alternatively, any other path can be
256specified with the ``-c`` option in which case the file needs to be present or
257an error will be raised.
258
259Its data follows the standard TOML format and is made up of different sections
260with ``DEFAULT`` as the default one.  Other sections may be used to define
261alternative profiles under arbitrary names which can be selected by the ``-p``
262option.  Command line options take precedence over configuration values, and
263profile sections take precedence over the default one.
264
265Supported options in each section are:
266
267``env_file``
268
269    Path to an environment file to load in the container, equivalent to the
270    ``-e`` command line option.
271
272``image``
273
274    Name of the container image to use, equivalent to the ``-i`` command line
275    option.
276
277``runtime``
278
279    Name of the container runtime, equivalent to the ``-r`` command line option.
280
281``uid`` / ``gid`` (integers)
282
283    User and group ID numbers to use inside the container, equivalents to the
284    ``-u`` and ``-g`` command line options respectively.
285
286
287Here's a sample configuration with an extra ``clang`` profile::
288
289  [DEFAULT]
290  runtime = "podman"
291  image = "tuxmake/korg-gcc"
292
293  [clang]
294  image = "tuxmake/korg-clang"
295  env_file = ".clang.env"
296
297It mentions a ``.clang.env`` file which simply contains this flag::
298
299  LLVM=1
300
301Let's take a look again at this example mentioned earlier::
302
303  scripts/container -i docker.io/tuxmake/korg-clang -- make LLVM=1 defconfig
304
305Using the configuration file, it can now be simplified into this::
306
307  scripts/container -p clang -- make defconfig
308
309Then to override the default user, the ``-u`` option can still be used::
310
311  scripts/container -p clang -u0 -- make defconfig
312
313This also illustrates how values take precedence over each other: the runtime
314is loaded from the ``DEFAULT`` section, the image from the ``clang`` section
315and the user ID from the command line ``-u`` option.
316