workflows.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 0/2] scripts: introduce containerized builds
@ 2025-12-10 13:58 Guillaume Tucker
  2025-12-10 13:58 ` [PATCH v1 1/2] scripts: add tool to run " Guillaume Tucker
  2025-12-10 13:58 ` [PATCH v1 2/2] Documentation: dev-tools: add container.rst page Guillaume Tucker
  0 siblings, 2 replies; 4+ messages in thread
From: Guillaume Tucker @ 2025-12-10 13:58 UTC (permalink / raw)
  To: Nathan Chancellor, Miguel Ojeda
  Cc: linux-kernel, rust-for-linux, linux-kbuild, automated-testing,
	workflows, llvm, Arnd Bergmann, Guillaume Tucker

This proposal emerged from an email discussion and a talk at Plumbers
last year:

    https://lore.kernel.org/all/affb7aff-dc9b-4263-bbd4-a7965c19ac4e@gtucker.io/

The aim is to facilitate reproducing builds for CI bots as well as
developers using containers.  Here's an illustrative example with a
kernel.org toolchain in a Docker image from tuxmake:

    $ scripts/container -i tuxmake/korg-clang-21 make LLVM=1 defconfig
      HOSTCC  scripts/basic/fixdep
      HOSTCC  scripts/kconfig/conf.o
    [...]
      HOSTCC  scripts/kconfig/util.o
      HOSTLD  scripts/kconfig/conf
    *** Default configuration is based on 'x86_64_defconfig'
    #
    # configuration written to .config
    #

and a follow-up command to build the kernel with the verbose flag
turned on to show DEBUG log messages from the container tool:

    $ scripts/container -i tuxmake/korg-clang-21 -v -- make LLVM=1 -j8
    [container DEBUG] runtime=docker, image=tuxmake/korg-clang-21
      GEN     arch/x86/include/generated/asm/orc_hash.h
      HOSTCC  scripts/basic/fixdep
      SYSHDR  arch/x86/include/generated/uapi/asm/unistd_32.h
      SYSHDR  arch/x86/include/generated/uapi/asm/unistd_64.h
      SYSHDR  arch/x86/include/generated/uapi/asm/unistd_x32.h
      WRAP    arch/x86/include/generated/uapi/asm/bpf_perf_event.h
      WRAP    arch/x86/include/generated/uapi/asm/errno.h
    [...]
      LD      arch/x86/boot/setup.elf
      OBJCOPY arch/x86/boot/setup.bin
      BUILD   arch/x86/boot/bzImage
    Kernel: arch/x86/boot/bzImage is ready  (#1)

While the example above uses a tuxmake image, I've also started
preparing reference container images with kernel.org toolchains and
no third-party dependencies other than the base Debian distro:

    https://gitlab.com/gtucker/korg-containers

This patch series include a documentation page with all the relevant
details about how to use the tool and images currently available.

Guillaume Tucker (2):
  scripts: add tool to run containerized builds
  Documentation: dev-tools: add container.rst page

 Documentation/dev-tools/container.rst | 175 ++++++++++++++++++++++++++
 Documentation/dev-tools/index.rst     |   1 +
 scripts/container                     | 112 +++++++++++++++++
 3 files changed, 288 insertions(+)
 create mode 100644 Documentation/dev-tools/container.rst
 create mode 100755 scripts/container

-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v1 1/2] scripts: add tool to run containerized builds
  2025-12-10 13:58 [PATCH v1 0/2] scripts: introduce containerized builds Guillaume Tucker
@ 2025-12-10 13:58 ` Guillaume Tucker
  2025-12-13  4:16   ` Guillaume Tucker
  2025-12-10 13:58 ` [PATCH v1 2/2] Documentation: dev-tools: add container.rst page Guillaume Tucker
  1 sibling, 1 reply; 4+ messages in thread
From: Guillaume Tucker @ 2025-12-10 13:58 UTC (permalink / raw)
  To: Nathan Chancellor, Miguel Ojeda
  Cc: linux-kernel, rust-for-linux, linux-kbuild, automated-testing,
	workflows, llvm, Arnd Bergmann, Guillaume Tucker

Add a 'scripts/container' tool written in Python to run any command in
the source tree from within a container.  This can typically be used
to call 'make' with a compiler toolchain image to run reproducible
builds but any arbitrary command can be run too.  Only Docker and
Podman are supported for this initial version.

Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Miguel Ojeda <ojeda@kernel.org>
Link: https://lore.kernel.org/all/affb7aff-dc9b-4263-bbd4-a7965c19ac4e@gtucker.io/
Signed-off-by: Guillaume Tucker <gtucker@gtucker.io>
---
 scripts/container | 112 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 112 insertions(+)
 create mode 100755 scripts/container

diff --git a/scripts/container b/scripts/container
new file mode 100755
index 000000000000..74644ac33685
--- /dev/null
+++ b/scripts/container
@@ -0,0 +1,112 @@
+#!/bin/env python3
+# SPDX-License-Identifier: GPL-2.0-only
+# Copyright (C) 2025 Guillaume Tucker
+
+"""Containerized builds"""
+
+import argparse
+import logging
+import os
+import subprocess
+import sys
+
+
+def get_logger(verbose):
+    """Set up a logger with the appropriate level"""
+    logger = logging.getLogger('container')
+    handler = logging.StreamHandler()
+    handler.setFormatter(logging.Formatter(
+        fmt='[container {levelname}] {message}', style='{'
+    ))
+    logger.addHandler(handler)
+    logger.setLevel(logging.DEBUG if verbose is True else logging.INFO)
+    return logger
+
+
+def run_docker(args):
+    """Run a command in a Docker container"""
+    uid = args.uid or os.getuid()
+    gid = args.gid or args.uid or os.getgid()
+    cmd = [
+        'docker', 'run',
+        '--interactive',
+        '--volume', f'{os.getcwd()}:/src',
+        '--workdir', '/src',
+        '--user', f'{uid}:{gid}'
+    ]
+    if args.env_file:
+        cmd += ['--env-file', args.env_file]
+    cmd.append(args.image)
+    cmd += args.cmd
+    return subprocess.call(cmd)
+
+
+def run_podman(args):
+    """Run a command in a Podman container"""
+    uid = args.uid or 1000
+    gid = args.gid or args.uid or 1000
+    cmd = [
+        'podman', 'run',
+        '--interactive',
+        '--volume', f'{os.getcwd()}:/src',
+        '--workdir', '/src',
+        '--userns', f'keep-id:uid={uid},gid={gid}',
+    ]
+    if args.env_file:
+        cmd += ['--env-file', args.env_file]
+    cmd.append(args.image)
+    cmd += args.cmd
+    return subprocess.call(cmd)
+
+
+def main(args):
+    """Main entry point for the container tool"""
+    logger = get_logger(args.verbose)
+    logger.debug("runtime=%s, image=%s", args.runtime, args.image)
+    runtimes = {
+        'docker': run_docker,
+        'podman': run_podman,
+    }
+    handler = runtimes.get(args.runtime)
+    if not handler:
+        logger.error("Unknown container runtime: %s", args.runtime)
+        return 1
+    try:
+        return handler(args)
+    except KeyboardInterrupt:
+        logger.error("aborted")
+        return 1
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser("Containerized builds")
+    parser.add_argument(
+        '-e', '--env-file',
+        help="Path to an environment file to load in the container."
+    )
+    parser.add_argument(
+        '-g', '--gid',
+        help="Group ID to use inside the container."
+    )
+    parser.add_argument(
+        '-i', '--image', default='gcc',
+        help="Container image, default is gcc."
+    )
+    parser.add_argument(
+        '-r', '--runtime', choices=['docker', 'podman'], default='docker',
+        help="Container runtime, default is docker."
+    )
+    parser.add_argument(
+        '-u', '--uid',
+        help="User ID to use inside the container.  If the -g option is not"
+        "specified, the user ID will also be used for the group ID."
+    )
+    parser.add_argument(
+        '-v', '--verbose', action='store_true',
+        help="Enable verbose output."
+    )
+    parser.add_argument(
+        'cmd', nargs='+',
+        help="Command to run in the container"
+    )
+    sys.exit(main(parser.parse_args(sys.argv[1:])))
-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [PATCH v1 2/2] Documentation: dev-tools: add container.rst page
  2025-12-10 13:58 [PATCH v1 0/2] scripts: introduce containerized builds Guillaume Tucker
  2025-12-10 13:58 ` [PATCH v1 1/2] scripts: add tool to run " Guillaume Tucker
@ 2025-12-10 13:58 ` Guillaume Tucker
  1 sibling, 0 replies; 4+ messages in thread
From: Guillaume Tucker @ 2025-12-10 13:58 UTC (permalink / raw)
  To: Nathan Chancellor, Miguel Ojeda
  Cc: linux-kernel, rust-for-linux, linux-kbuild, automated-testing,
	workflows, llvm, Arnd Bergmann, Guillaume Tucker

Add a dev-tools/container.rst documentation page for the
scripts/container tool.  This covers the basic usage with additional
information about environment variables and user IDs.  It also
includes a number of practical examples with a reference to the
experimental kernel.org toolchain images.

Cc: Nathan Chancellor <nathan@kernel.org>
Cc: Miguel Ojeda <ojeda@kernel.org>
Signed-off-by: Guillaume Tucker <gtucker@gtucker.io>
---
 Documentation/dev-tools/container.rst | 175 ++++++++++++++++++++++++++
 Documentation/dev-tools/index.rst     |   1 +
 2 files changed, 176 insertions(+)
 create mode 100644 Documentation/dev-tools/container.rst

diff --git a/Documentation/dev-tools/container.rst b/Documentation/dev-tools/container.rst
new file mode 100644
index 000000000000..2a56f256f648
--- /dev/null
+++ b/Documentation/dev-tools/container.rst
@@ -0,0 +1,175 @@
+.. SPDX-License-Identifier: GPL-2.0-only
+.. Copyright (C) 2025 Guillaume Tucker
+
+====================
+Containerized Builds
+====================
+
+The ``container`` tool can be used to run any command in the kernel source tree
+from within a container.  Doing so facilitates reproducing builds across
+various platforms, for example when a test bot has reported an issue which
+requires a specific version of a compiler or an external test suite.  While
+this can already be done by users who are familiar with containers, having a
+dedicated tool in the kernel tree lowers the barrier to entry by solving common
+problems once and for all (e.g. user id management).  It also makes it easier
+to share an exact command line leading to a particular result.  The main use
+case is likely to be kernel builds but virtually anything can be run: KUnit,
+checkpatch etc. provided a suitable image is available.
+
+
+Options
+=======
+
+Command line syntax::
+
+  scripts/container [OPTION]... CMD...
+
+Available options:
+
+``-e, --env-file ENV_FILE``
+
+    Path to an environment file to load in the container.
+
+``-g, --gid GID``
+
+    Group id to use inside the container.
+
+``-i, --image IMAGE``
+
+    Container image, default is ``gcc``.
+
+``-r, --runtime RUNTIME``
+
+    Container runtime, default is ``docker``.  Supported runtimes: ``docker``,
+    ``podman``.
+
+``-u, --uid UID``
+
+    User id to use inside the container.  If the ``-g`` option is not
+    specified, the user id will also be used for the group id.
+
+``-v, --verbose``
+
+    Enable verbose output.
+
+``-h, --help``
+
+    Show the help message and exit.
+
+
+Usage
+=====
+
+It's entirely up to the user to choose which image to use and the ``CMD``
+arguments are passed directly as an arbitrary command line to run in the
+container.  The tool will take care of mounting the source tree as the current
+working directory and adjust the user and group id as needed.
+
+The container images are provided by the user and selected via the ``-i``
+option.  They will typically include a compiler toolchain to build the kernel
+and as such, the default image tag is set to ``gcc`` to give a convenient way
+of running builds.  Any local image with a GCC compiler toolchain could be
+tagged as ``gcc`` to make it point to it.  For example::
+
+  docker tag my-user/gcc:15 gcc
+
+The container runtime can be selected with the ``-r`` option, which can be
+either Docker or Podman.  Support for other runtimes may be added later
+depending on their popularity among users.
+
+
+Environment Variables
+=====================
+
+Environment variables are not propagated to the container so they have to be
+either defined in the image itself or via the ``-e`` option using an
+environment file.  In some cases it makes more sense to have them defined in
+the Containerfile used to create the image.  For example, a Clang-only compiler
+toolchain image would most likely have ``LLVM=1`` defined.  The local
+environment file is more useful for user-specific variables during development.
+
+Please note that ``make`` options can still be passed on the command line, so
+while this can't be done as the first argument needs to be the executable::
+
+  scripts/container INSTALL_MOD_STRIP=1 make modules_install
+
+this will work::
+
+  scripts/container make modules_install INSTALL_MOD_STRIP=1
+
+
+User IDs
+========
+
+This is an area where the behaviour will vary slightly depending on the
+container runtime.  The goal is to run commands as the user invoking the tool.
+With Podman, a namespace is created to map the current user id to a different
+one in the container (1000 by default).  With Docker, while this is also
+possible with recent versions it requires a special feature to be enabled in
+the daemon so it's not used here for simplicity.  Instead, the container is run
+with the current user id directly.  In both cases, this will provide the same
+file permissions for the kernel source tree mounted as a volume.  The only
+difference is that when using Docker without a namespace, the user id may not
+be the same as the default one set in the image.
+
+Say, we're using an image which sets up a default user with id 1000 and the
+current user calling the ``container`` tool has id 1234.  The kernel source
+tree was checked out by this same user so the files belong to user 1234.  With
+Podman, the container will be running as user id 1000 with a mapping to id 1234
+so that the files from the mounted volume appear to belong to id 1000 inside
+the container.  With Docker and no namespace, the container will be running
+with user id 1234 which can access the files in the volume but not in the user
+1000 home directory.  This shouldn't be an issue when running commands only in
+the kernel tree but it is worth highlighting here as it might matter for
+special corner cases.
+
+
+Examples
+========
+
+The shortest example is to run a basic kernel build using Docker and the
+default ``gcc`` image::
+
+  scripts/container -- make defconfig
+  scripts/container -- make -j$(nproc)
+
+.. note::
+
+   When running a command with options within the container, it should be
+   separated with a double dash ``--`` to not confuse them with the
+   ``container`` tool options.  Simple make targets with no options don't
+   strictly require the double dashes e.g.::
+
+     scripts/container make mrproper
+
+To run ``checkpatch.pl`` in a ``patches`` directory with a generic image::
+
+  scripts/container -i perl:slim-trixie scripts/checkpatch.pl patches/*
+
+To build using the TuxMake Clang image::
+
+  scripts/container -i tuxmake/x86_64_korg-clang -- make LLVM=1 -j$(nproc)
+
+The examples below refer to ``kernel.org`` images which are based on the
+`kernel.org compiler toolchains
+<https://mirrors.edge.kernel.org/pub/tools/>`__.  These aren't (yet) available
+in any public registry but users can build their own locally instead using this
+`experimental repository <https://gitlab.com/gtucker/korg-containers>`__ by
+running ``make PREFIX=kernel.org/``.
+
+To build just ``bzImage`` using Clang::
+
+  scripts/container -i kernel.org/clang -- make bzImage -j$(nproc)
+
+To run KUnit::
+
+  scripts/container -i kernel.org/gcc:kunit -- \
+      tools/testing/kunit/kunit.py \
+          run \
+          --arch=x86_64 \
+          --cross_compile=x86_64-linux-
+
+To build the HTML documentation, which requires the ``kdocs`` image built with
+``make PREFIX=kernel.org/ extra`` as it's not a compiler toolchain::
+
+  scripts/container -i kernel.org/kdocs make htmldocs
diff --git a/Documentation/dev-tools/index.rst b/Documentation/dev-tools/index.rst
index 4b8425e348ab..527a0e4cf2ed 100644
--- a/Documentation/dev-tools/index.rst
+++ b/Documentation/dev-tools/index.rst
@@ -38,6 +38,7 @@ Documentation/process/debugging/index.rst
    gpio-sloppy-logic-analyzer
    autofdo
    propeller
+   container
 
 
 .. only::  subproject and html
-- 
2.47.3


^ permalink raw reply	[flat|nested] 4+ messages in thread

* Re: [PATCH v1 1/2] scripts: add tool to run containerized builds
  2025-12-10 13:58 ` [PATCH v1 1/2] scripts: add tool to run " Guillaume Tucker
@ 2025-12-13  4:16   ` Guillaume Tucker
  0 siblings, 0 replies; 4+ messages in thread
From: Guillaume Tucker @ 2025-12-13  4:16 UTC (permalink / raw)
  To: Nathan Chancellor, Miguel Ojeda
  Cc: linux-kernel, rust-for-linux, linux-kbuild, automated-testing,
	workflows, llvm, Arnd Bergmann, Onur Özkan

[+Onur - sorry I didn't Cc you when sending this series]

On 10/12/2025 2:58 pm, Guillaume Tucker wrote:
> +def run_docker(args):
> +    """Run a command in a Docker container"""
> +    uid = args.uid or os.getuid()
> +    gid = args.gid or args.uid or os.getgid()
> +    cmd = [
> +        'docker', 'run',
> +        '--interactive',
> +        '--volume', f'{os.getcwd()}:/src',
> +        '--workdir', '/src',
> +        '--user', f'{uid}:{gid}'
> +    ]
> +    if args.env_file:
> +        cmd += ['--env-file', args.env_file]
> +    cmd.append(args.image)
> +    cmd += args.cmd
> +    return subprocess.call(cmd)

Just realised that it also needs a TTY to handle Ctrl-C signals
correctly, otherwise the Python process would stop but the container
would keep running in a detached process (same for podman):


diff --git a/scripts/container b/scripts/container
index 74644ac33685..e05425c06d28 100755
--- a/scripts/container
+++ b/scripts/container
@@ -30,6 +30,7 @@ def run_docker(args):
      cmd = [
          'docker', 'run',
          '--interactive',
+        '--tty',
          '--volume', f'{os.getcwd()}:/src',
          '--workdir', '/src',
          '--user', f'{uid}:{gid}'


I'll send a v2 next week, but I'll wait a bit for any feedback first.

Thanks,
Guillaume




^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2025-12-13 15:57 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-12-10 13:58 [PATCH v1 0/2] scripts: introduce containerized builds Guillaume Tucker
2025-12-10 13:58 ` [PATCH v1 1/2] scripts: add tool to run " Guillaume Tucker
2025-12-13  4:16   ` Guillaume Tucker
2025-12-10 13:58 ` [PATCH v1 2/2] Documentation: dev-tools: add container.rst page Guillaume Tucker

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox