-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathDockerfile
More file actions
172 lines (154 loc) · 8.07 KB
/
Copy pathDockerfile
File metadata and controls
172 lines (154 loc) · 8.07 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
# syntax=docker/dockerfile:1.7
# rustbgpd container image.
#
# Two consumable stages:
#
# runtime (DEFAULT) — lean production image: the daemon, the `rbgp`
# CLI, and the Birdwatcher adapter, nonroot user, nothing else. This is what the GHCR release
# image publishes (.github/workflows/container.yml builds the
# default target). Built with the full `release` profile (fat-LTO,
# codegen-units=1) and `--features jemalloc` — the exact build
# every number in docs/benchmarks.md is measured on.
# dev — interop / CI / lab image: adds the EVPN load-gen helpers
# (evpn-tester / evpn-monitor), the interop start script, and
# iproute2/ping for containerlab topologies. Built with the fast
# `ci` profile — interop M-jobs rebuild this image constantly and
# the fat-LTO serial link would slow every lab run.
#
# Multi-stage build with cargo-chef separating dep compilation from
# workspace compilation. Two builder stages share the planner recipe
# and the BuildKit cache mounts; only the stages a given --target
# needs are built.
#
# Cache levers:
# - cargo-chef: dep build layer invalidates only on Cargo.lock change
# - BuildKit cache mounts: registry + target persist across builds
# - mold linker: parallel final link, faster than the default GNU ld
#
# Build:
# docker build -t rustbgpd:latest . # lean runtime
# docker build --target dev -t rustbgpd:dev . # dev / interop
#
# BuildKit is required for the `RUN --mount=type=cache` directives
# below; the legacy Docker builder rejects them with a parse error.
# Modern Docker (>= 23.0) and buildx enable BuildKit by default, and
# the CI workflows use `docker/build-push-action@v7` which is
# BuildKit-native — see .github/workflows/interop.yml and
# kernel-dataplane.yml. If you hit a parse error on the cache mounts,
# either upgrade Docker or set `DOCKER_BUILDKIT=1` explicitly.
FROM rust:1.95-bookworm AS chef
RUN apt-get update && apt-get install -y --no-install-recommends \
protobuf-compiler \
mold \
&& rm -rf /var/lib/apt/lists/* \
&& cargo install cargo-chef --version 0.1.71 --locked
WORKDIR /build
# Use mold for every cargo link in this stage and all stages that inherit.
ENV RUSTFLAGS="-C link-arg=-fuse-ld=mold"
FROM chef AS planner
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
# ── builder: fast `ci`-profile build for the dev image ───────────────
FROM chef AS builder
COPY --from=planner /build/recipe.json recipe.json
# Cook deps under cache mounts. Dep layer invalidates only when
# Cargo.lock changes; everyday source-only commits skip this step.
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
--mount=type=cache,target=/build/target,sharing=locked \
cargo chef cook --profile ci --recipe-path recipe.json
COPY . .
# Build workspace + stash binaries outside the cache mount so the
# final-stage COPY can find them. The target/ cache directory is a
# tmpfs-style mount that the next stage cannot read directly.
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
--mount=type=cache,target=/build/target,sharing=locked \
cargo build --workspace --profile ci && \
mkdir -p /out && \
cp target/ci/rustbgpd /out/ && \
cp target/ci/rbgp /out/ && \
cp target/ci/evpn-tester /out/ && \
cp target/ci/evpn-monitor /out/
# ── builder-release: benchmarked-profile build for the runtime image ─
# Full `release` profile (fat-LTO, codegen-units=1) with jemalloc as
# the global allocator — the published image must be the same build
# the benchmarks are measured on, not the CI-shaped one.
FROM chef AS builder-release
COPY --from=planner /build/recipe.json recipe.json
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
--mount=type=cache,target=/build/target,sharing=locked \
cargo chef cook --release --features rustbgpd/jemalloc --recipe-path recipe.json
COPY . .
RUN --mount=type=cache,target=/usr/local/cargo/registry,sharing=locked \
--mount=type=cache,target=/usr/local/cargo/git,sharing=locked \
--mount=type=cache,target=/build/target,sharing=locked \
cargo build --release --features rustbgpd/jemalloc \
-p rustbgpd -p rustbgpctl -p birdwatcher-adapter && \
mkdir -p /out && \
cp target/release/rustbgpd /out/ && \
cp target/release/rbgp /out/ && \
cp target/release/birdwatcher-adapter /out/ && \
# Bash completions for the runtime image, generated by the shipped
# binary itself so they never drift from the build.
/out/rbgp completions bash > /out/rbgp.bash-completion
# ── dev: interop / CI / lab image ────────────────────────────────────
# Ships the daemon + CLI plus the development-only helpers the
# containerlab topologies and soak harnesses expect. Runs as root so
# labs can program links/netns freely.
FROM debian:bookworm-slim AS dev
RUN apt-get update && apt-get install -y --no-install-recommends \
iproute2 \
iputils-ping \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /out/rustbgpd /usr/local/bin/rustbgpd
COPY --from=builder /out/rbgp /usr/local/bin/rbgp
COPY --from=builder /out/evpn-tester /usr/local/bin/evpn-tester
COPY --from=builder /out/evpn-monitor /usr/local/bin/evpn-monitor
COPY tests/interop/scripts/start-rustbgpd.sh /usr/local/bin/start-rustbgpd.sh
RUN mkdir -p /var/lib/rustbgpd
EXPOSE 179 9179
# Default: run daemon with config at /etc/rustbgpd/config.toml
# Interop tests override with: docker run ... sleep infinity
CMD ["rustbgpd", "/etc/rustbgpd/config.toml"]
# ── runtime: lean production image (DEFAULT target) ──────────────────
# Daemon + rbgp + Birdwatcher adapter — no dev/test/bench helpers. Binaries come from
# builder-release (fat-LTO + jemalloc, the benchmarked build). Runs as
# a nonroot user; Docker's default net.ipv4.ip_unprivileged_port_start=0 lets it
# bind port 179 (grant CAP_NET_BIND_SERVICE explicitly on runtimes
# that don't, e.g. some Kubernetes setups). Kernel-dataplane features
# (Linux FIB / EVPN VTEP) additionally need CAP_NET_ADMIN — see
# docs/how-to/deployment.md.
FROM debian:bookworm-slim AS runtime
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/* \
# uid/gid pinned, not allocated. docs/how-to/deployment.md tells
# operators to chown host bind mounts to 999; an unpinned system
# account shifts whenever the base image adds an earlier one, and
# every pre-chown'd directory silently becomes EACCES.
&& groupadd --system --gid 999 rustbgpd \
&& useradd --system --uid 999 --gid 999 --home-dir /var/lib/rustbgpd \
--shell /usr/sbin/nologin rustbgpd \
&& mkdir -p /var/lib/rustbgpd \
&& chown rustbgpd:rustbgpd /var/lib/rustbgpd
COPY --from=builder-release /out/rustbgpd /usr/local/bin/rustbgpd
COPY --from=builder-release /out/rbgp /usr/local/bin/rbgp
COPY --from=builder-release /out/birdwatcher-adapter /usr/local/bin/birdwatcher-adapter
# Conventional bash-completion drop-in path: picked up automatically
# when the bash-completion package is present (e.g. docker exec with an
# interactive shell on a derived image).
COPY --from=builder-release /out/rbgp.bash-completion /usr/share/bash-completion/completions/rbgp
COPY LICENSE-MIT LICENSE-APACHE /
# Numeric, not the account name: Kubernetes `runAsNonRoot: true` cannot
# resolve a name-form USER and fails the container at admission unless
# the pod spec repeats `runAsUser`.
USER 999:999
EXPOSE 179 9179
# Authenticated gRPC responsiveness only; core actor readiness is available
# through an explicit `rbgp health` override. The default endpoint is the
# local socket; set RUSTBGPD_ADDR if configuration moves it.
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD rbgp health --liveness
CMD ["rustbgpd", "/etc/rustbgpd/config.toml"]