diff --git a/.github/workflows/build-and-test.yaml b/.github/workflows/build-and-test.yaml index 4ebef9f..2a653f1 100644 --- a/.github/workflows/build-and-test.yaml +++ b/.github/workflows/build-and-test.yaml @@ -22,6 +22,8 @@ jobs: arch: arm64 runs-on: ${{ matrix.runner }} timeout-minutes: 30 + env: + APT_MIRROR: http://azure.archive.ubuntu.com/ubuntu/ steps: - name: Checkout repository diff --git a/.github/workflows/build-oci.yaml b/.github/workflows/build-oci.yaml index 9ebca8f..96b3343 100644 --- a/.github/workflows/build-oci.yaml +++ b/.github/workflows/build-oci.yaml @@ -37,6 +37,8 @@ jobs: runs-on: ${{ matrix.runner }} # NOTE: 90 min covers the qemu lanes; native lanes finish well under 30. timeout-minutes: 90 + env: + APT_MIRROR: http://azure.archive.ubuntu.com/ubuntu/ steps: - name: Checkout repository @@ -58,7 +60,7 @@ jobs: uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0 with: path: images-out/ - key: images-${{ matrix.arch }}-${{ hashFiles('images/Dockerfile.*', 'hack/bread-warning.sh', 'hack/banner.txt', 'hack/lazy-apt.sh', 'hack/build_image.sh', '.stamp/binaries') }} + key: images-${{ matrix.arch }}-${{ hashFiles('images/Dockerfile.*', 'hack/bread-warning.sh', 'hack/banner.txt', 'hack/lazy-apt.sh', 'hack/apt-mirror.sh', 'hack/build_image.sh', '.stamp/binaries') }} - name: Set up qemu (emulated arches only) if: matrix.qemu && steps.images-cache.outputs.cache-hit != 'true' diff --git a/README.md b/README.md index da1355e..6447894 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ spread-bread/ check_base.sh # detect upstream ubuntu base digest drift; rewrite @sha256 pins inline_scripts.rb # splice scripts/*.sh into yaml templates tar-shim.sh # image /bin/tar; routes extraction to bsdtar where gnu tar is broken + apt-mirror.sh # build-time apt mirror override, bind-mounted into image builds by ci scripts/ # allocate / discard scripts, one pair per flavour images/ # one Dockerfile per (flavour, ubuntu version) templates/ # yaml templates with `source scripts/...` markers diff --git a/hack/apt-mirror.sh b/hack/apt-mirror.sh new file mode 100755 index 0000000..a017804 --- /dev/null +++ b/hack/apt-mirror.sh @@ -0,0 +1,30 @@ +#!/bin/sh -e +# bread-apt-mirror: build-time apt mirror override for docker build, which +# otherwise pulls from archive.ubuntu.com; on ci that is the slow path, while +# the runner itself uses the azure mirror. Same mirror, same failover shape: +# https://github.com/actions/runner-images/blob/main/images/ubuntu/scripts/build/configure-apt-sources.sh +# https://manpages.ubuntu.com/manpages/noble/en/man1/apt-transport-mirror.1.html +# +# Writes into the scratch dir $1 copies of the apt sources with the archive +# uris pointed at a mirrorlist ($APT_MIRROR first, archive.ubuntu.com second) +# plus an apt.conf that makes apt read those copies; the build exports +# APT_CONFIG=/apt.conf. The image's own /etc/apt is never touched. +# Without APT_MIRROR the apt.conf is empty and apt behaves as stock. +# +# Usage: bread-apt-mirror + +dir="${1:?scratch dir required}" +mkdir -p "$dir/sources.list.d" +: > "$dir/apt.conf" +[ -n "${APT_MIRROR:-}" ] || exit 0 + +list="$dir/mirrors.txt" +printf '%s\tpriority:1\nhttp://archive.ubuntu.com/ubuntu/\tpriority:2\n' "$APT_MIRROR" > "$list" + +: > "$dir/sources.list" +for f in /etc/apt/sources.list /etc/apt/sources.list.d/*.list /etc/apt/sources.list.d/*.sources; do + [ -f "$f" ] || continue + sed "s|http://archive\.ubuntu\.com/ubuntu/|mirror+file:$list|g" "$f" > "$dir/${f#/etc/apt/}" +done + +printf 'Dir::Etc::sourcelist "%s/sources.list";\nDir::Etc::sourceparts "%s/sources.list.d";\n' "$dir" "$dir" > "$dir/apt.conf" diff --git a/hack/build_image.sh b/hack/build_image.sh index 7b890e5..aea3222 100755 --- a/hack/build_image.sh +++ b/hack/build_image.sh @@ -30,6 +30,7 @@ case "$flavour" in bread) docker build \ --tag "bread:$ver-$arch" \ + --build-arg "APT_MIRROR=${APT_MIRROR:-}" \ --file "images/Dockerfile.bread-$ver" \ --platform "linux/$arch" \ . @@ -38,6 +39,7 @@ case "$flavour" in docker build \ --tag "bread-chisel-releases:$ver-$arch" \ --build-arg "BASE_TAG=$ver-$arch" \ + --build-arg "APT_MIRROR=${APT_MIRROR:-}" \ --build-arg "BUILD_ARCH=$arch" \ --file "images/Dockerfile.bread-chisel-releases-$ver" \ --platform "linux/$arch" \ diff --git a/hack/hash_inputs.sh b/hack/hash_inputs.sh index ad3edd4..262b0c6 100755 --- a/hack/hash_inputs.sh +++ b/hack/hash_inputs.sh @@ -40,12 +40,14 @@ case "$flavour" in "hack/bread-warning.sh" "hack/banner.txt" "hack/tar-shim.sh" + "hack/apt-mirror.sh" ) ;; bread-chisel-releases) inputs=( "images/Dockerfile.bread-chisel-releases-$ver" "hack/lazy-apt.sh" + "hack/apt-mirror.sh" ".stamp/bread-$ver-$arch" ".stamp/binaries" ) diff --git a/images/Dockerfile.bread-22.04 b/images/Dockerfile.bread-22.04 index 4c6e109..972b72a 100644 --- a/images/Dockerfile.bread-22.04 +++ b/images/Dockerfile.bread-22.04 @@ -2,14 +2,19 @@ FROM docker.io/library/ubuntu:22.04@sha256:829f6df217bcbae2b371026e81711d1a787c61b2967ad09d015063663ebafbf7 +ARG APT_MIRROR= + # Skip man/doc/info install for every subsequent package -- dpkg's man-db # trigger is a major cost under qemu emulation (s390x / ppc64le). Persists in # the image fs, so the bread-chisel-releases install inherits the exclusion. -RUN printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ > /etc/dpkg/dpkg.cfg.d/01-nodoc && \ apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssh-server libarchive-tools && \ - mkdir /var/run/sshd || true && \ + mkdir -p /var/run/sshd && \ echo 'root:bread' | chpasswd && \ echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \ diff --git a/images/Dockerfile.bread-24.04 b/images/Dockerfile.bread-24.04 index 46b41d9..7553b4f 100644 --- a/images/Dockerfile.bread-24.04 +++ b/images/Dockerfile.bread-24.04 @@ -2,14 +2,19 @@ FROM docker.io/library/ubuntu:24.04@sha256:224a1869083a311ef3f13648a154ba79832fbef6364d31493642ca03082da254 +ARG APT_MIRROR= + # Skip man/doc/info install for every subsequent package -- dpkg's man-db # trigger is a major cost under qemu emulation (s390x / ppc64le). Persists in # the image fs, so the bread-chisel-releases install inherits the exclusion. -RUN printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ > /etc/dpkg/dpkg.cfg.d/01-nodoc && \ apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssh-server libarchive-tools && \ - mkdir /var/run/sshd || true && \ + mkdir -p /var/run/sshd && \ echo 'root:bread' | chpasswd && \ echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \ diff --git a/images/Dockerfile.bread-25.10 b/images/Dockerfile.bread-25.10 index 8d5df43..0ec91ed 100644 --- a/images/Dockerfile.bread-25.10 +++ b/images/Dockerfile.bread-25.10 @@ -2,14 +2,19 @@ FROM docker.io/library/ubuntu:25.10@sha256:7cc5e35f6567ee8c66d2abb4aab0fd866669e6207c237c3a8f0947a5c7f17092 +ARG APT_MIRROR= + # Skip man/doc/info install for every subsequent package -- dpkg's man-db # trigger is a major cost under qemu emulation (s390x / ppc64le). Persists in # the image fs, so the bread-chisel-releases install inherits the exclusion. -RUN printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ > /etc/dpkg/dpkg.cfg.d/01-nodoc && \ apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssh-server libarchive-tools && \ - mkdir /var/run/sshd || true && \ + mkdir -p /var/run/sshd && \ echo 'root:bread' | chpasswd && \ echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \ diff --git a/images/Dockerfile.bread-26.04 b/images/Dockerfile.bread-26.04 index 3a16769..8db13b3 100644 --- a/images/Dockerfile.bread-26.04 +++ b/images/Dockerfile.bread-26.04 @@ -2,14 +2,19 @@ FROM docker.io/library/ubuntu:26.04@sha256:513c074113a871b51a8d16ab445c88779d6452d937a164fb5cc479f32668a41d +ARG APT_MIRROR= + # Skip man/doc/info install for every subsequent package -- dpkg's man-db # trigger is a major cost under qemu emulation (s390x / ppc64le). Persists in # the image fs, so the bread-chisel-releases install inherits the exclusion. -RUN printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ > /etc/dpkg/dpkg.cfg.d/01-nodoc && \ apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssh-server libarchive-tools && \ - mkdir /var/run/sshd || true && \ + mkdir -p /var/run/sshd && \ echo 'root:bread' | chpasswd && \ echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \ diff --git a/images/Dockerfile.bread-26.10 b/images/Dockerfile.bread-26.10 index 4a8efaf..b6521fe 100644 --- a/images/Dockerfile.bread-26.10 +++ b/images/Dockerfile.bread-26.10 @@ -2,14 +2,19 @@ FROM docker.io/library/ubuntu:26.10@sha256:49077a16b772f8bc6e6f160ad2bfc218919f3455037387ed19a8309174328603 +ARG APT_MIRROR= + # Skip man/doc/info install for every subsequent package -- dpkg's man-db # trigger is a major cost under qemu emulation (s390x / ppc64le). Persists in # the image fs, so the bread-chisel-releases install inherits the exclusion. -RUN printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + printf 'path-exclude /usr/share/man/*\npath-exclude /usr/share/doc/*\npath-exclude /usr/share/info/*\n' \ > /etc/dpkg/dpkg.cfg.d/01-nodoc && \ apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends openssh-server libarchive-tools && \ - mkdir /var/run/sshd || true && \ + mkdir -p /var/run/sshd && \ echo 'root:bread' | chpasswd && \ echo "PermitRootLogin yes" >> /etc/ssh/sshd_config && \ echo "PasswordAuthentication yes" >> /etc/ssh/sshd_config && \ diff --git a/images/Dockerfile.bread-chisel-releases-22.04 b/images/Dockerfile.bread-chisel-releases-22.04 index c55d086..0f76c7c 100644 --- a/images/Dockerfile.bread-chisel-releases-22.04 +++ b/images/Dockerfile.bread-chisel-releases-22.04 @@ -9,8 +9,12 @@ ARG BASE_TAG=22.04-amd64 ARG BUILD_ARCH=amd64 FROM bread:${BASE_TAG} ARG BUILD_ARCH +ARG APT_MIRROR= -RUN apt-get update && \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ curl wget git jq file sudo tree \ skopeo iproute2 && \ diff --git a/images/Dockerfile.bread-chisel-releases-24.04 b/images/Dockerfile.bread-chisel-releases-24.04 index 5a0b848..0db0b3b 100644 --- a/images/Dockerfile.bread-chisel-releases-24.04 +++ b/images/Dockerfile.bread-chisel-releases-24.04 @@ -9,8 +9,12 @@ ARG BASE_TAG=24.04-amd64 ARG BUILD_ARCH=amd64 FROM bread:${BASE_TAG} ARG BUILD_ARCH +ARG APT_MIRROR= -RUN apt-get update && \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ curl wget git jq file sudo tree \ skopeo iproute2 && \ diff --git a/images/Dockerfile.bread-chisel-releases-25.10 b/images/Dockerfile.bread-chisel-releases-25.10 index cda0585..c85c322 100644 --- a/images/Dockerfile.bread-chisel-releases-25.10 +++ b/images/Dockerfile.bread-chisel-releases-25.10 @@ -9,8 +9,12 @@ ARG BASE_TAG=25.10-amd64 ARG BUILD_ARCH=amd64 FROM bread:${BASE_TAG} ARG BUILD_ARCH +ARG APT_MIRROR= -RUN apt-get update && \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ curl wget git jq file sudo tree \ skopeo iproute2 && \ diff --git a/images/Dockerfile.bread-chisel-releases-26.04 b/images/Dockerfile.bread-chisel-releases-26.04 index 8fc1544..1c979f6 100644 --- a/images/Dockerfile.bread-chisel-releases-26.04 +++ b/images/Dockerfile.bread-chisel-releases-26.04 @@ -9,8 +9,12 @@ ARG BASE_TAG=26.04-amd64 ARG BUILD_ARCH=amd64 FROM bread:${BASE_TAG} ARG BUILD_ARCH +ARG APT_MIRROR= -RUN apt-get update && \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ curl wget git jq file sudo tree \ skopeo iproute2 && \ diff --git a/images/Dockerfile.bread-chisel-releases-26.10 b/images/Dockerfile.bread-chisel-releases-26.10 index 541c279..a26f87b 100644 --- a/images/Dockerfile.bread-chisel-releases-26.10 +++ b/images/Dockerfile.bread-chisel-releases-26.10 @@ -9,8 +9,12 @@ ARG BASE_TAG=26.10-amd64 ARG BUILD_ARCH=amd64 FROM bread:${BASE_TAG} ARG BUILD_ARCH +ARG APT_MIRROR= -RUN apt-get update && \ +RUN --mount=type=bind,source=hack/apt-mirror.sh,target=/usr/local/bin/bread-apt-mirror \ + --mount=type=tmpfs,target=/run/apt-mirror \ + export APT_CONFIG=/run/apt-mirror/apt.conf && bread-apt-mirror /run/apt-mirror && \ + apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ curl wget git jq file sudo tree \ skopeo iproute2 && \