Skip to content

Commit f0140a4

Browse files
fix(ci): Better permission and cache dirs handling in Docker (#9323)
* Use gosu only once * Remove `COLORBT_SHOW_HIDDEN` * Simplify Dockerfile * Remove `check_directory_files` from entrypoint * Remove check for `ZEBRA_CONF_PATH` in entrypoint * Simplify ownership setting for `ZEBRA_CACHE_DIR` * Simplify ownership setting for `LOG_FILE` * Refactor Dockerfile & entrypoint * Refactor vars in Dockerfile * fmt * Use `chown` for `ZEBRA_CONF_PATH` * `run_cargo_test` -> `run_test` * Make `run_test` runnable with gosu * Cosmetics * Don't pre-compile Zebra * Revert: "Don't pre-compile Zebra" * Fix the custom conf test * Reintroduce `CARGO_HOME` in Dockerfile * Pass `FEATURES` as env var to entrypoint * Fix ARGs in Dockerfile * Revert "Remove `COLORBT_SHOW_HIDDEN`" This reverts commit 960d5ca. * Specify cache state dir in CI * Specify lwd cache dir in CI * refactor: reorganize variables and avoid running entrypoint commands in subshell (#9326) * refactor(docker): improve container configuration and security - Optimize Dockerfile build stages and environment variables - Improve file operations with proper ownership - Streamline entrypoint script privilege management * refactor(docker): enhance user management and directory ownership - Add HOME argument back to ensure proper user home directory setup - Implement ownership change for the user's home directory * refactor(docker): remove redundant cache directory setup - Eliminate explicit creation and ownership setting for LWD and Zebra cache directories in Dockerfile. - Introduce default values for cache directories in entrypoint script, allowing for environment variable overrides. * fix: run all cargo commands as user * chore: reduce diff * fix: revert to more robust command array --------- Co-authored-by: Gustavo Valverde <[email protected]> Co-authored-by: Gustavo Valverde <[email protected]>
1 parent 49741e8 commit f0140a4

File tree

4 files changed

+88
-135
lines changed

4 files changed

+88
-135
lines changed

.github/workflows/sub-ci-integration-tests-gcp.yml

+12-12
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ jobs:
108108
app_name: zebrad
109109
test_id: sync-past-checkpoint
110110
test_description: Test full validation sync from a cached state
111-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_CHECKPOINT_SYNC=1"
111+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_CHECKPOINT_SYNC=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
112112
needs_zebra_state: true
113113
saves_to_disk: false
114114
disk_suffix: checkpoint
@@ -178,7 +178,7 @@ jobs:
178178
app_name: zebrad
179179
test_id: update-to-tip
180180
test_description: Test syncing to tip with a Zebra tip state
181-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_UPDATE_SYNC=1"
181+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_UPDATE_SYNC=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
182182
needs_zebra_state: true
183183
# update the disk on every PR, to increase CI speed
184184
saves_to_disk: true
@@ -209,7 +209,7 @@ jobs:
209209
test_id: checkpoints-mainnet
210210
test_description: Generate Zebra checkpoints on mainnet
211211
# TODO: update the test to use {{ input.network }} instead?
212-
test_variables: "-e NETWORK=Mainnet -e GENERATE_CHECKPOINTS_MAINNET=1"
212+
test_variables: "-e NETWORK=Mainnet -e GENERATE_CHECKPOINTS_MAINNET=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
213213
needs_zebra_state: true
214214
# test-update-sync updates the disk on every PR, so we don't need to do it here
215215
saves_to_disk: false
@@ -285,7 +285,7 @@ jobs:
285285
app_name: zebrad
286286
test_id: checkpoints-testnet
287287
test_description: Generate Zebra checkpoints on testnet
288-
test_variables: "-e NETWORK=Testnet -e GENERATE_CHECKPOINTS_TESTNET=1"
288+
test_variables: "-e NETWORK=Testnet -e GENERATE_CHECKPOINTS_TESTNET=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
289289
network: "Testnet"
290290
needs_zebra_state: true
291291
# update the disk on every PR, to increase CI speed
@@ -316,7 +316,7 @@ jobs:
316316
app_name: lightwalletd
317317
test_id: lwd-full-sync
318318
test_description: Test lightwalletd full sync
319-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_FULL_SYNC=1 -e ZEBRA_TEST_LIGHTWALLETD=1"
319+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_FULL_SYNC=1 -e ZEBRA_TEST_LIGHTWALLETD=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
320320
# This test runs for longer than 6 hours, so it needs multiple jobs
321321
is_long_test: true
322322
needs_zebra_state: true
@@ -351,7 +351,7 @@ jobs:
351351
app_name: lightwalletd
352352
test_id: lwd-update-sync
353353
test_description: Test lightwalletd update sync with both states
354-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_UPDATE_SYNC=1 -e ZEBRA_TEST_LIGHTWALLETD=1"
354+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_UPDATE_SYNC=1 -e ZEBRA_TEST_LIGHTWALLETD=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra -e LWD_CACHE_DIR=/home/zebra/.cache/lwd"
355355
needs_zebra_state: true
356356
needs_lwd_state: true
357357
saves_to_disk: true
@@ -379,7 +379,7 @@ jobs:
379379
app_name: lightwalletd
380380
test_id: fully-synced-rpc
381381
test_description: Test lightwalletd RPC with a Zebra tip state
382-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_RPC_CALL=1 -e ZEBRA_TEST_LIGHTWALLETD=1"
382+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_RPC_CALL=1 -e ZEBRA_TEST_LIGHTWALLETD=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
383383
needs_zebra_state: true
384384
saves_to_disk: false
385385
secrets: inherit
@@ -401,7 +401,7 @@ jobs:
401401
app_name: lightwalletd
402402
test_id: lwd-send-transactions
403403
test_description: Test sending transactions via lightwalletd
404-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_TRANSACTIONS=1 -e ZEBRA_TEST_LIGHTWALLETD=1"
404+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_TRANSACTIONS=1 -e ZEBRA_TEST_LIGHTWALLETD=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra -e LWD_CACHE_DIR=/home/zebra/.cache/lwd"
405405
needs_zebra_state: true
406406
needs_lwd_state: true
407407
saves_to_disk: false
@@ -424,7 +424,7 @@ jobs:
424424
app_name: lightwalletd
425425
test_id: lwd-grpc-wallet
426426
test_description: Test gRPC calls via lightwalletd
427-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_GRPC=1 -e ZEBRA_TEST_LIGHTWALLETD=1"
427+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_LWD_GRPC=1 -e ZEBRA_TEST_LIGHTWALLETD=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra -e LWD_CACHE_DIR=/home/zebra/.cache/lwd"
428428
needs_zebra_state: true
429429
needs_lwd_state: true
430430
saves_to_disk: false
@@ -451,7 +451,7 @@ jobs:
451451
app_name: zebrad
452452
test_id: get-block-template
453453
test_description: Test getblocktemplate RPC method via Zebra's rpc server
454-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_GET_BLOCK_TEMPLATE=1"
454+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_GET_BLOCK_TEMPLATE=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
455455
needs_zebra_state: true
456456
needs_lwd_state: false
457457
saves_to_disk: false
@@ -474,7 +474,7 @@ jobs:
474474
app_name: zebrad
475475
test_id: submit-block
476476
test_description: Test submitting blocks via Zebra's rpc server
477-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_SUBMIT_BLOCK=1"
477+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_SUBMIT_BLOCK=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
478478
needs_zebra_state: true
479479
needs_lwd_state: false
480480
saves_to_disk: false
@@ -497,7 +497,7 @@ jobs:
497497
app_name: zebra-scan
498498
test_id: scanner-tests
499499
test_description: Tests the scanner.
500-
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_SCANNER=1"
500+
test_variables: "-e NETWORK=${{ inputs.network || vars.ZCASH_NETWORK }} -e TEST_SCANNER=1 -e ZEBRA_CACHE_DIR=/home/zebra/.cache/zebra"
501501
needs_zebra_state: true
502502
needs_lwd_state: false
503503
saves_to_disk: false

.github/workflows/sub-ci-unit-tests-docker.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ jobs:
181181
with:
182182
test_id: "custom-conf"
183183
docker_image: ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ inputs.image_digest }}
184-
test_variables: '-e ZEBRA_CONF_PATH="zebrad/tests/common/configs/custom-conf.toml"'
184+
test_variables: '-e ZEBRA_CONF_PATH="/home/zebra/zebrad/tests/common/configs/custom-conf.toml"'
185185
grep_patterns: '-e "extra_coinbase_data:\sSome\(\"do you even shield\?\"\)"'
186186

187187
failure-issue:

docker/Dockerfile

+42-69
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,29 @@
33

44
# If you want to include a file in the Docker image, add it to .dockerignore.
55
#
6-
# We are using 4 (TODO: 5) stages:
6+
# We use 4 (TODO: 5) stages:
77
# - deps: installs build dependencies and sets default values
8-
# - tests: builds tests binaries
8+
# - tests: prepares a test image
99
# - release: builds release binaries
10-
# - runtime: runs the release binaries
10+
# - runtime: prepares the release image
1111
# - TODO: Add a `monitoring` stage
1212
#
1313
# We first set default values for build arguments used across the stages.
1414
# Each stage must define the build arguments (ARGs) it uses.
1515

16-
# Build zebrad with these features
17-
#
18-
# Keep these argument defaults in sync with GitHub vars.RUST_PROD_FEATURES
16+
ARG RUST_VERSION=1.85.0
17+
18+
# Keep in sync with vars.RUST_PROD_FEATURES in GitHub
1919
# https://github.com/ZcashFoundation/zebra/settings/variables/actions
2020
ARG FEATURES="default-release-binaries"
2121

22-
ARG USER="zebra"
2322
ARG UID=10001
24-
ARG GID=10001
23+
ARG GID=${UID}
24+
ARG USER="zebra"
2525
ARG HOME="/home/${USER}"
26+
ARG CARGO_HOME="${HOME}/.cargo"
2627

27-
ARG RUST_VERSION=1.85.0
28-
# In this stage we download all system requirements to build the project
29-
#
30-
# It also captures all the build arguments to be used as environment variables.
31-
# We set defaults for the arguments, in case the build does not include this information.
28+
# This stage prepares Zebra's build deps and captures build args as env vars.
3229
FROM rust:${RUST_VERSION}-bookworm AS deps
3330
SHELL ["/bin/bash", "-xo", "pipefail", "-c"]
3431

@@ -39,25 +36,20 @@ RUN apt-get -qq update && \
3936
protobuf-compiler \
4037
&& rm -rf /var/lib/apt/lists/* /tmp/*
4138

42-
# Build arguments and variables set for tracelog levels and debug information
43-
ARG RUST_LOG
44-
ENV RUST_LOG=${RUST_LOG:-info}
45-
46-
ARG RUST_BACKTRACE
47-
ENV RUST_BACKTRACE=${RUST_BACKTRACE:-1}
48-
49-
ARG RUST_LIB_BACKTRACE
50-
ENV RUST_LIB_BACKTRACE=${RUST_LIB_BACKTRACE:-1}
51-
52-
ARG COLORBT_SHOW_HIDDEN
53-
ENV COLORBT_SHOW_HIDDEN=${COLORBT_SHOW_HIDDEN:-1}
54-
39+
# Build arguments and variables
5540
ARG CARGO_INCREMENTAL
5641
ENV CARGO_INCREMENTAL=${CARGO_INCREMENTAL:-0}
5742

58-
ARG SHORT_SHA
59-
# If this is not set, it must be an empty string, so Zebra can try an alternative git commit source:
43+
ARG CARGO_HOME
44+
ENV CARGO_HOME=${CARGO_HOME}
45+
46+
ARG FEATURES
47+
ENV FEATURES=${FEATURES}
48+
49+
# If this is not set, it must be an empty string, so Zebra can try an
50+
# alternative git commit source:
6051
# https://github.com/ZcashFoundation/zebra/blob/9ebd56092bcdfc1a09062e15a0574c94af37f389/zebrad/src/application.rs#L179-L182
52+
ARG SHORT_SHA
6153
ENV SHORT_SHA=${SHORT_SHA:-}
6254

6355
# This stage builds tests without running them.
@@ -66,9 +58,6 @@ ENV SHORT_SHA=${SHORT_SHA:-}
6658
# An entrypoint.sh is only available in this step for easier test handling with variables.
6759
FROM deps AS tests
6860

69-
ARG FEATURES
70-
ENV FEATURES=${FEATURES}
71-
7261
# Skip IPv6 tests by default, as some CI environment don't have IPv6 available
7362
ARG ZEBRA_SKIP_IPV6_TESTS
7463
ENV ZEBRA_SKIP_IPV6_TESTS=${ZEBRA_SKIP_IPV6_TESTS:-1}
@@ -80,20 +69,18 @@ ARG UID
8069
ENV UID=${UID}
8170
ARG GID
8271
ENV GID=${GID}
83-
ARG HOME
84-
ENV HOME=${HOME}
8572
ARG USER
8673
ENV USER=${USER}
74+
ARG HOME
8775

88-
RUN addgroup --gid ${GID} ${USER} && \
89-
adduser --gid ${GID} --uid ${UID} --home ${HOME} ${USER}
76+
RUN addgroup --quiet --gid ${GID} ${USER} && \
77+
adduser --quiet --gid ${GID} --uid ${UID} --home ${HOME} ${USER} --disabled-password --gecos ""
9078

9179
# Set the working directory for the build.
9280
WORKDIR ${HOME}
93-
ENV CARGO_HOME="${HOME}/.cargo/"
9481

9582
# Build Zebra test binaries, but don't run them
96-
83+
#
9784
# Leverage a cache mount to /usr/local/cargo/registry/
9885
# for downloaded dependencies, a cache mount to /usr/local/cargo/git/db
9986
# for git repository dependencies, and a cache mount to ${HOME}/target/ for
@@ -136,30 +123,22 @@ COPY --from=tianon/gosu:bookworm /gosu /usr/local/bin/
136123
ENV ZEBRA_CONF_PATH="${HOME}/.config/zebrad.toml"
137124
COPY --chown=${UID}:${GID} ./docker/default-zebra-config.toml ${ZEBRA_CONF_PATH}
138125

139-
ENV LWD_CACHE_DIR="${HOME}/.cache/lwd"
140-
RUN mkdir -p ${LWD_CACHE_DIR} && \
141-
chown -R ${UID}:${GID} ${LWD_CACHE_DIR}
126+
# As the build has already run with the root user,
127+
# we need to set the correct permissions for the home and cargo home dirs owned by it.
128+
RUN chown -R ${UID}:${GID} "${HOME}" && \
129+
chown -R ${UID}:${GID} "${CARGO_HOME}"
142130

143-
# Use the same cache dir as in the production environment.
144-
ENV ZEBRA_CACHE_DIR="${HOME}/.cache/zebra"
145-
RUN mkdir -p ${ZEBRA_CACHE_DIR} && \
146-
chown -R ${UID}:${GID} ${ZEBRA_CACHE_DIR}
147-
148-
COPY ./ ${HOME}
149-
RUN chown -R ${UID}:${GID} ${HOME}
150-
151-
COPY ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
131+
COPY --chown=${UID}:${GID} ./ ${HOME}
132+
COPY --chown=${UID}:${GID} ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
152133

153134
ENTRYPOINT [ "entrypoint.sh", "test" ]
154135

155-
# In this stage we build a release (generate the zebrad binary)
136+
# This stage builds the zebrad release binary.
156137
#
157-
# This step also adds `cache mounts` as this stage is completely independent from the
158-
# `test` stage. This step is a dependency for the `runtime` stage, which uses the resulting
159-
# zebrad binary from this step.
138+
# It also adds `cache mounts` as this stage is completely independent from the
139+
# `test` stage. The resulting zebrad binary is used in the `runtime` stage.
160140
FROM deps AS release
161141

162-
ARG FEATURES
163142
ARG HOME
164143

165144
RUN --mount=type=bind,source=tower-batch-control,target=tower-batch-control \
@@ -184,8 +163,8 @@ RUN --mount=type=bind,source=tower-batch-control,target=tower-batch-control \
184163
cargo build --locked --release --features "${FEATURES}" --package zebrad --bin zebrad && \
185164
cp ${HOME}/target/release/zebrad /usr/local/bin
186165

187-
# This step starts from scratch using Debian and only adds the resulting binary
188-
# from the `release` stage.
166+
# This stage starts from scratch using Debian and copies the built zebrad binary
167+
# from the `release` stage along with other binaries and files.
189168
FROM debian:bookworm-slim AS runtime
190169

191170
ARG FEATURES
@@ -209,28 +188,22 @@ ARG UID
209188
ENV UID=${UID}
210189
ARG GID
211190
ENV GID=${GID}
212-
ARG HOME
213-
ENV HOME=${HOME}
214191
ARG USER
215192
ENV USER=${USER}
193+
ARG HOME
216194

217-
RUN addgroup --gid ${GID} ${USER} && \
218-
adduser --gid ${GID} --uid ${UID} --home ${HOME} ${USER}
195+
RUN addgroup --quiet --gid ${GID} ${USER} && \
196+
adduser --quiet --gid ${GID} --uid ${UID} --home ${HOME} ${USER} --disabled-password --gecos ""
219197

220198
WORKDIR ${HOME}
221199

222200
# We set the default locations of the conf and cache dirs according to the XDG
223201
# spec: https://specifications.freedesktop.org/basedir-spec/latest/
224202

203+
RUN chown -R ${UID}:${GID} ${HOME}
204+
225205
ARG ZEBRA_CONF_PATH="${HOME}/.config/zebrad.toml"
226206
ENV ZEBRA_CONF_PATH=${ZEBRA_CONF_PATH}
227-
COPY --chown=${UID}:${GID} ./docker/default-zebra-config.toml ${ZEBRA_CONF_PATH}
228-
229-
ARG ZEBRA_CACHE_DIR="${HOME}/.cache/zebra"
230-
ENV ZEBRA_CACHE_DIR=${ZEBRA_CACHE_DIR}
231-
RUN mkdir -p ${ZEBRA_CACHE_DIR} && chown -R ${UID}:${GID} ${ZEBRA_CACHE_DIR}
232-
233-
RUN chown -R ${UID}:${GID} ${HOME}
234207

235208
# We're explicitly NOT using the USER directive here.
236209
# Instead, we run as root initially and use gosu in the entrypoint.sh
@@ -240,9 +213,9 @@ RUN chown -R ${UID}:${GID} ${HOME}
240213

241214
# Copy the gosu binary to be able to run the entrypoint as non-root user
242215
COPY --from=tianon/gosu:bookworm /gosu /usr/local/bin/
243-
244216
COPY --from=release /usr/local/bin/zebrad /usr/local/bin/
245-
COPY ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
217+
COPY --chown=${UID}:${GID} ./docker/default-zebra-config.toml ${ZEBRA_CONF_PATH}
218+
COPY --chown=${UID}:${GID} ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh
246219

247220
ENTRYPOINT [ "entrypoint.sh" ]
248221
CMD ["zebrad"]

0 commit comments

Comments
 (0)