forked from ZcashFoundation/zebra
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathDockerfile
More file actions
225 lines (187 loc) · 7.98 KB
/
Copy pathDockerfile
File metadata and controls
225 lines (187 loc) · 7.98 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
# syntax=docker/dockerfile:1
# check=skip=UndefinedVar,UserExist # We use setpriv in the entrypoint instead of USER directive
# If you want to include a file in the Docker image, add it to .dockerignore.
#
# We use 4 (TODO: 5) stages:
# - deps: installs build dependencies and sets default values
# - tests: prepares a test image
# - release: builds release binaries
# - runtime: prepares the release image
# - TODO: Add a `monitoring` stage
#
# We first set default values for build arguments used across the stages.
# Each stage must define the build arguments (ARGs) it uses.
ARG RUST_VERSION=1.89.0
ARG FEATURES="default-release-binaries"
ARG UID=10001
ARG GID=${UID}
ARG USER="zebra"
ARG HOME="/home/${USER}"
ARG CARGO_HOME="${HOME}/.cargo"
ARG CARGO_TARGET_DIR="${HOME}/target"
# This stage prepares Zebra's build deps and captures build args as env vars.
FROM rust:${RUST_VERSION}-trixie AS deps
SHELL ["/bin/bash", "-xo", "pipefail", "-c"]
# Make the build platform available as a variable
ARG BUILDPLATFORM
# Install zebra build deps
RUN apt-get -qq update && \
apt-get -qq install -y --no-install-recommends \
libclang-dev \
protobuf-compiler \
&& rm -rf /var/lib/apt/lists/* /tmp/*
# Build arguments and variables
ARG CARGO_INCREMENTAL
ENV CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-0}
ARG CARGO_HOME
ENV CARGO_HOME=${CARGO_HOME}
ARG CARGO_TARGET_DIR
ENV CARGO_TARGET_DIR=${CARGO_TARGET_DIR}
# This stage builds tests without running them.
#
# We also download needed dependencies for tests to work, from other images.
# An entrypoint.sh is only available in this step for easier test handling with variables.
FROM deps AS tests
ARG SHORT_SHA
ARG FEATURES
ENV FEATURES=${FEATURES}
# Skip IPv6 tests by default, as some CI environment don't have IPv6 available
ARG SKIP_IPV6_TESTS
ENV SKIP_IPV6_TESTS=${SKIP_IPV6_TESTS:-1}
# This environment setup is almost identical to the `runtime` target so that the
# `tests` target differs minimally. In fact, a subset of this setup is used for
# the `runtime` target.
ARG UID
ENV UID=${UID}
ARG GID
ENV GID=${GID}
ARG USER
ENV USER=${USER}
ARG HOME
ENV HOME=${HOME}
RUN addgroup --quiet --gid ${GID} ${USER} && \
adduser --quiet --gid ${GID} --uid ${UID} --home ${HOME} ${USER} --disabled-password --gecos ""
# Set the working directory for the build.
WORKDIR ${HOME}
ARG CARGO_HOME
ARG CARGO_TARGET_DIR
# Download and install the pre-built cargo-nextest binary.
RUN apt-get -qq update && \
apt-get -qq install -y --no-install-recommends curl && \
mkdir -p "${CARGO_HOME}/bin" && \
case ${BUILDPLATFORM:-linux/$(uname -m)} in \
"linux/amd64"|"linux/x86_64") ARCH="linux" ;; \
"linux/arm64"|"linux/aarch64") ARCH="linux-arm" ;; \
*) echo "Unsupported architecture: ${BUILDPLATFORM:-linux/$(uname -m)}"; exit 1 ;; \
esac && \
curl -LsSf "https://get.nexte.st/latest/${ARCH}" | tar zxf - -C "${CARGO_HOME}/bin" && \
apt-get -qq remove --purge -y curl && \
apt-get -qq autoremove -y && \
rm -rf /var/lib/apt/lists/* /tmp/*
# Copy source code first to ensure consistent timestamps
COPY --link --chown=${UID}:${GID} ./ ${HOME}
# Build Zebra test binaries using nextest, but don't run them.
# This also copies the necessary binaries to /usr/local/bin.
RUN [ -n "${SHORT_SHA}" ] && export SHORT_SHA="${SHORT_SHA}" || true; \
cargo nextest run --locked --release --no-run --features "${FEATURES}" && \
# Copy binaries to standard location
cp ${CARGO_TARGET_DIR}/release/zebrad /usr/local/bin && \
# Only copy zebra-checkpoints if the feature is enabled
if echo "${FEATURES}" | grep -q "zebra-checkpoints"; then \
cp ${CARGO_TARGET_DIR}/release/zebra-checkpoints /usr/local/bin; \
fi && \
# Set proper ownership
chown -R ${UID}:${GID} ${CARGO_HOME} && \
chown -R ${UID}:${GID} ${CARGO_TARGET_DIR}
# Copy the lightwalletd binary and source files to be able to run tests
COPY --link --from=electriccoinco/lightwalletd:v0.4.17 /usr/local/bin/lightwalletd /usr/local/bin/
COPY --link --chown=${UID}:${GID} ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT [ "entrypoint.sh", "test" ]
CMD [ "cargo", "test" ]
# This stage builds the zebrad release binary.
#
# It also adds `cache mounts` as this stage is completely independent from the
# `test` stage. The resulting zebrad binary is used in the `runtime` stage.
FROM deps AS release
ARG SHORT_SHA
ARG FEATURES
ENV FEATURES=${FEATURES}
# Set the working directory for the build.
ARG HOME
WORKDIR ${HOME}
ARG CARGO_HOME
ARG CARGO_TARGET_DIR
RUN --mount=type=bind,source=tower-batch-control,target=tower-batch-control \
--mount=type=bind,source=tower-fallback,target=tower-fallback \
--mount=type=bind,source=zebra-chain,target=zebra-chain \
--mount=type=bind,source=zebra-consensus,target=zebra-consensus \
--mount=type=bind,source=zebra-network,target=zebra-network \
--mount=type=bind,source=zebra-node-services,target=zebra-node-services \
--mount=type=bind,source=zebra-rpc,target=zebra-rpc \
--mount=type=bind,source=zebra-script,target=zebra-script \
--mount=type=bind,source=zebra-state,target=zebra-state \
--mount=type=bind,source=zebra-test,target=zebra-test \
--mount=type=bind,source=zebra-utils,target=zebra-utils \
--mount=type=bind,source=zebrad,target=zebrad \
--mount=type=bind,source=Cargo.toml,target=Cargo.toml \
--mount=type=bind,source=Cargo.lock,target=Cargo.lock \
--mount=type=cache,target=${CARGO_TARGET_DIR} \
--mount=type=cache,target=${CARGO_HOME} \
[ -n "${SHORT_SHA}" ] && export SHORT_SHA="${SHORT_SHA}" || true; \
cargo build --locked --release --features "${FEATURES}" --package zebrad --bin zebrad && \
cp ${CARGO_TARGET_DIR}/release/zebrad /usr/local/bin
# This stage starts from scratch using Debian and copies the built zebrad binary
# from the `release` stage along with other binaries and files.
FROM debian:trixie-slim AS runtime
ARG FEATURES
ENV FEATURES=${FEATURES}
# Create a non-privileged user for running `zebrad`.
#
# We use a high UID/GID (10001) to avoid overlap with host system users.
# This reduces the risk of container user namespace conflicts with host accounts,
# which could potentially lead to privilege escalation if a container escape occurs.
#
# We do not use the `--system` flag for user creation since:
# 1. System user ranges (100-999) can collide with host system users
# (see: https://github.com/nginx/docker-nginx/issues/490)
# 2. There's no value added and warning messages can be raised at build time
# (see: https://github.com/dotnet/dotnet-docker/issues/4624)
#
# The high UID/GID values provide an additional security boundary in containers
# where user namespaces are shared with the host.
ARG UID
ENV UID=${UID}
ARG GID
ENV GID=${GID}
ARG USER
ENV USER=${USER}
ARG HOME
ENV HOME=${HOME}
# Install curl for healtchecks and adduser for user/group creation
RUN apt-get -q update && \
apt-get -q install -y --no-install-recommends \
adduser \
curl \
&& rm -rf /var/lib/apt/lists/* /tmp/*
RUN addgroup --quiet --gid ${GID} ${USER} && \
adduser --quiet --gid ${GID} --uid ${UID} --home ${HOME} ${USER} --disabled-password --gecos ""
WORKDIR ${HOME}
RUN chown -R ${UID}:${GID} ${HOME}
# We're explicitly NOT using the USER directive here.
# Instead, we run as root initially and use setpriv in the entrypoint.sh
# to step down to the non-privileged user. This allows us to change permissions
# on mounted volumes before running the application as a non-root user.
# User with UID=${UID} is created above and used via setpriv in entrypoint.sh.
# setpriv is part of util-linux, already included in debian:trixie-slim.
COPY --link --from=release /usr/local/bin/zebrad /usr/local/bin/
COPY --link --chown=${UID}:${GID} ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
ENTRYPOINT [ "entrypoint.sh" ]
CMD ["zebrad"]
# TODO: Add a `monitoring` stage
#
# This stage will be based on `runtime`, and initially:
#
# - run `zebrad` on Testnet
# - with mining enabled using S-nomp and `nheqminer`.
#
# We can add further functionality to this stage for further purposes.