From e327b20cc8047fbaf78e092a5835125c1930ffe9 Mon Sep 17 00:00:00 2001 From: "Lance R. Vick" Date: Sat, 13 Jan 2024 12:36:12 -0800 Subject: [PATCH 1/7] initial docker build support --- Dockerfile | 13 +++++++++++++ rootfs.py | 20 +++++++++++++++++--- 2 files changed, 30 insertions(+), 3 deletions(-) create mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..8215dc19b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,13 @@ +FROM local/stage0 as stage0 + +FROM debian as fetch +RUN apt update && apt install -y curl gcc +ADD . live-bootstrap +WORKDIR live-bootstrap +RUN ./download-distfiles.sh +RUN mv target/ /rootfs/ + +FROM scratch as build +COPY --from=fetch /rootfs . +ENV PATH=/bin +RUN ["/bootstrap-seeds/POSIX/x86/kaem-optional-seed"] diff --git a/rootfs.py b/rootfs.py index 7cbb4bc9a..9b91bf9dc 100755 --- a/rootfs.py +++ b/rootfs.py @@ -34,7 +34,7 @@ def create_configuration_file(args): config.write(f"ARCH={args.arch}\n") config.write(f"ARCH_DIR={stage0_arch_map.get(args.arch, args.arch)}\n") config.write(f"FORCE_TIMESTAMPS={args.force_timestamps}\n") - config.write(f"CHROOT={args.chroot or args.bwrap}\n") + config.write(f"CHROOT={args.chroot or args.bwrap or args.docker}\n") config.write(f"UPDATE_CHECKSUMS={args.update_checksums}\n") config.write(f"JOBS={args.cores}\n") config.write(f"SWAP_SIZE={args.swap}\n") @@ -75,6 +75,8 @@ def main(): action="store_true") parser.add_argument("-bw", "--bwrap", help="Run inside a bwrap sandbox", action="store_true") + parser.add_argument("-do", "--docker", help="Run inside a docker build", + action="store_true") parser.add_argument("-t", "--target", help="Target directory", default="target") parser.add_argument("--tmpfs", help="Use a tmpfs on target", @@ -140,15 +142,17 @@ def check_types(): count += 1 if args.bwrap: count += 1 + if args.docker: + count += 1 if args.bare_metal: count += 1 return count if check_types() > 1: - raise ValueError("No more than one of qemu, chroot, bwrap, bare metal" + raise ValueError("No more than one of qemu, chroot, bwrap, docker, bare metal" "may be used.") if check_types() == 0: - raise ValueError("One of qemu, chroot, bwrap, or bare metal must be selected.") + raise ValueError("One of qemu, chroot, bwrap, docker, or bare metal must be selected.") # Arch validation if args.arch != "x86": @@ -250,6 +254,16 @@ def bootstrap(args, generator, target, size, cleanup): run_as_root('env', '-i', 'PATH=/bin', chroot_binary, generator.target_dir, init, cleanup=cleanup) + elif args.docker: + generator.prepare(target, using_kernel=False) + arch = stage0_arch_map.get(args.arch, args.arch) + init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed') + print(generator.target_dir, init) + run('env', '-i', 'DOCKER_BUILDKIT=1', 'docker', 'build', + '--progress=plain', + '-t', 'local/live', + '.') + elif args.bwrap: init = '/init' if not args.internal_ci or args.internal_ci == "pass1": From 347a33bd7ef5b94bda74fb867fac8d3c1c5b53c1 Mon Sep 17 00:00:00 2001 From: fosslinux Date: Sat, 13 Jan 2024 18:27:36 -0800 Subject: [PATCH 2/7] external sources arg --- rootfs.py | 4 +-- steps/improve/finalize_fhs.sh | 54 ++--------------------------------- 2 files changed, 4 insertions(+), 54 deletions(-) diff --git a/rootfs.py b/rootfs.py index 9b91bf9dc..ac24c932a 100755 --- a/rootfs.py +++ b/rootfs.py @@ -41,8 +41,8 @@ def create_configuration_file(args): config.write(f"FINAL_JOBS={args.cores}\n") config.write(f"INTERNAL_CI={args.internal_ci or False}\n") config.write(f"INTERACTIVE={args.interactive}\n") - config.write(f"QEMU={args.qemu}\n") - config.write(f"BARE_METAL={args.bare_metal or (args.qemu and args.interactive)}\n") + config.write(f"BARE_METAL={args.bare_metal}\n") + config.write(f"EXTERNAL_SOURCES={args.external_sources}\n") if (args.bare_metal or args.qemu) and not args.kernel: if args.repo or args.external_sources: config.write("DISK=sdb1\n") diff --git a/steps/improve/finalize_fhs.sh b/steps/improve/finalize_fhs.sh index 94658ab04..6c5e6d514 100755 --- a/steps/improve/finalize_fhs.sh +++ b/steps/improve/finalize_fhs.sh @@ -16,58 +16,8 @@ mount | grep '/sys' &> /dev/null || (mkdir -p /sys; mount -t sysfs sysfs /sys) mount | grep '/tmp' &> /dev/null || (mkdir -p /tmp; mount -t tmpfs tmpfs /tmp) mount | grep '/dev/shm' &> /dev/null || (mkdir -p /dev/shm; mount -t tmpfs tmpfs /dev/shm) -if [ "${CHROOT}" = False ]; then - rm /etc/mtab - ln -s /proc/mounts /etc/mtab -fi - -# Add /etc/resolv.conf -if [ ! -e "/etc/resolv.conf" ]; then +if [ "${EXTERNAL_SOURCES}" = "False" ]; then + # Add /etc/resolv.conf echo 'nameserver 1.1.1.1' > /etc/resolv.conf -fi -if [ ! -e "/etc/resolv.conf/head" ]; then echo 'nameserver 1.1.1.1' > /etc/resolv.conf.head fi - -# /etc/passwd -- taken from LFS -if [ ! -e "/etc/passwd" ]; then - cat > /etc/passwd << "EOF" -root:x:0:0:root:/root:/bin/bash -bin:x:1:1:bin:/dev/null:/usr/bin/false -daemon:x:6:6:Daemon User:/dev/null:/usr/bin/false -messagebus:x:18:18:D-Bus Message Daemon User:/run/dbus:/usr/bin/false -uuidd:x:80:80:UUID Generation Daemon User:/dev/null:/usr/bin/false -nobody:x:65534:65534:Unprivileged User:/dev/null:/usr/bin/false -EOF -fi - -# /etc/group -- taken from LFS -if [ ! -e "/etc/group" ]; then - cat > /etc/group << "EOF" -root:x:0: -bin:x:1:daemon -sys:x:2: -kmem:x:3: -tape:x:4: -tty:x:5: -daemon:x:6: -floppy:x:7: -disk:x:8: -lp:x:9: -dialout:x:10: -audio:x:11: -video:x:12: -utmp:x:13: -usb:x:14: -cdrom:x:15: -adm:x:16: -messagebus:x:18: -input:x:24: -mail:x:34: -kvm:x:61: -uuidd:x:80: -wheel:x:97: -users:x:999: -nogroup:x:65534: -EOF -fi From 3e532d3e7d26adca907197d3c90ccad5b44875a4 Mon Sep 17 00:00:00 2001 From: "Lance R. Vick" Date: Mon, 15 Jan 2024 22:16:40 -0800 Subject: [PATCH 3/7] deterministic docker support --- .dockerignore | 2 ++ Dockerfile | 33 ++++++++++++++++++++++----------- rootfs.py | 11 +++++++++-- 3 files changed, 33 insertions(+), 13 deletions(-) create mode 100644 .dockerignore diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..503659943 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,2 @@ +* +!target diff --git a/Dockerfile b/Dockerfile index 8215dc19b..1d47d90fb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,13 +1,24 @@ -FROM local/stage0 as stage0 - -FROM debian as fetch -RUN apt update && apt install -y curl gcc -ADD . live-bootstrap -WORKDIR live-bootstrap -RUN ./download-distfiles.sh -RUN mv target/ /rootfs/ - FROM scratch as build -COPY --from=fetch /rootfs . -ENV PATH=/bin +ADD target/ / RUN ["/bootstrap-seeds/POSIX/x86/kaem-optional-seed"] + +FROM build as install +ENV PATH=/bin:/usr/sbin:/usr/bin +RUN set -eux; \ + rm -rf /usr/lib/python*/__pycache__; \ + mkdir -p /rootfs/etc /rootfs/home/user; \ + cp -R $(ls -d /etc/* | grep -v '\(resolv.conf\|hosts\)') /rootfs/etc/; \ + cp -R lib usr bin var /rootfs/; \ + echo "user:x:1000:" > /rootfs/etc/group; \ + echo "user:x:1000:1000::/home/user:/bin/bash" > /rootfs/etc/passwd; \ + find /rootfs -exec touch -hcd "@0" "{}" + + +FROM scratch as package +COPY --from=install /rootfs / +USER 1000:1000 +ENTRYPOINT ["/bin/bash"] +ENV TZ=UTC +ENV LANG=C.UTF-8 +ENV SOURCE_DATE_EPOCH=1 +ENV KCONFIG_NOTIMESTAMP=1 +ENV PS1="bootstrap$ " diff --git a/rootfs.py b/rootfs.py index ac24c932a..63b6568b0 100755 --- a/rootfs.py +++ b/rootfs.py @@ -175,6 +175,9 @@ def check_types(): else: args.target_size = 0 + if args.docker: + args.external_sources = True + # Swap file size validation if args.qemu or args.bare_metal: args.swap = (int(str(args.swap).rstrip('gGmM')) * @@ -259,9 +262,13 @@ def bootstrap(args, generator, target, size, cleanup): arch = stage0_arch_map.get(args.arch, args.arch) init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed') print(generator.target_dir, init) - run('env', '-i', 'DOCKER_BUILDKIT=1', 'docker', 'build', + run('env', '-i', 'DOCKER_BUILDKIT=1', 'SOURCE_DATE_EPOCH=1', + 'docker', 'build', + '--build-arg=SOURCE_DATE_EPOCH=1', '--progress=plain', - '-t', 'local/live', + '--platform=linux/amd64', + '--target=package', + '-t', 'local/live-bootstrap', '.') elif args.bwrap: From 4d95de08a0acf4ab446ea3c48b835a14948637b4 Mon Sep 17 00:00:00 2001 From: "Lance R. Vick" Date: Wed, 24 Jan 2024 16:02:54 -0800 Subject: [PATCH 4/7] use long options for docker --- rootfs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootfs.py b/rootfs.py index 63b6568b0..8a028bd45 100755 --- a/rootfs.py +++ b/rootfs.py @@ -268,7 +268,7 @@ def bootstrap(args, generator, target, size, cleanup): '--progress=plain', '--platform=linux/amd64', '--target=package', - '-t', 'local/live-bootstrap', + '--tag', 'local/live-bootstrap', '.') elif args.bwrap: From 6074e77186a7be1e4893a9e9d4393b877e30a05b Mon Sep 17 00:00:00 2001 From: "Lance R. Vick" Date: Wed, 24 Jan 2024 16:58:46 -0800 Subject: [PATCH 5/7] License headers --- .dockerignore | 6 +++++- Dockerfile | 4 ++++ rootfs.py | 1 + 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index 503659943..69dc40149 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,6 @@ -* +# SPDX-FileCopyrightText: 2024 Lance Vick +# +# SPDX-License-Identifier: GPL-3.0-or-later + + !target diff --git a/Dockerfile b/Dockerfile index 1d47d90fb..4742fdbab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,3 +1,7 @@ +# SPDX-FileCopyrightText: 2024 Lance Vick +# +# SPDX-License-Identifier: GPL-3.0-or-later + FROM scratch as build ADD target/ / RUN ["/bootstrap-seeds/POSIX/x86/kaem-optional-seed"] diff --git a/rootfs.py b/rootfs.py index 8a028bd45..a4eb2236c 100755 --- a/rootfs.py +++ b/rootfs.py @@ -13,6 +13,7 @@ # SPDX-FileCopyrightText: 2021 Melg Eight # SPDX-FileCopyrightText: 2021-23 Samuel Tyler # SPDX-FileCopyrightText: 2023-24 Gábor Stefanik +# SPDX-FileCopyrightText: 2024 Lance Vick import argparse import os From 35d421139f72b5821e9d02b773618389b83967fa Mon Sep 17 00:00:00 2001 From: Kevin Nause Date: Tue, 2 Dec 2025 10:33:52 -0500 Subject: [PATCH 6/7] Fixes based on feedback in PR #413 --- Dockerfile | 47 ++++++++++++++++++++++++------ README.rst | 13 +++++++-- rootfs.py | 25 +++++++++------- steps/improve/finalize_fhs.sh | 54 +++++++++++++++++++++++++++++++++-- 4 files changed, 115 insertions(+), 24 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4742fdbab..01e8ad3e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,54 @@ # SPDX-FileCopyrightText: 2024 Lance Vick +# SPDX-FileCopyrightText: 2025 Kevin Nause # # SPDX-License-Identifier: GPL-3.0-or-later -FROM scratch as build -ADD target/ / +ARG ARCH=x86 +ARG USER=user +ARG UID=1000 +ARG GID=1000 +ARG HOME=/home/${USER} + +FROM scratch AS build +ARG TARGET +ARG INIT +COPY ${TARGET} / + +FROM build AS build-aarch64 +RUN ["/bootstrap-seeds/POSIX/AArch64/kaem-optional-seed"] + +FROM build AS build-amd64 +RUN ["/bootstrap-seeds/POSIX/AMD64/kaem-optional-seed"] + +FROM build AS build-riscv32 +RUN ["/bootstrap-seeds/POSIX/riscv32/kaem-optional-seed"] + +FROM build AS build-riscv64 +RUN ["/bootstrap-seeds/POSIX/riscv64/kaem-optional-seed"] + +FROM build AS build-x86 RUN ["/bootstrap-seeds/POSIX/x86/kaem-optional-seed"] -FROM build as install +FROM build-${ARCH} AS install +ARG USER +ARG UID +ARG GID +ARG HOME ENV PATH=/bin:/usr/sbin:/usr/bin -RUN set -eux; \ +RUN set -eu; \ rm -rf /usr/lib/python*/__pycache__; \ - mkdir -p /rootfs/etc /rootfs/home/user; \ + mkdir -p /rootfs/etc /rootfs/${HOME}; \ cp -R $(ls -d /etc/* | grep -v '\(resolv.conf\|hosts\)') /rootfs/etc/; \ cp -R lib usr bin var /rootfs/; \ - echo "user:x:1000:" > /rootfs/etc/group; \ - echo "user:x:1000:1000::/home/user:/bin/bash" > /rootfs/etc/passwd; \ + echo "${USER}:x:${GID}:" > /rootfs/etc/group; \ + echo "${USER}:x:${UID}:${GID}::${HOME}:/bin/bash" > /rootfs/etc/passwd; \ find /rootfs -exec touch -hcd "@0" "{}" + -FROM scratch as package +FROM scratch AS package +ARG UID +ARG GID COPY --from=install /rootfs / -USER 1000:1000 +USER ${UID}:${GID} ENTRYPOINT ["/bin/bash"] ENV TZ=UTC ENV LANG=C.UTF-8 diff --git a/README.rst b/README.rst index 154c860c3..4b5b7de81 100644 --- a/README.rst +++ b/README.rst @@ -33,8 +33,8 @@ Without using Python: passing it to ``rootfs.py```). 1. ``git clone https://github.com/fosslinux/live-bootstrap`` 2. ``git submodule update --init --recursive`` -3. Consider whether you are going to run this in a chroot, in QEMU, or on bare - metal. (All of this *can* be automated, but not in a trustable way. See +3. Consider whether you are going to run this in a chroot, in QEMU, on bare + metal, or docker. (All of this *can* be automated, but not in a trustable way. See further below.) a. **chroot:** Create a directory where the chroot will reside, run @@ -73,6 +73,15 @@ Without using Python: (``-nic user,model=e1000``), and ``-machine kernel-irqchip=split``. c. **Bare metal:** Follow the same steps as QEMU, but the disks need to be two different *physical* disks, and boot from the first disk. + d. **Docker:** Follow the same steps as chroot. To debug build errors, see + [docker buildx debug](https://docs.docker.com/reference/cli/docker/buildx/debug/). + + ```bash + DOCKER_BUILDKIT=1 BUILDX_EXPERIMENTAL=1 \ + docker buildx debug --invoke /bin/sh build \ + --build-arg=ARCH=x86 --build-arg=TARGET=target/ --build-arg=SOURCE_DATE_EPOCH=1 \ + --progress=auto --platform=linux/amd64 --target=install --tag=live-bootstrap-debug . + ``` Mirrors ------- diff --git a/rootfs.py b/rootfs.py index a4eb2236c..2f9822f04 100755 --- a/rootfs.py +++ b/rootfs.py @@ -14,6 +14,7 @@ # SPDX-FileCopyrightText: 2021-23 Samuel Tyler # SPDX-FileCopyrightText: 2023-24 Gábor Stefanik # SPDX-FileCopyrightText: 2024 Lance Vick +# SPDX-FileCopyrightText: 2025 Kevin Nause import argparse import os @@ -42,8 +43,8 @@ def create_configuration_file(args): config.write(f"FINAL_JOBS={args.cores}\n") config.write(f"INTERNAL_CI={args.internal_ci or False}\n") config.write(f"INTERACTIVE={args.interactive}\n") - config.write(f"BARE_METAL={args.bare_metal}\n") - config.write(f"EXTERNAL_SOURCES={args.external_sources}\n") + config.write(f"QEMU={args.qemu}\n") + config.write(f"BARE_METAL={args.bare_metal or (args.qemu and args.interactive)}\n") if (args.bare_metal or args.qemu) and not args.kernel: if args.repo or args.external_sources: config.write("DISK=sdb1\n") @@ -262,15 +263,17 @@ def bootstrap(args, generator, target, size, cleanup): generator.prepare(target, using_kernel=False) arch = stage0_arch_map.get(args.arch, args.arch) init = os.path.join(os.sep, 'bootstrap-seeds', 'POSIX', arch, 'kaem-optional-seed') - print(generator.target_dir, init) - run('env', '-i', 'DOCKER_BUILDKIT=1', 'SOURCE_DATE_EPOCH=1', - 'docker', 'build', - '--build-arg=SOURCE_DATE_EPOCH=1', - '--progress=plain', - '--platform=linux/amd64', - '--target=package', - '--tag', 'local/live-bootstrap', - '.') + target_rel = os.path.relpath(generator.target_dir, os.getcwd()) + run('env', '-i', 'DOCKER_BUILDKIT=1', + 'docker', 'build', + '--build-arg=ARCH='+ arch, + '--build-arg=TARGET=' + target_rel, + '--build-arg=SOURCE_DATE_EPOCH=1', + '--progress=auto', + '--platform=linux/amd64', + '--target=package', + '--tag=live-bootstrap', + '.') elif args.bwrap: init = '/init' diff --git a/steps/improve/finalize_fhs.sh b/steps/improve/finalize_fhs.sh index 6c5e6d514..94658ab04 100755 --- a/steps/improve/finalize_fhs.sh +++ b/steps/improve/finalize_fhs.sh @@ -16,8 +16,58 @@ mount | grep '/sys' &> /dev/null || (mkdir -p /sys; mount -t sysfs sysfs /sys) mount | grep '/tmp' &> /dev/null || (mkdir -p /tmp; mount -t tmpfs tmpfs /tmp) mount | grep '/dev/shm' &> /dev/null || (mkdir -p /dev/shm; mount -t tmpfs tmpfs /dev/shm) -if [ "${EXTERNAL_SOURCES}" = "False" ]; then - # Add /etc/resolv.conf +if [ "${CHROOT}" = False ]; then + rm /etc/mtab + ln -s /proc/mounts /etc/mtab +fi + +# Add /etc/resolv.conf +if [ ! -e "/etc/resolv.conf" ]; then echo 'nameserver 1.1.1.1' > /etc/resolv.conf +fi +if [ ! -e "/etc/resolv.conf/head" ]; then echo 'nameserver 1.1.1.1' > /etc/resolv.conf.head fi + +# /etc/passwd -- taken from LFS +if [ ! -e "/etc/passwd" ]; then + cat > /etc/passwd << "EOF" +root:x:0:0:root:/root:/bin/bash +bin:x:1:1:bin:/dev/null:/usr/bin/false +daemon:x:6:6:Daemon User:/dev/null:/usr/bin/false +messagebus:x:18:18:D-Bus Message Daemon User:/run/dbus:/usr/bin/false +uuidd:x:80:80:UUID Generation Daemon User:/dev/null:/usr/bin/false +nobody:x:65534:65534:Unprivileged User:/dev/null:/usr/bin/false +EOF +fi + +# /etc/group -- taken from LFS +if [ ! -e "/etc/group" ]; then + cat > /etc/group << "EOF" +root:x:0: +bin:x:1:daemon +sys:x:2: +kmem:x:3: +tape:x:4: +tty:x:5: +daemon:x:6: +floppy:x:7: +disk:x:8: +lp:x:9: +dialout:x:10: +audio:x:11: +video:x:12: +utmp:x:13: +usb:x:14: +cdrom:x:15: +adm:x:16: +messagebus:x:18: +input:x:24: +mail:x:34: +kvm:x:61: +uuidd:x:80: +wheel:x:97: +users:x:999: +nogroup:x:65534: +EOF +fi From 8e2d95c59218b2aba4350fe1bc28df5ab424219b Mon Sep 17 00:00:00 2001 From: Kevin Nause Date: Sat, 6 Dec 2025 15:20:55 -0500 Subject: [PATCH 7/7] Added arch to docker tag --- rootfs.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rootfs.py b/rootfs.py index 2f9822f04..24b8c9fda 100755 --- a/rootfs.py +++ b/rootfs.py @@ -270,9 +270,9 @@ def bootstrap(args, generator, target, size, cleanup): '--build-arg=TARGET=' + target_rel, '--build-arg=SOURCE_DATE_EPOCH=1', '--progress=auto', - '--platform=linux/amd64', + '--platform=linux/amd64,linux/arm64,linux/i386,linux/riscv64', '--target=package', - '--tag=live-bootstrap', + '--tag=live-bootstrap-' + arch, '.') elif args.bwrap: