1- FROM public.ecr.aws/lts/ubuntu:24.04
2-
3- # TODO: use a multi-stage build to reduce the download size when updating this container.
4- # The Rust toolchain layer will get updated most frequently, but we could keep the system
5- # dependencies layer intact for much longer.
1+ # Building the devctr is a multi-stage process. The dependency graph is as follows:
2+ #
3+ # Stage dependency graph:
4+ #
5+ # +--- qemu-builder -------+
6+ # | |
7+ # +--- libseccomp-builder -+
8+ # | |
9+ # base-image +--------------------+--- iperf3-builder -----+--- devctr
10+ # | | |
11+ # | +--- git-secrets-builder +
12+ # | |
13+ # +--- apt-base |
14+ # | |
15+ # | |
16+ # python-deps +--- crosvm-builder -----+
17+ # | | |
18+ # rust-toolchain ---+------------------------+
19+ #
20+ # Parallel builders (from base-image):
21+ # qemu-builder, libseccomp-builder, iperf3-builder, git-secrets-builder
22+ #
23+ # Sequential base chain:
24+ # base-image -> apt-base -> python-deps -> rust-toolchain
25+ #
26+ # Rust fork (from rust-toolchain):
27+ # crosvm-builder (build deps thrown away, only binary copied)
28+ # devctr (cargo tools, kani, nightly, then COPY from all builders)
29+ #
630
7- ARG RUST_TOOLCHAIN="1.94.1"
8- ARG TMP_BUILD_DIR=/tmp/build
31+ # ============================================================
32+ # Base image: Shared between builders
33+ # ============================================================
34+ FROM public.ecr.aws/lts/ubuntu:24.04 AS base-image
935ARG DEBIAN_FRONTEND=noninteractive
10- ARG PIP_BREAK_SYSTEM_PACKAGES=1
1136ARG ARCH
37+ RUN apt-get update \
38+ && apt-get -y install --no-install-recommends \
39+ git gcc make libc-dev ca-certificates musl-tools
1240
13- ENV CARGO_HOME=/usr/local/rust
14- ENV RUSTUP_HOME=/usr/local/rust
15- ENV PATH="$PATH:$CARGO_HOME/bin"
16- ENV LC_ALL=C.UTF-8
41+ # help musl-gcc find linux headers
42+ RUN cd /usr/include/$ARCH-linux-musl \
43+ && ln -s ../$ARCH-linux-gnu/asm asm \
44+ && ln -s ../linux linux \
45+ && ln -s ../asm-generic asm-generic
46+
47+ # ============================================================
48+ # Builder: Qemu vhost-user-blk backend
49+ # ============================================================
50+ FROM base-image AS qemu-builder
51+ ARG PIP_BREAK_SYSTEM_PACKAGES=1
1752ENV QEMU_VER="8.1.1"
18- ENV CROSVM_VER="9d542e6dafa3a85acd1fb6cd6f1adfa1331c4e96"
19- ENV CROSVM_TOOLCHAIN_VER="1.68.2"
20- ENV LIBSECCOMP_VER="v2.6.0"
2153
22- # Build and install Qemu vhost-user-blk backend
23- #
2454RUN apt-get update \
2555 && apt-get -y install --no-install-recommends \
2656 curl gpg gpg-agent \
@@ -35,27 +65,65 @@ RUN apt-get update \
3565 && tar xf qemu-${QEMU_VER}.tar.xz && cd qemu-${QEMU_VER} \
3666 && ./configure && make -j $(nproc) contrib/vhost-user-blk/vhost-user-blk \
3767 && strip ./build/contrib/vhost-user-blk/vhost-user-blk \
38- && cp -a ./build/contrib/vhost-user-blk/vhost-user-blk /usr/local/bin \
39- && pip3 uninstall -y meson \
40- && apt-get purge -y \
41- curl gpg gpg-agent \
42- build-essential ninja-build libglib2.0-dev libpixman-1-dev flex bison \
43- && apt-get autoremove -y \
44- && cd && rm -r /tmp/qemu_build
68+ && cp -a ./build/contrib/vhost-user-blk/vhost-user-blk /usr/local/bin
69+
70+ # ============================================================
71+ # Builder: static libseccomp (musl)
72+ # ============================================================
73+ FROM base-image AS libseccomp-builder
74+ ENV LIBSECCOMP_VER="v2.6.0"
75+
76+ # Install static version of libseccomp
77+ # We need to compile from source because
78+ # libseccomp provided by the distribution is not
79+ # compiled with musl-gcc and we need this
80+ # for our musl builds.
81+ # We specify the tag in order to have a fixed version
82+ # of the library.
83+ RUN apt-get -y install --no-install-recommends \
84+ libtool gperf autoconf automake \
85+ && git clone https://github.com/seccomp/libseccomp /tmp/libseccomp \
86+ && cd /tmp/libseccomp \
87+ && git checkout tags/${LIBSECCOMP_VER} \
88+ && ./autogen.sh \
89+ && CC="musl-gcc -static" ./configure --enable-static=yes --enable-shared=false \
90+ && make DESTDIR=/staging install
91+
92+ # ============================================================
93+ # Builder: iperf3-vsock
94+ # ============================================================
95+ FROM base-image AS iperf3-builder
96+ RUN git clone https://github.com/stefano-garzarella/iperf-vsock /tmp/iperf-vsock \
97+ && cd /tmp/iperf-vsock && git checkout 9245f9a \
98+ && mkdir build && cd build \
99+ && ../configure "LDFLAGS=--static" --disable-shared && make \
100+ && cp src/iperf3 /usr/local/bin/iperf3-vsock
101+
102+ # ============================================================
103+ # Builder: git-secrets
104+ # ============================================================
105+ FROM base-image AS git-secrets-builder
106+ RUN git clone https://github.com/awslabs/git-secrets /tmp/git-secrets \
107+ && cd /tmp/git-secrets \
108+ && make DESTDIR=/staging install
109+
110+ # ============================================================
111+ # Base: apt packages (changes very rarely)
112+ # ============================================================
113+ FROM base-image AS apt-base
114+ ARG ARCH
115+ ENV LC_ALL=C.UTF-8
45116
46- # Install system dependencies
47- #
48117RUN apt-get update \
49118 && apt-get -y install --no-install-recommends \
50119 # essential build tools
51- gcc make libc-dev binutils-dev libssl-dev \
120+ binutils-dev libssl-dev \
52121 # Useful utilities
53122 gdbserver \
54123 # Needed in order to be able to compile `userfaultfd-sys`.
55124 clang \
56125 curl \
57126 file \
58- git \
59127 jq \
60128 less \
61129 libbfd-dev \
@@ -80,18 +148,44 @@ RUN apt-get update \
80148 python3-seccomp \
81149 # for aws-lc-rs
82150 cmake \
83- # for Qemu vhost-user-blk backend
84- libglib2.0-dev \
85151 # for crosvm (vhost-user-blk backend)
86152 libcap2 \
87153 # for debugging
88154 gdb strace trace-cmd \
89155 && rm -rf /var/lib/apt/lists/*
90156
157+
158+ # Add cross-compile toolchain for devtool checkbuild command (rust target added in devctr stage)
159+ RUN case "${ARCH}" in \
160+ "aarch64" ) \
161+ apt-get update && apt install -y gcc-x86-64-linux-gnu libc6-dev-amd64-cross linux-libc-dev-amd64-cross \
162+ ;; \
163+ "x86_64" ) \
164+ apt-get update && apt install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross linux-libc-dev-arm64-cross \
165+ ;; \
166+ *) echo "Unsupported arch ${ARCH}" && exit 1 ;; \
167+ esac \
168+ && rm -rf /var/lib/apt/lists/*
169+
170+
171+ # Download codecov uploader
172+ RUN cd /usr/local/bin \
173+ && (if [ "$ARCH" = "x86_64" ]; then \
174+ curl -O https://uploader.codecov.io/latest/linux/codecov; else \
175+ curl -O https://uploader.codecov.io/latest/aarch64/codecov; fi) \
176+ && chmod +x codecov
177+
178+ # ============================================================
179+ # Base: Python/Poetry deps (changes with poetry.lock)
180+ # ============================================================
181+ FROM apt-base AS python-deps
182+ ARG PIP_BREAK_SYSTEM_PACKAGES=1
183+ ARG ARCH
184+ ARG VENV="/opt/venv"
185+
91186RUN curl -sSL https://install.python-poetry.org | python3 -
92187ENV PATH="/root/.local/bin:$PATH"
93188
94- ARG VENV="/opt/venv"
95189COPY tools/devctr/poetry.lock /tmp/poetry/
96190COPY tools/devctr/pyproject.toml /tmp/poetry/
97191RUN cd /tmp/poetry \
@@ -106,24 +200,50 @@ ENV PATH=$VENV/bin:$PATH
106200# apt-get installs it globally, to manually copy it into the venv
107201RUN cp /usr/lib/python3/dist-packages/seccomp.cpython-312-"$ARCH" -linux-gnu.so "$VENV" /lib/python3.12/site-packages/
108202
109- RUN git clone https://github.com/awslabs/git-secrets /tmp/git-secrets \
110- && cd /tmp/git-secrets \
111- && make install \
112- && cd - \
113- && rm -rf /tmp/git-secrets
203+ # ============================================================
204+ # Base: Rust toolchain (current version)
205+ # ============================================================
206+ FROM python-deps AS rust-toolchain
207+ ARG RUST_TOOLCHAIN="1.94.1"
208+ ENV CARGO_HOME=/usr/local/rust
209+ ENV RUSTUP_HOME=/usr/local/rust
210+ ENV PATH="$PATH:$CARGO_HOME/bin"
211+ RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN" \
212+ && rustup target add x86_64-unknown-linux-musl \
213+ && rustup target add aarch64-unknown-linux-musl \
214+ && rustup component add llvm-tools-preview clippy rustfmt
215+
216+ # ============================================================
217+ # Builder: crosvm (used as vhost-user-blk backend)
218+ # ============================================================
219+ FROM rust-toolchain AS crosvm-builder
220+ ENV CROSVM_VER="9d542e6dafa3a85acd1fb6cd6f1adfa1331c4e96"
221+ RUN apt-get update && \
222+ apt-get -y install --no-install-recommends \
223+ libcap2 \
224+ libcap-dev \
225+ protobuf-compiler \
226+ && git clone https://github.com/google/crosvm.git /tmp/crosvm \
227+ && cd /tmp/crosvm && git checkout ${CROSVM_VER} \
228+ && git submodule update --init \
229+ && cargo build --no-default-features --release \
230+ && strip ./target/release/crosvm \
231+ && cp -a ./target/release/crosvm /usr/local/bin
114232
115- # Running the three as a single dockerfile command to avoid inflation of the image:
116- # - Install the Rust toolchain.
233+ # ============================================================
234+ # Devctr (final): Kani, cargo targets and assembled artifacts
235+ # ============================================================
236+ FROM rust-toolchain AS devctr
237+ ARG ARCH
238+ ENV CARGO_HOME=/usr/local/rust
239+
240+ # Run these as a single dockerfile command to avoid inflation of the image:
241+ # - Install required binary crates, including cargo-afl (fuzzer) and Kani (formal verification)
117242# - Kani always installs _some_ nightly toolchain, we reuse it for the seccomp filter analysis test. Dynamically
118243# determine the exact toolchain name, and install more components into it.
119- # - Build and install crosvm (used as vhost-user-blk backend)
120- # - Clean up cargo compilation directories
121244# - Always install both x86_64 and aarch64 musl targets, as our rust-toolchain.toml would force on-the-fly installation of both anyway
122- RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-toolchain "$RUST_TOOLCHAIN" \
123- && rustup target add x86_64-unknown-linux-musl \
124- && rustup target add aarch64-unknown-linux-musl \
125- && rustup component add llvm-tools-preview clippy rustfmt \
126- && cargo install --locked grcov cargo-sort cargo-afl \
245+ # - Clean up cargo compilation directories
246+ RUN cargo install --locked grcov cargo-sort cargo-afl \
127247 && cargo install --locked cargo-deny --version 0.19.0 \
128248 && cargo install --locked kani-verifier --version 0.67.0 && cargo kani setup \
129249 \
@@ -132,88 +252,20 @@ RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal --default-too
132252 && rustup target add "$ARCH" -unknown-linux-musl --toolchain "$NIGHTLY_TOOLCHAIN" \
133253 && cargo +"$NIGHTLY_TOOLCHAIN" install cargo-udeps \
134254 \
135- && apt-get update \
136- && apt-get -y install --no-install-recommends \
137- libcap-dev \
138- protobuf-compiler \
139- && git clone https://github.com/google/crosvm.git /tmp/crosvm \
140- && cd /tmp/crosvm && git checkout ${CROSVM_VER} \
141- && git submodule update --init \
142- && cargo build --no-default-features --release \
143- && strip ./target/release/crosvm \
144- && cp -a ./target/release/crosvm /usr/local/bin \
145- && apt-get purge -y \
146- libcap-dev \
147- protobuf-compiler \
148- && apt-get autoremove -y \
149- && rm -rf /var/lib/apt/lists/* \
150- && rustup toolchain uninstall ${CROSVM_TOOLCHAIN_VER}-${ARCH}-unknown-linux-gnu \
151- && cd && rm -r /tmp/crosvm \
255+ && case "${ARCH}" in \
256+ "aarch64" ) rustup target add x86_64-unknown-linux-gnu ;; \
257+ "x86_64" ) rustup target add aarch64-unknown-linux-gnu ;; \
258+ esac \
152259 \
153260 && rm -rf "$CARGO_HOME/registry" \
154261 && rm -rf "$CARGO_HOME/git"
155262
156- # help musl-gcc find linux headers
157- RUN cd /usr/include/$ARCH-linux-musl \
158- && ln -s ../$ARCH-linux-gnu/asm asm \
159- && ln -s ../linux linux \
160- && ln -s ../asm-generic asm-generic
161-
162- # Install static version of libseccomp
163- # We need to compile from source because
164- # libseccomp provided by the distribution is not
165- # compiled with musl-gcc and we need this
166- # for our musl builds.
167- # We specify the tag in order to have a fixed version
168- # of the library.
169- RUN apt-get update \
170- && apt-get -y install \
171- libtool gperf \
172- && git clone https://github.com/seccomp/libseccomp /tmp/libseccomp \
173- && cd /tmp/libseccomp \
174- && git checkout tags/${LIBSECCOMP_VER} \
175- && ./autogen.sh \
176- && CC="musl-gcc -static" ./configure --enable-static=yes --enable-shared=false \
177- && make install \
178- && cd \
179- && apt-get purge -y \
180- libtool gperf \
181- && apt-get autoremove -y \
182- && rm -rf /tmp/libseccomp
183-
184- # Build iperf3-vsock
185- RUN mkdir "$TMP_BUILD_DIR" && cd "$TMP_BUILD_DIR" \
186- && git clone https://github.com/stefano-garzarella/iperf-vsock \
187- && cd iperf-vsock && git checkout 9245f9a \
188- && mkdir build && cd build \
189- && ../configure "LDFLAGS=--static" --disable-shared && make \
190- && cp src/iperf3 /usr/local/bin/iperf3-vsock \
191- && cd / \
192- && rm -rf "$TMP_BUILD_DIR"
193-
194- # Download the codecov.io uploader
195- RUN cd /usr/local/bin \
196- && (if [ "$ARCH" = "x86_64" ]; then \
197- curl -O https://uploader.codecov.io/latest/linux/codecov; else \
198- curl -O https://uploader.codecov.io/latest/aarch64/codecov; fi) \
199- && chmod +x codecov \
200- && cd -
201-
202- # Add cross-compile toolchain for devtool checkbuild command
203- RUN case "${ARCH}" in \
204- "aarch64" ) \
205- apt install -y gcc-x86-64-linux-gnu libc6-dev-amd64-cross linux-libc-dev-amd64-cross && \
206- rustup target add x86_64-unknown-linux-gnu \
207- ;; \
208- "x86_64" ) \
209- apt install -y gcc-aarch64-linux-gnu libc6-dev-arm64-cross linux-libc-dev-arm64-cross && \
210- rustup target add aarch64-unknown-linux-gnu \
211- ;; \
212- *) \
213- echo "Unsupported arch ${ARCH}" && \
214- exit 1 \
215- ;; \
216- esac
263+ # Copy pre-built artifacts LAST — builder changes don't invalidate Rust layer
264+ COPY --from=qemu-builder /usr/local/bin/vhost-user-blk /usr/local/bin/
265+ COPY --from=libseccomp-builder /staging /
266+ COPY --from=iperf3-builder /usr/local/bin/iperf3-vsock /usr/local/bin/
267+ COPY --from=git-secrets-builder /staging /
268+ COPY --from=crosvm-builder /usr/local/bin/crosvm /usr/local/bin/
217269
218270ADD tools/devctr/ctr_gitconfig /root/.gitconfig
219271
0 commit comments