Skip to content

Commit c08788c

Browse files
committed
start, introduce a 'min' version of the CI builder image
* min version is much smaller than the the full image, allowing for faster CI startup * updates ci-builder/Dockerfile with the first layer being the 'min' image * update CI jobs to use 'min' image where possible
1 parent 8f8ae3f commit c08788c

File tree

6 files changed

+137
-74
lines changed

6 files changed

+137
-74
lines changed

bin/ci-builder

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ cd "$(dirname "$0")/.."
2424

2525
if [[ $# -lt 2 ]]
2626
then
27-
echo "usage: $0 <command> <stable|nightly> [<args>...]
27+
echo "usage: $0 <command> <stable|nightly|min> [<args>...]
2828
2929
Manages the ci-builder Docker image, which contains the dependencies required
3030
to build, test, and deploy the code in this repository.
@@ -40,25 +40,33 @@ For details, consult ci/builder/README.md."
4040
fi
4141

4242
cmd=$1 && shift
43-
channel=$1 && shift
43+
flavor=$1 && shift
4444

4545
rust_date=
46-
case "$channel" in
47-
stable) rust_version=$(sed -n 's/rust-version = "\(.*\)"/\1/p' Cargo.toml) ;;
46+
case "$flavor" in
47+
min)
48+
docker_target=ci-builder-min
49+
rust_version=$(sed -n 's/rust-version = "\(.*\)"/\1/p' Cargo.toml)
50+
;;
51+
stable)
52+
docker_target=ci-builder-full
53+
rust_version=$(sed -n 's/rust-version = "\(.*\)"/\1/p' Cargo.toml)
54+
;;
4855
nightly)
56+
docker_target=ci-builder-full
4957
rust_version=nightly
5058
rust_date=/$NIGHTLY_RUST_DATE
5159
;;
5260
*)
53-
printf "unknown rust channel %q\n" "$channel"
61+
printf "unknown CI builder flavor %q\n" "$flavor"
5462
exit 1
5563
;;
5664
esac
5765

5866
arch_gcc=${MZ_DEV_CI_BUILDER_ARCH:-$(arch_gcc)}
5967
arch_go=$(arch_go "$arch_gcc")
6068

61-
cid_file=ci/builder/.${channel%%-*}.cidfile
69+
cid_file=ci/builder/.${flavor%%-*}.cidfile
6270

6371
rust_components=rustc,cargo,rust-std-$arch_gcc-unknown-linux-gnu,llvm-tools-preview
6472
if [[ $rust_version = nightly ]]; then
@@ -86,6 +94,7 @@ build() {
8694
--build-arg "BAZEL_VERSION=$bazel_version" \
8795
--tag materialize/ci-builder:"$tag" \
8896
--tag materialize/ci-builder:"$cache_tag" \
97+
--target $docker_target \
8998
"$@" ci/builder
9099
}
91100

@@ -111,6 +120,7 @@ files+="
111120
rust-version:$rust_version
112121
rust-date:$rust_date
113122
arch:$arch_gcc
123+
flavor:$flavor
114124
"
115125
tag=$(echo "$files" | python3 -c '
116126
import base64
@@ -121,7 +131,7 @@ input = sys.stdin.buffer.read()
121131
hash = base64.b32encode(hashlib.sha1(input).digest())
122132
print(hash.decode())
123133
')
124-
cache_tag=cache-$rust_version-$arch_go
134+
cache_tag=cache-$flavor-$rust_version-$arch_go
125135

126136

127137
case "$cmd" in

ci/builder/Dockerfile

Lines changed: 109 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,112 @@
77
# the Business Source License, use of this software will be governed
88
# by the Apache License, Version 2.0.
99

10-
# Build a cross-compiling toolchain that targets the oldest version of Linux
11-
# that we support.
10+
# Stage 1: Build a minimum CI Builder image that we can use for the initial
11+
# steps like `mkpipeline` and `Build`, as well as any tests that are self
12+
# contained and use other Docker images.
13+
FROM ubuntu:noble-20241015 AS ci-builder-min
1214

15+
WORKDIR /workdir
16+
17+
ARG ARCH_GCC
18+
ARG ARCH_GO
19+
20+
# Environment variables that should be set for the entire build container.
21+
22+
# Ensure any Rust binaries that crash print a backtrace.
23+
ENV RUST_BACKTRACE=1
24+
# Ensure that all python output is unbuffered, otherwise it is not
25+
# logged properly in Buildkite.
26+
ENV PYTHONUNBUFFERED=1
27+
# Set a environment variable that tools can check to see if they're in the
28+
# builder or not.
29+
ENV MZ_DEV_CI_BUILDER=1
30+
31+
# Faster uncompression
32+
ARG XZ_OPT=-T0
33+
34+
# Absolute minimum set of dependencies needed for a CI job.
35+
#
36+
# Please take care with what gets added here. The goal of this initial layer is to be as small as
37+
# possible since it's used for the `mkpipeline` and `Build` CI jobs, which block __all other__
38+
# jobs.
39+
RUN apt-get update --fix-missing && TZ=UTC DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
40+
ca-certificates \
41+
curl \
42+
docker.io \
43+
gdb \
44+
git \
45+
gnupg2 \
46+
libxml2 \
47+
python3 \
48+
&& rm -rf /var/lib/apt/lists/*
49+
50+
# Install Python dependencies. These are necessary to run some of our base tooling.
51+
COPY requirements.txt /workdir/
52+
RUN curl -LsSf https://astral.sh/uv/0.4.25/install.sh | UV_INSTALL_DIR=/usr/local UV_UNMANAGED_INSTALL=1 sh \
53+
&& uv pip install --system --break-system-packages -r /workdir/requirements.txt && rm /workdir/requirements*.txt
54+
55+
# Install extra tools not available in apt repositories.
56+
57+
COPY rust.asc .
58+
RUN gpg --import rust.asc \
59+
&& rm rust.asc \
60+
&& echo "trusted-key 85AB96E6FA1BE5FE" >> ~/.gnupg/gpg.conf
61+
62+
ARG BAZEL_VERSION
63+
ARG RUST_DATE
64+
ARG RUST_VERSION
65+
66+
RUN \
67+
# 1. autouseradd
68+
#
69+
# Ensures that the UID used when running the container has a proper entry in
70+
# `/etc/passwd`, and writable home directory.
71+
curl -fsSL https://github.com/benesch/autouseradd/releases/download/1.3.0/autouseradd-1.3.0-$ARCH_GO.tar.gz \
72+
| tar xz -C / --strip-components 1 \
73+
# 2. Bazel
74+
#
75+
# We primarily build Materialize via Bazel in CI, and Bazel pulls in its own dependencies.
76+
&& arch_bazel=$(echo "$ARCH_GCC" | sed -e "s/aarch64/arm64/" -e "s/amd64/x86_64/") bazel_version=$(echo "$BAZEL_VERSION") \
77+
&& curl -fsSL -o /usr/local/bin/bazel https://github.com/bazelbuild/bazel/releases/download/$bazel_version/bazel-$bazel_version-linux-$arch_bazel \
78+
&& if [ "$arch_bazel" = arm64 ]; then echo 'fac4b954e0501c2be8b9653a550b443eb85284e568d08b102977e2bf587b09d7 /usr/local/bin/bazel' | sha256sum --check; fi \
79+
&& if [ "$arch_bazel" = x86_64 ]; then echo '48ea0ff9d397a48add6369c261c5a4431fe6d5d5348cfb81411782fb80c388d3 /usr/local/bin/bazel' | sha256sum --check; fi \
80+
&& chmod +x /usr/local/bin/bazel \
81+
# 3. Docker
82+
#
83+
# If you upgrade Docker (Compose) version here, also update it in misc/python/cli/mzcompose.py.
84+
&& mkdir -p /usr/local/lib/docker/cli-plugins \
85+
&& curl -fsSL https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-$ARCH_GCC > /usr/local/lib/docker/cli-plugins/docker-compose \
86+
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-compose \
87+
&& curl -fsSL https://github.com/christian-korneck/docker-pushrm/releases/download/v1.9.0/docker-pushrm_linux_$ARCH_GO > /usr/local/lib/docker/cli-plugins/docker-pushrm \
88+
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-pushrm \
89+
# 4. Cargo
90+
#
91+
# Some parts of our stack use 'cargo' to read metadata, so we install just that. Importantly we
92+
# do not install 'rustc' or any of the other tools, this keeps the Docker image small.
93+
&& mkdir rust \
94+
&& curl -fsSL https://static.rust-lang.org/dist$RUST_DATE/rust-$RUST_VERSION-$ARCH_GCC-unknown-linux-gnu.tar.gz > rust.tar.gz \
95+
&& curl -fsSL https://static.rust-lang.org/dist$RUST_DATE/rust-$RUST_VERSION-$ARCH_GCC-unknown-linux-gnu.tar.gz.asc > rust.asc \
96+
&& gpg --verify rust.asc rust.tar.gz \
97+
&& tar -xzf rust.tar.gz -C rust --strip-components=1 \
98+
&& rust/install.sh --components=cargo \
99+
&& rm -rf rust.asc rust.tar.gz rust
100+
101+
# Make the image as small as possible.
102+
RUN find /workdir /root -mindepth 1 -maxdepth 1 -exec rm -rf {} +
103+
104+
# Remove Ubuntu user causing UID collisions.
105+
# https://bugs.launchpad.net/cloud-images/+bug/2005129
106+
RUN userdel -r ubuntu
107+
108+
ENTRYPOINT ["autouseradd", "--user", "materialize"]
109+
110+
# Stage 2. Build a cross-compiling toolchain that targets the oldest version of
111+
# Linux that we support.
112+
#
113+
# TODO(parkmycar): This shouldn't be necessary anymore with Bazel.
13114
FROM ubuntu:noble-20241015 as crosstool
115+
14116
ARG ARCH_GCC
15117
ARG ARCH_GO
16118

@@ -68,10 +170,10 @@ RUN DEFCONFIG=crosstool-$ARCH_GCC.defconfig ct-ng defconfig \
68170
&& rm crosstool-$ARCH_GCC.defconfig \
69171
&& ct-ng build
70172

71-
# Import the cross-compiling toolchain into a fresh image, omitting the
72-
# dependencies that we needed to actually build the toolchain.
173+
# Stage 3: Build a full CI Builder image that imports the cross-compiling
174+
# toolchain and can be used for any CI job.
175+
FROM ci-builder-min as ci-builder-full
73176

74-
FROM ubuntu:noble-20241015
75177
ARG ARCH_GCC
76178
ARG ARCH_GO
77179

@@ -135,9 +237,7 @@ RUN gpg --dearmor < nodesource.asc > /etc/apt/keyrings/nodesource.gpg \
135237
&& apt-get update \
136238
&& apt-get install -y --no-install-recommends nodejs
137239

138-
RUN curl -fsSL https://github.com/benesch/autouseradd/releases/download/1.3.0/autouseradd-1.3.0-$ARCH_GO.tar.gz \
139-
| tar xz -C / --strip-components 1 \
140-
&& curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.8.0/shellcheck-v0.8.0.linux.$ARCH_GCC.tar.xz > shellcheck.tar.xz \
240+
RUN curl -fsSL https://github.com/koalaman/shellcheck/releases/download/v0.8.0/shellcheck-v0.8.0.linux.$ARCH_GCC.tar.xz > shellcheck.tar.xz \
141241
&& tar -xJf shellcheck.tar.xz -C /usr/local/bin --strip-components 1 shellcheck-v0.8.0/shellcheck \
142242
&& rm shellcheck.tar.xz \
143243
&& curl -fsSL https://github.com/bufbuild/buf/releases/download/v1.18.0/buf-Linux-$ARCH_GCC.tar.gz > buf.tar.gz \
@@ -148,12 +248,6 @@ RUN curl -fsSL https://github.com/benesch/autouseradd/releases/download/1.3.0/au
148248
&& tar -xf kail.tar.gz -C /usr/local/bin kail \
149249
&& rm kail.tar.gz \
150250
&& chmod +x /usr/local/bin/kail \
151-
&& mkdir -p /usr/local/lib/docker/cli-plugins \
152-
# If you upgrade Docker (Compose) version here, also update it in misc/python/cli/mzcompose.py \
153-
&& curl -fsSL https://github.com/docker/compose/releases/download/v2.15.1/docker-compose-linux-$ARCH_GCC > /usr/local/lib/docker/cli-plugins/docker-compose \
154-
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-compose \
155-
&& curl -fsSL https://github.com/christian-korneck/docker-pushrm/releases/download/v1.9.0/docker-pushrm_linux_$ARCH_GO > /usr/local/lib/docker/cli-plugins/docker-pushrm \
156-
&& chmod +x /usr/local/lib/docker/cli-plugins/docker-pushrm \
157251
&& curl -fsSL https://github.com/parca-dev/parca-debuginfo/releases/download/v0.11.0/parca-debuginfo_0.11.0_Linux_$(echo "$ARCH_GCC" | sed "s/aarch64/arm64/").tar.gz \
158252
| tar xz -C /usr/local/bin parca-debuginfo
159253

@@ -212,8 +306,6 @@ RUN mkdir rust \
212306
RUN ln -s /usr/bin/lld /opt/x-tools/$ARCH_GCC-unknown-linux-gnu/bin/$ARCH_GCC-unknown-linux-gnu-ld.lld \
213307
&& ln -s /usr/bin/lld /opt/x-tools/$ARCH_GCC-unknown-linux-gnu/bin/$ARCH_GCC-unknown-linux-gnu-lld
214308

215-
RUN curl -LsSf https://astral.sh/uv/0.4.25/install.sh | UV_INSTALL_DIR=/usr/local UV_UNMANAGED_INSTALL=1 sh
216-
217309
# Shims for sanitizers
218310
COPY sanshim/$ARCH_GCC /sanshim
219311

@@ -223,13 +315,6 @@ COPY sanshim/$ARCH_GCC /sanshim
223315
COPY pyright-version.sh /workdir/
224316
RUN npx pyright@$(sh /workdir/pyright-version.sh) --help
225317

226-
# Install Python dependencies. These are so quick to install and change
227-
# frequently enough that it makes sense to install them last.
228-
229-
COPY requirements.txt /workdir/
230-
231-
RUN uv pip install --system --break-system-packages -r /workdir/requirements.txt && rm /workdir/requirements*.txt
232-
233318
# Install APT repo generator.
234319

235320
RUN curl -fsSL https://github.com/deb-s3/deb-s3/releases/download/0.11.3/deb-s3-0.11.3.gem > deb-s3.gem \
@@ -258,21 +343,7 @@ RUN if [ $ARCH_GCC = x86_64 ]; then \
258343
&& rm hugo.tar.gz; \
259344
fi
260345

261-
# Install Bazel.
262-
#
263-
# TODO(parkmycar): Run Bazel in a Docker image that does not have access to clang/gcc or any other tools.
264-
265-
ARG BAZEL_VERSION
266-
267-
# Download the bazel binary from the official GitHub releases since the apt repositories do not
268-
# contain arm64 releases.
269-
RUN arch_bazel=$(echo "$ARCH_GCC" | sed -e "s/aarch64/arm64/" -e "s/amd64/x86_64/") bazel_version=$(echo "$BAZEL_VERSION") \
270-
&& curl -fsSL -o /usr/local/bin/bazel https://github.com/bazelbuild/bazel/releases/download/$bazel_version/bazel-$bazel_version-linux-$arch_bazel \
271-
&& if [ "$arch_bazel" = arm64 ]; then echo 'fac4b954e0501c2be8b9653a550b443eb85284e568d08b102977e2bf587b09d7 /usr/local/bin/bazel' | sha256sum --check; fi \
272-
&& if [ "$arch_bazel" = x86_64 ]; then echo '48ea0ff9d397a48add6369c261c5a4431fe6d5d5348cfb81411782fb80c388d3 /usr/local/bin/bazel' | sha256sum --check; fi \
273-
&& chmod +x /usr/local/bin/bazel
274-
275-
# Install KinD, kubectl, helm, helm-docs & terraform
346+
# Install KinD, kubectl, helm & helm-docs
276347

277348
RUN curl -fsSL https://kind.sigs.k8s.io/dl/v0.14.0/kind-linux-$ARCH_GO > /usr/local/bin/kind \
278349
&& chmod +x /usr/local/bin/kind \
@@ -340,28 +411,11 @@ ENV CARGO_TARGET_DIR=/mnt/build
340411
ENV CARGO_INCREMENTAL=0
341412
ENV HELM_PLUGINS=/usr/local/share/helm/plugins
342413

343-
# Set a environment variable that tools can check to see if they're in the
344-
# builder or not.
345-
346-
ENV MZ_DEV_CI_BUILDER=1
347-
348414
# Set up for a persistent volume to hold Cargo metadata, so that crate metadata
349415
# does not need to be refetched on every compile.
350-
351416
ENV CARGO_HOME=/cargo
352417
RUN mkdir /cargo && chmod 777 /cargo
353418
VOLUME /cargo
354419

355-
# Ensure any Rust binaries that crash print a backtrace.
356-
ENV RUST_BACKTRACE=1
357-
358420
# Make the image as small as possible.
359421
RUN find /workdir /root -mindepth 1 -maxdepth 1 -exec rm -rf {} +
360-
361-
# remove Ubuntu user causing UID collisions
362-
# https://bugs.launchpad.net/cloud-images/+bug/2005129
363-
RUN userdel -r ubuntu
364-
365-
# Ensure that all python output is unbuffered, otherwise it is not
366-
# logged properly in Buildkite
367-
ENV PYTHONUNBUFFERED=1

ci/mkpipeline.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,15 @@ pipeline=${1:-test}
2323
bootstrap_steps=
2424

2525
for arch in x86_64 aarch64; do
26-
for toolchain in stable nightly; do
27-
if ! MZ_DEV_CI_BUILDER_ARCH=$arch bin/ci-builder exists $toolchain; then
26+
for flavor in stable nightly min; do
27+
if ! MZ_DEV_CI_BUILDER_ARCH=$arch bin/ci-builder exists $flavor; then
2828
queue=builder-linux-x86_64
2929
if [[ $arch = aarch64 ]]; then
3030
queue=builder-linux-aarch64-mem
3131
fi
3232
bootstrap_steps+="
33-
- label: bootstrap $toolchain $arch
34-
command: bin/ci-builder push $toolchain
33+
- label: bootstrap $flavor $arch
34+
command: bin/ci-builder push $flavor
3535
agents:
3636
queue: $queue
3737
"
@@ -47,7 +47,7 @@ steps:
4747
env:
4848
CI_BAZEL_BUILD: 1
4949
CI_BAZEL_REMOTE_CACHE: "https://bazel-remote.dev.materialize.com"
50-
command: bin/ci-builder run stable bin/pyactivate -m ci.mkpipeline $pipeline $@
50+
command: bin/ci-builder run min bin/pyactivate -m ci.mkpipeline $pipeline $@
5151
priority: 200
5252
agents:
5353
queue: hetzner-aarch64-4cpu-8gb

ci/nightly/pipeline.template.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ steps:
2020
steps:
2121
- id: build-x86_64
2222
label: ":bazel: Build x86_64"
23-
command: bin/ci-builder run stable bin/pyactivate -m ci.test.build
23+
command: bin/ci-builder run min bin/pyactivate -m ci.test.build
2424
inputs:
2525
- "*"
2626
artifact_paths: bazel-explain.log
@@ -31,7 +31,7 @@ steps:
3131

3232
- id: build-aarch64
3333
label: ":bazel: Build aarch64"
34-
command: bin/ci-builder run stable bin/pyactivate -m ci.test.build
34+
command: bin/ci-builder run min bin/pyactivate -m ci.test.build
3535
inputs:
3636
- "*"
3737
artifact_paths: bazel-explain.log

ci/release-qualification/pipeline.template.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ steps:
2020
steps:
2121
- id: build-aarch64
2222
label: ":bazel: Build aarch64"
23-
command: bin/ci-builder run stable bin/pyactivate -m ci.test.build
23+
command: bin/ci-builder run min bin/pyactivate -m ci.test.build
2424
inputs:
2525
- "*"
2626
artifact_paths: bazel-explain.log
@@ -39,7 +39,7 @@ steps:
3939
label: ":bazel: Build x86_64"
4040
env:
4141
CI_BAZEL_BUILD: "1"
42-
command: bin/ci-builder run stable bin/pyactivate -m ci.test.build
42+
command: bin/ci-builder run min bin/pyactivate -m ci.test.build
4343
inputs:
4444
- "*"
4545
artifact_paths: bazel-explain.log

ci/test/pipeline.template.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
dag: true
1616

1717
env:
18-
CI_BUILDER_SCCACHE: 1
1918
CI_BAZEL_BUILD: 1
2019
CI_BAZEL_REMOTE_CACHE: $BAZEL_REMOTE_CACHE
2120
# Note: In .cargo/config we set the default build jobs to -1 so on developer machines we keep
@@ -90,7 +89,7 @@ steps:
9089
- id: build-x86_64
9190
label: ":bazel: Build x86_64"
9291
env:
93-
command: bin/ci-builder run stable bin/pyactivate -m ci.test.build
92+
command: bin/ci-builder run min bin/pyactivate -m ci.test.build
9493
inputs:
9594
- "*"
9695
artifact_paths: bazel-explain.log
@@ -102,7 +101,7 @@ steps:
102101
- id: build-aarch64
103102
label: ":bazel: Build aarch64"
104103
env:
105-
command: bin/ci-builder run stable bin/pyactivate -m ci.test.build
104+
command: bin/ci-builder run min bin/pyactivate -m ci.test.build
106105
inputs:
107106
- "*"
108107
artifact_paths: bazel-explain.log

0 commit comments

Comments
 (0)