Skip to content

Commit 2eb2eab

Browse files
committed
ci: make containers reproducible
Make containers reproducible by: * using a dated debian tag; and * enabling the snapshot server URL * enabling SOURCE_DATE_EPOCH and container file timestamping * using a tmpfs for /var/log * removing unreproducible files The instructions are heavily influenced by [1]. Add git `safe.directory` exemptions everywhere in case the `/src` filesystem is mounted as a different uid. This is very common in containerized build environments. Also move each container into its own build context directory. The filesystem layout now matches the container registry URL. Containerization is an unending time sink—there is always something more to be done. [1]: siemens/kas@bb51bd7
1 parent e8d0f3a commit 2eb2eab

8 files changed

Lines changed: 102 additions & 37 deletions

File tree

.github/container/Dockerfile.rust.aarch64-unknown-linux-gnu renamed to .github/container/aarch64-unknown-linux-gnu/Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
FROM ghcr.io/cbs228/sameold/builder/rust:latest
66

7-
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
7+
ARG SOURCE_DATE_EPOCH
8+
9+
RUN --mount=target=/var/lib/apt,type=cache,sharing=locked \
810
--mount=target=/var/cache/apt,type=cache,sharing=locked \
11+
--mount=destination=/var/log,type=tmpfs \
912
[ "$(dpkg --print-architecture)" != arm64 ] || exit 0; \
1013
set -eux; \
1114
apt-get update; \
@@ -14,7 +17,8 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
1417
gcc-aarch64-linux-gnu \
1518
libc6-dev-arm64-cross \
1619
libc6:arm64 \
17-
;
20+
; \
21+
rm -f -- /etc/machine-id /var/cache/ldconfig/aux-cache
1822

1923
ARG RUST_TARGET="aarch64-unknown-linux-gnu"
2024

.github/container/Dockerfile.rust.armv7-unknown-linux-gnueabihf renamed to .github/container/armv7-unknown-linux-gnueabihf/Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
FROM ghcr.io/cbs228/sameold/builder/rust:latest
66

7-
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
7+
ARG SOURCE_DATE_EPOCH
8+
9+
RUN --mount=target=/var/lib/apt,type=cache,sharing=locked \
810
--mount=target=/var/cache/apt,type=cache,sharing=locked \
11+
--mount=destination=/var/log,type=tmpfs \
912
[ "$(dpkg --print-architecture)" != armhf ] || exit 0; \
1013
set -eux; \
1114
apt-get update; \
@@ -14,7 +17,8 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
1417
gcc-arm-linux-gnueabihf \
1518
libc6-dev-armhf-cross \
1619
libc6:armhf \
17-
;
20+
; \
21+
rm -f -- /etc/machine-id /var/cache/ldconfig/aux-cache
1822

1923
ARG RUST_TARGET="armv7-unknown-linux-gnueabihf"
2024

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,41 @@
22
# Debian base image
33
#
44

5-
ARG DEBIAN_SUITE=buster
5+
# or buster-20240612-slim for a snapshot-capable, reproducible image
6+
ARG DEBIAN_TAG=buster-slim
67

7-
FROM docker.io/library/debian:${DEBIAN_SUITE}-slim
8+
FROM docker.io/library/debian:${DEBIAN_TAG}
9+
10+
ARG DEBIAN_TAG
11+
ARG SOURCE_DATE_EPOCH
812

913
# Create a non-root user for running builds
1014
# GHA wants uid 1001
1115
ARG UID=1001
1216

13-
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
17+
RUN --mount=target=/var/lib/apt,type=cache,sharing=locked \
1418
--mount=target=/var/cache/apt,type=cache,sharing=locked \
19+
--mount=destination=/var/log,type=tmpfs \
1520
set -eux; \
1621
# create an unprivileged user for builds
17-
useradd -u "$UID" --create-home --user-group builder; \
22+
groupadd builder -g "$UID"; \
23+
useradd builder -u "$UID" -g "$UID" --create-home; \
1824
# build directories for any user
1925
mkdir -m 1777 /src /install /cargo; \
2026
# re-enable apt caching (we have a cache mount)
2127
rm -f /etc/apt/apt.conf.d/docker-clean; \
28+
# if tag contains numerics, like buster-20240612-slim, use the
29+
# snapshot URL that's baked into the image
30+
if echo "${DEBIAN_TAG}" | grep -q "[0-9]"; then \
31+
sed -i -r \
32+
-e 's/^deb/# deb/' \
33+
-e 's|^#\s*(.*http://snapshot\.)|\1|' \
34+
/etc/apt/sources.list; \
35+
cat >&2 /etc/apt/sources.list; \
36+
echo 'Acquire::Check-Valid-Until "false";' > /etc/apt/apt.conf.d/use-snapshot.conf; \
37+
echo 'Acquire::Retries "10";' >> /etc/apt/apt.conf.d/use-snapshot.conf; \
38+
echo 'Acquire::Retries::Delay::Maximum "600";' >> /etc/apt/apt.conf.d/use-snapshot.conf; \
39+
fi; \
2240
# enable packages from multiple architectures
2341
dpkg --add-architecture amd64; \
2442
dpkg --add-architecture armhf; \
@@ -36,8 +54,9 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
3654
qemu-user \
3755
qemu-user-binfmt \
3856
tar \
39-
zstd \
40-
;
57+
zstd; \
58+
git config --system --add safe.directory '*'; \
59+
rm -f -- /etc/machine-id /var/cache/ldconfig/aux-cache
4160

4261
# Directories for sources and installed binaries
4362
VOLUME ["/src", "/install"]

.github/container/build.sh

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@
44
#
55
# run with --push to push the images.
66

7-
now="$(date -u +'%Y-%m-%d')"
7+
# set to disable cache
8+
NO_CACHE="${NO_CACHE:-}"
89

10+
DEBIAN_TAG="buster-20240612-slim"
911
CONTAINER_PREFIX="ghcr.io/cbs228"
1012
CONTAINER_FQNAME="${CONTAINER_PREFIX}/sameold/builder/%s"
11-
CONTAINER_TAGS=("$now" "latest")
1213

1314
RUST_VERSIONS=("1.84.0")
1415

@@ -60,6 +61,28 @@ container_name() {
6061
printf "$CONTAINER_FQNAME" "$1"
6162
}
6263

64+
buildcontainer() {
65+
# Usage: buildcontainer ARGS
66+
#
67+
# Run the $BUILDER to build a container image. Some standardized
68+
# arguments are passed to every build.
69+
70+
if [[ $BUILDER =~ podman$ ]]; then
71+
run "$BUILDER" build \
72+
--build-arg SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
73+
--timestamp "$SOURCE_DATE_EPOCH" \
74+
${NO_CACHE:+--no-cache} \
75+
"$@"
76+
else
77+
# docker mode; 100% untested
78+
run "$BUILDER" buildx build \
79+
--build-arg SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" \
80+
--output type=docker,rewrite-timestamp=true \
81+
${NO_CACHE:+--no-cache} \
82+
"$@"
83+
fi
84+
}
85+
6386
tagall() {
6487
# Usage: tagall SHORTNAME TAG0 TAG1 ...
6588
#
@@ -115,54 +138,59 @@ while true; do
115138
done
116139

117140
BUILDER="$(container_builder)"
118-
selfdir="$(dirname "${0?}")"
141+
selfdir="$(dirname "$(realpath -e "${0?}")")"
142+
143+
# set SOURCE_DATE_EPOCH if possible
144+
SOURCE_DATE_EPOCH="${SOURCE_DATE_EPOCH:-$(git log -1 --pretty=%ct -- "$selfdir" || date +%s)}"
145+
export SOURCE_DATE_EPOCH
146+
147+
# tag with "latest" and SOURCE_DATE_EPOCH
148+
CONTAINER_TAGS=("latest" "$(date --date '@'"$SOURCE_DATE_EPOCH" +'%Y-%m-%d')")
119149

120150
# build the base image
121151
base_tag="$(container_name base):${CONTAINER_TAGS[0]}"
122152

123-
run "$BUILDER" build \
124-
-f "${selfdir?}/Dockerfile.base" \
153+
buildcontainer \
154+
--build-arg DEBIAN_TAG="$DEBIAN_TAG" \
125155
--tag "$base_tag" \
126-
"${selfdir?}"
156+
"${selfdir?}/base"
127157

128158
# add rust to the base image
129159
rust_tag="$(container_name rust):${CONTAINER_TAGS[0]}"
130160

131-
run "$BUILDER" build \
132-
-f "${selfdir?}/Dockerfile.rust" \
161+
buildcontainer \
133162
--from "$base_tag" \
134163
--build-arg RUST_VERSIONS="${RUST_VERSIONS[*]}" \
135164
--tag "$rust_tag" \
136-
"${selfdir?}"
165+
"${selfdir?}/rust"
137166

138167
# build architecture-specific images
139-
for containerfile in "${selfdir}/"Dockerfile.rust.*; do
140-
platform_triple="${containerfile##*.}"
168+
for containerdir in "${selfdir?}/"*-*-*; do
169+
[ -d "$containerdir" ] || continue
170+
171+
platform_triple="$(basename ${containerdir})"
141172
cur_tag="$(container_name "$platform_triple"):${CONTAINER_TAGS[0]}"
142173

143-
run "$BUILDER" build \
174+
buildcontainer \
144175
--from "$rust_tag" \
145-
-f "${containerfile}" \
146176
--tag "${cur_tag}" \
147-
"${selfdir?}"
177+
"${containerdir}"
148178
done
149179

150180
# if all builds succeed, apply remaining tags...
151181
tagall base "${CONTAINER_TAGS[@]}"
152182
tagall rust "${CONTAINER_TAGS[@]}"
153-
for containerfile in "${selfdir}/"Dockerfile.rust.*; do
154-
platform_triple="${containerfile##*.}"
183+
for containerdir in "${selfdir?}/"*-*-*; do
184+
[ -d "$containerdir" ] || continue
155185

156-
tagall "$platform_triple" "${CONTAINER_TAGS[@]}"
186+
tagall "$(basename "$containerdir")" "${CONTAINER_TAGS[@]}"
157187
done
158188

159189
[ -n "${push_images:-}" ] || exit 0
160190

161191
# ... and push
162-
pushall base "${CONTAINER_TAGS[@]}"
163-
pushall rust "${CONTAINER_TAGS[@]}"
164-
for containerfile in "${selfdir}/"Dockerfile.rust.*; do
165-
platform_triple="${containerfile##*.}"
192+
for containerdir in "${selfdir?}/"*; do
193+
[ -d "$containerdir" ] || continue
166194

167-
pushall "$platform_triple" "${CONTAINER_TAGS[@]}"
195+
pushall "$(basename "$containerdir")" "${CONTAINER_TAGS[@]}"
168196
done

.github/container/Dockerfile.rust.i686-unknown-linux-gnu renamed to .github/container/i686-unknown-linux-gnu/Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
FROM ghcr.io/cbs228/sameold/builder/rust:latest
66

7-
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
7+
ARG SOURCE_DATE_EPOCH
8+
9+
RUN --mount=target=/var/lib/apt,type=cache,sharing=locked \
810
--mount=target=/var/cache/apt,type=cache,sharing=locked \
11+
--mount=destination=/var/log,type=tmpfs \
912
[ "$(dpkg --print-architecture)" != i386 ] || exit 0; \
1013
set -eux; \
1114
apt-get update; \
@@ -14,7 +17,8 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
1417
gcc-i686-linux-gnu \
1518
libc6-dev-i386-cross \
1619
libc6:i386 \
17-
;
20+
; \
21+
rm -f -- /etc/machine-id /var/cache/ldconfig/aux-cache
1822

1923
ARG RUST_TARGET="i686-unknown-linux-gnu"
2024

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44

55
FROM ghcr.io/cbs228/sameold/builder/base:latest
66

7+
ARG SOURCE_DATE_EPOCH
8+
79
# Install rustup and platform-native target
810
#
911
# RUST_VERSIONS: list of version numbers or strings
@@ -52,6 +54,6 @@ RUN set -eux; \
5254
(umask 022 && echo "$RUSTUP_ARCH" >/etc/rust-native-arch)
5355

5456
# Install scripts
55-
COPY rootfiles/ /
57+
COPY rootfiles /
5658

5759
LABEL org.opencontainers.image.description="A pinned Rust toolchain with rustup."

.github/container/rootfiles/usr/local/bin/qemu-run-maybe renamed to .github/container/rust/rootfiles/usr/local/bin/qemu-run-maybe

File renamed without changes.

.github/container/Dockerfile.rust.x86_64-unknown-linux-gnu renamed to .github/container/x86_64-unknown-linux-gnu/Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,11 @@
44

55
FROM ghcr.io/cbs228/sameold/builder/rust:latest
66

7-
RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
7+
ARG SOURCE_DATE_EPOCH
8+
9+
RUN --mount=target=/var/lib/apt,type=cache,sharing=locked \
810
--mount=target=/var/cache/apt,type=cache,sharing=locked \
11+
--mount=destination=/var/log,type=tmpfs \
912
[ "$(dpkg --print-architecture)" != amd64 ] || exit 0; \
1013
set -eux; \
1114
apt-get update; \
@@ -14,7 +17,8 @@ RUN --mount=target=/var/lib/apt/lists,type=cache,sharing=locked \
1417
gcc-x86-64-linux-gnu \
1518
libc6-dev-amd64-cross \
1619
libc6:amd64 \
17-
;
20+
; \
21+
rm -f -- /etc/machine-id /var/cache/ldconfig/aux-cache
1822

1923
ARG RUST_TARGET="x86_64-unknown-linux-gnu"
2024

0 commit comments

Comments
 (0)