Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
378 lines (311 loc) · 13.6 KB
/
Copy pathDockerfile
File metadata and controls
378 lines (311 loc) · 13.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
# Copyright The containerd Authors.
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
# syntax=docker/dockerfile:1
# Build the Linux kernel, erofs rootfs, and containerd shim for running nerdbox
ARG XX_VERSION=1.9.0
ARG GO_VERSION=1.26.3
ARG BASE_DEBIAN_DISTRO="bookworm"
ARG GOLANG_IMAGE="golang:${GO_VERSION}-${BASE_DEBIAN_DISTRO}"
ARG GOLANGCI_LINT_VERSION=2.7.2
ARG GOLANGCI_FROM_SOURCE=false
ARG DOCKER_VERSION=28.4.0
ARG DOCKER_IMAGE="docker:${DOCKER_VERSION}-cli"
ARG RUST_IMAGE="rust:1.89.0-slim-${BASE_DEBIAN_DISTRO}"
# xx is a helper for cross-compilation
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
FROM --platform=$BUILDPLATFORM ${GOLANG_IMAGE} AS base
RUN echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
RUN apt-get update && apt-get install --no-install-recommends -y file
FROM base AS kernel-build-base
# Set environment variables for non-interactive installations
ENV DEBIAN_FRONTEND=noninteractive
RUN echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache
# Install build dependencies
RUN --mount=type=cache,sharing=locked,id=kernel-aptlib,target=/var/lib/apt \
--mount=type=cache,sharing=locked,id=kernel-aptcache,target=/var/cache/apt \
apt-get update && apt-get install -y build-essential libncurses-dev flex bison libssl-dev libelf-dev bc cpio git wget xz-utils pahole
ARG KERNEL_VERSION="6.12.44"
ARG KERNEL_ARCH="x86_64"
ARG KERNEL_NPROC
ARG KERNEL_PAGE_SIZE="4k"
# Validate KERNEL_PAGE_SIZE early
RUN <<EOT
set -e
case "${KERNEL_PAGE_SIZE}" in
4k|16k) ;;
*) echo "ERROR: unsupported KERNEL_PAGE_SIZE=${KERNEL_PAGE_SIZE} (must be 4k or 16k)" ; exit 1 ;;
esac
if [ "${KERNEL_PAGE_SIZE}" = "16k" ] && [ "${KERNEL_ARCH}" != "arm64" ]; then
echo "ERROR: KERNEL_PAGE_SIZE=16k is only supported on arm64, not ${KERNEL_ARCH}" ; exit 1
fi
EOT
# Install cross-compiler if host architecture differs from target
RUN --mount=type=cache,sharing=locked,id=kernel-aptlib,target=/var/lib/apt \
--mount=type=cache,sharing=locked,id=kernel-aptcache,target=/var/cache/apt <<EOT
HOST_ARCH=$(uname -m)
# Normalize host arch to match KERNEL_ARCH naming
case "${HOST_ARCH}" in
aarch64) HOST_ARCH=arm64 ;;
esac
if [ "${HOST_ARCH}" != "${KERNEL_ARCH}" ]; then
case "${KERNEL_ARCH}" in
arm64) apt-get update && apt-get install -y gcc-aarch64-linux-gnu ;;
x86_64) apt-get update && apt-get install -y gcc-x86-64-linux-gnu ;;
*) echo "Unsupported architecture: ${KERNEL_ARCH}" ; exit 1 ;;
esac
fi
EOT
# Set the working directory
WORKDIR /usr/src
RUN wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${KERNEL_VERSION}.tar.xz && \
tar -xf linux-${KERNEL_VERSION}.tar.xz && \
rm linux-${KERNEL_VERSION}.tar.xz && \
mv linux-${KERNEL_VERSION} linux
#COPY --from=config-build /usr/src/fragments/.config /usr/src/linux/.config
COPY kernel/config-${KERNEL_VERSION}-${KERNEL_ARCH} /usr/src/linux/.config
COPY kernel/patches /usr/src/linux/patches
RUN <<EOT
set -e
for patch in $(ls -d /usr/src/linux/patches/*.patch); do
patch -p1 -d /usr/src/linux --fuzz=0 < "$patch";
done
EOT
# Adjust kernel page size for arm64 (x86_64 only supports 4k pages)
RUN <<EOT
set -e
if [ "${KERNEL_ARCH}" = "arm64" ] && [ "${KERNEL_PAGE_SIZE}" = "16k" ]; then
/usr/src/linux/scripts/config --file /usr/src/linux/.config \
--disable CONFIG_ARM64_4K_PAGES \
--enable CONFIG_ARM64_16K_PAGES \
--disable CONFIG_ARM64_64K_PAGES
HOST_ARCH=$(uname -m)
case "${HOST_ARCH}" in
aarch64) HOST_ARCH=arm64 ;;
esac
CROSS_COMPILE=""
if [ "${HOST_ARCH}" != "${KERNEL_ARCH}" ]; then
case "${KERNEL_ARCH}" in
arm64) CROSS_COMPILE=aarch64-linux-gnu- ;;
x86_64) CROSS_COMPILE=x86_64-linux-gnu- ;;
esac
fi
cd linux && ARCH="${KERNEL_ARCH}" CROSS_COMPILE="${CROSS_COMPILE}" make olddefconfig
fi
EOT
# Build the kernel
# Seperate from base to allow config construction from fragments in the future
FROM kernel-build-base AS kernel-build
# Compile the kernel
RUN <<EOT
set -e
HOST_ARCH=$(uname -m)
# Normalize host arch to match KERNEL_ARCH naming
case "${HOST_ARCH}" in
aarch64) HOST_ARCH=arm64 ;;
esac
CROSS_COMPILE=""
if [ "${HOST_ARCH}" != "${KERNEL_ARCH}" ]; then
case "${KERNEL_ARCH}" in
arm64) CROSS_COMPILE=aarch64-linux-gnu- ;;
x86_64) CROSS_COMPILE=x86_64-linux-gnu- ;;
esac
fi
cd linux && ARCH="${KERNEL_ARCH}" CROSS_COMPILE="${CROSS_COMPILE}" make -j${KERNEL_NPROC:-$(nproc)}
EOT
RUN <<EOT
set -e
cd linux
mkdir /build
case "${KERNEL_ARCH}" in
x86_64) cp vmlinux /build/kernel ;;
arm64) cp arch/arm64/boot/Image /build/kernel ;;
*) echo "Unsupported architecture: ${KERNEL_ARCH} " ; exit 1 ;;
esac
EOT
FROM base AS shim-build
WORKDIR /go/src/github.com/containerd/nerdbox
ARG GO_DEBUG_GCFLAGS
ARG GO_GCFLAGS
ARG GO_BUILD_FLAGS
ARG GO_LDFLAGS
ARG TARGETOS
ARG TARGETARCH
ARG TARGETPLATFORM
ARG GOPROXY
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/root/.cache/go-build,id=shim-build-$TARGETPLATFORM \
GOOS=${TARGETOS} GOPROXY=${GOPROXY} GOARCH=${TARGETARCH} go build ${GO_DEBUG_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o /build/containerd-shim-nerdbox-v1 ${GO_LDFLAGS} -tags 'no_grpc' ./cmd/containerd-shim-nerdbox-v1
FROM base AS vminit-build
WORKDIR /go/src/github.com/containerd/nerdbox
ARG GO_DEBUG_GCFLAGS
ARG GO_GCFLAGS
ARG GO_BUILD_FLAGS
ARG TARGETPLATFORM
ARG TARGETARCH
ARG GOPROXY
RUN --mount=type=bind,target=.,rw \
--mount=type=cache,target=/root/.cache/go-build,id=vminit-build-$TARGETPLATFORM \
GOARCH=${TARGETARCH} GOPROXY=${GOPROXY} go build ${GO_DEBUG_GCFLAGS} ${GO_GCFLAGS} ${GO_BUILD_FLAGS} -o /build/vminitd -ldflags '-extldflags \"-static\" -s -w' -tags 'osusergo netgo static_build no_grpc' ./cmd/vminitd
# TODO: Use nix instructions to build crun statically
#FROM base AS crun-src
#
#ARG CRUN_VERSION=1.24
#
#WORKDIR /usr/src/crun
#RUN git init . && git remote add origin "https://github.com/containers/crun.git"
#
#RUN git fetch -q --depth 1 origin "${CRUN_VERSION}" +refs/tags/*:refs/tags/* && git checkout -q FETCH_HEAD
#
#FROM base AS crun-build
#WORKDIR /go/src/github.com/containers/crun
#ARG TARGETPLATFORM
#RUN --mount=type=cache,sharing=locked,id=crun-aptlib,target=/var/lib/apt \
# --mount=type=cache,sharing=locked,id=crun-aptcache,target=/var/cache/apt \
# apt-get update && apt-get install -y --no-install-recommends \
# make git gcc build-essential pkgconf libtool \
# libsystemd-dev libprotobuf-c-dev libcap-dev libseccomp-dev libyajl-dev \
# go-md2man autoconf python3 automake
#RUN --mount=from=crun-src,src=/usr/src/crun,rw \
# --mount=type=cache,target=/root/.cache/go-build,id=crun-build-$TARGETPLATFORM <<EOT
# set -e
# ./autogen.sh
# ./configure
# make
# mkdir /build
# mv crun /build/
#EOT
FROM base AS crun-build
WORKDIR /usr/src/crun
ARG TARGETARCH
RUN mkdir /build && wget -O /build/crun https://github.com/containers/crun/releases/download/1.24/crun-1.24-linux-${TARGETARCH}-disable-systemd
FROM base AS erofs-build
WORKDIR /usr/src/rootfs
ARG TARGETPLATFORM
RUN --mount=type=cache,sharing=locked,id=erofs-aptlib,target=/var/lib/apt \
--mount=type=cache,sharing=locked,id=erofs-aptcache,target=/var/cache/apt \
apt-get update && apt-get install -y --no-install-recommends erofs-utils
# Create all mount-point directories required by vminitd's systemMounts.
# /etc is included so that a tmpfs can be mounted over it at runtime,
# making it writable even though the erofs image itself is read-only.
# /var/run is a symlink to /run so that crun state writes land on the
# writable /run tmpfs rather than failing against the read-only rootfs.
RUN mkdir -p dev etc proc run sbin sys tmp var && ln -s /run var/run
COPY --from=vminit-build /build/vminitd ./sbin/vminitd
COPY --from=crun-build /build/crun ./sbin/crun
RUN <<EOT
set -e
chmod +x sbin/vminitd sbin/crun
mkdir /build
mkfs.erofs -zlz4 /build/nerdbox-rootfs.erofs .
EOT
FROM scratch AS kernel
ARG KERNEL_ARCH="x86_64"
COPY --from=kernel-build /build/kernel /nerdbox-kernel-${KERNEL_ARCH}
FROM scratch AS erofs
COPY --from=erofs-build /build/nerdbox-rootfs.erofs /nerdbox-rootfs.erofs
FROM scratch AS shim
COPY --from=shim-build /build/containerd-shim-nerdbox-v1 /containerd-shim-nerdbox-v1
FROM "${DOCKER_IMAGE}" AS docker-cli
FROM "${GOLANG_IMAGE}" AS dlv
RUN go install github.com/go-delve/delve/cmd/dlv@latest
FROM "${RUST_IMAGE}" AS libkrun-build
ARG LIBKRUN_VERSION=v1.19.0
# Pin to the commit that fixes get_extent_at binary search at extent
# boundaries (merged into imago main as 1907e11b). A [patch.crates-io]
# git override substitutes by crate name regardless of version, so this
# replaces the 0.2.1 locked by libkrun's Cargo.lock without any sed patching.
ARG IMAGO_FIX_REV=1907e11b2e1420bd3a6aec1d697a2301c6916f74
RUN --mount=type=cache,sharing=locked,id=libkrun-aptlib,target=/var/lib/apt \
--mount=type=cache,sharing=locked,id=libkrun-aptcache,target=/var/cache/apt \
apt-get update && apt-get install -y git libcap-ng-dev libclang-19-dev llvm make
COPY script/patches/ /patches/
RUN git clone --depth 1 --branch ${LIBKRUN_VERSION} https://github.com/containers/libkrun.git && \
cd libkrun && \
git apply /patches/libkrun-*.patch && \
printf '\n[patch.crates-io]\nimago = { git = "https://gitlab.com/hreitz/imago.git", rev = "%s" }\n' \
"${IMAGO_FIX_REV}" >> Cargo.toml && \
cargo update imago && \
make -j$(nproc) BLK=1 NET=1
FROM scratch AS libkrun
COPY --from=libkrun-build /libkrun/target/release/libkrun.so /libkrun.so
FROM ${GOLANG_IMAGE} AS dev
ARG CONTAINERD_VERSION=2.1.4
ARG TARGETARCH
ENV PATH=/go/src/github.com/containerd/nerdbox/_output:$PATH
WORKDIR /go/src/github.com/containerd/nerdbox
RUN --mount=type=cache,sharing=locked,id=dev-aptlib,target=/var/lib/apt \
--mount=type=cache,sharing=locked,id=dev-aptcache,target=/var/cache/apt \
apt-get update && apt-get install -y erofs-utils git make wget
RUN wget https://github.com/containerd/containerd/releases/download/v${CONTAINERD_VERSION}/containerd-${CONTAINERD_VERSION}-linux-${TARGETARCH}.tar.gz && \
tar -C /usr/local/bin --strip-components=1 -xf containerd-${CONTAINERD_VERSION}-linux-${TARGETARCH}.tar.gz && \
rm containerd-${CONTAINERD_VERSION}-linux-${TARGETARCH}.tar.gz
COPY --from=docker-cli /usr/local/bin/docker /usr/local/bin/docker
COPY --from=docker-cli /usr/local/libexec/docker/cli-plugins/docker-buildx /usr/local/libexec/docker/cli-plugins/docker-buildx
COPY --from=dlv /go/bin/dlv /usr/local/bin/dlv
COPY --from=libkrun /libkrun.so /usr/local/lib64/libkrun.so
ENV LIBKRUN_PATH=/go/src/github.com/containerd/nerdbox/_output
VOLUME /var/lib/containerd
FROM base AS golangci-build
WORKDIR /src
ARG GOLANGCI_LINT_VERSION
ADD https://github.com/golangci/golangci-lint.git#v${GOLANGCI_LINT_VERSION} .
COPY --link --from=xx / /
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/ \
xx-go --wrap && \
go mod download
RUN --mount=type=cache,target=/go/pkg/mod \
--mount=type=cache,target=/root/.cache/ \
xx-go --wrap && \
mkdir -p out && \
go build -o /out/golangci-lint ./cmd/golangci-lint
FROM scratch AS golangci-binary-false
FROM scratch AS golangci-binary-true
COPY --from=golangci-build /out/golangci-lint golangci-lint
FROM golangci-binary-${GOLANGCI_FROM_SOURCE} AS golangci-binary
FROM base AS lint-base
ENV GOFLAGS="-buildvcs=false"
RUN <<EOT
apt-get update
apt-get install -y --no-install-recommends gcc libc6-dev yamllint
rm -rf /var/lib/apt/lists/*
EOT
ARG GOLANGCI_LINT_VERSION
ARG GOLANGCI_FROM_SOURCE
COPY --link --from=golangci-binary / /usr/bin/
RUN [ "${GOLANGCI_FROM_SOURCE}" = "true" ] && exit 0; wget -O- -nv https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s v${GOLANGCI_LINT_VERSION}
COPY --link --from=xx / /
WORKDIR /go/src/github.com/containerd/nerdbox
FROM lint-base AS golangci-lint
ARG TARGETNAME
ARG TARGETPLATFORM
RUN --mount=target=/go/src/github.com/containerd/nerdbox \
--mount=target=/root/.cache,type=cache,id=lint-cache-${TARGETNAME}-${TARGETPLATFORM} \
xx-go --wrap && \
golangci-lint run -c .golangci.yml && \
touch /golangci-lint.done
FROM lint-base AS golangci-verify-false
RUN --mount=target=/go/src/github.com/containerd/nerdbox \
golangci-lint config verify && \
touch /golangci-verify.done
FROM scratch AS golangci-verify-true
COPY <<EOF /golangci-verify.done
EOF
FROM golangci-verify-${GOLANGCI_FROM_SOURCE} AS golangci-verify
FROM lint-base AS yamllint
RUN --mount=target=/go/src/github.com/containerd/nerdbox \
yamllint -c .yamllint.yml --strict . && \
touch /yamllint.done
FROM scratch AS lint
COPY --link --from=golangci-lint /golangci-lint.done /
COPY --link --from=golangci-verify /golangci-verify.done /
COPY --link --from=yamllint /yamllint.done /