-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ci: Refactor Dockerfile & entrypoint #8923
base: main
Are you sure you want to change the base?
Changes from 27 commits
64be0ae
a248b14
ca1620c
ea8b119
7cba8cf
56c65e6
be38132
0492b7a
6595740
22dc738
962d4d3
621754b
6b68592
c788ccc
38837e4
b58a602
2ada296
99cd18f
c718609
69b03d4
6932d9a
6fe460d
c5010b8
e05df78
e9f0479
7422ecf
4fa064c
afeb05f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -151,19 +151,6 @@ jobs: | |||||
test_variables: '-e NETWORK' | ||||||
network: 'Mainnet' | ||||||
|
||||||
# Test reconfiguring the the docker image for tesnet. | ||||||
test-configuration-file-testnet: | ||||||
name: Test CI testnet Docker config file | ||||||
# Make sure Zebra can sync the genesis block on testnet | ||||||
uses: ./.github/workflows/sub-test-zebra-config.yml | ||||||
with: | ||||||
test_id: 'testnet-conf' | ||||||
docker_image: ${{ vars.GAR_BASE }}/${{ vars.CI_IMAGE_NAME }}@${{ inputs.image_digest }} | ||||||
grep_patterns: '-e "net.*=.*Test.*estimated progress to chain tip.*Genesis" -e "net.*=.*Test.*estimated progress to chain tip.*BeforeOverwinter"' | ||||||
# TODO: improve the entrypoint to avoid using `ENTRYPOINT_FEATURES=""` | ||||||
test_variables: '-e NETWORK -e ZEBRA_CONF_PATH="/etc/zebrad/zebrad.toml" -e ENTRYPOINT_FEATURES=""' | ||||||
network: 'Testnet' | ||||||
|
||||||
Comment on lines
-154
to
-166
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test was created to confirm that any change we do in CI or in Docker doesn't affect the ability to read the proper There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This test is failing with this PR, similarly to the other one. I have a better approach in mind, which I didn't do in this PR. Let's add it back in a subsequent PR? Moreover, there seem to be some parts that are bugs or hard to understand. For example, I couldn't figure out what There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
zebra/.github/workflows/sub-test-zebra-config.yml Lines 90 to 91 in 46c6b6e
I do agree that setting the I'd suggest commenting this and adding a TODO in top of it, or creating an issue, instead of removing the test. Just so we don't forget later on, as this is an important validation. |
||||||
# Test that Zebra works using $ZEBRA_CONF_PATH config | ||||||
test-zebra-conf-path: | ||||||
name: Test CI custom Docker config file | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,11 +3,12 @@ | |
|
||
# If you want to include a file in the Docker image, add it to .dockerignore. | ||
# | ||
# We are using 4 stages: | ||
# We are using 4 (TODO: 5) stages: | ||
# - deps: install build dependencies and sets the needed variables | ||
# - tests: builds tests binaries | ||
# - release: builds release binaries | ||
# - runtime: runs the release binaries | ||
# - 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. | ||
|
@@ -21,7 +22,8 @@ ARG TEST_FEATURES="lightwalletd-grpc-tests zebra-checkpoints" | |
ARG EXPERIMENTAL_FEATURES="" | ||
|
||
ARG APP_HOME="/opt/zebrad" | ||
ARG RUST_VERSION=1.79.0 | ||
ARG RUST_VERSION=1.81.0 | ||
|
||
# In this stage we download all system requirements to build the project | ||
# | ||
# It also captures all the build arguments to be used as environment variables. | ||
|
@@ -67,10 +69,9 @@ ENV SHORT_SHA=${SHORT_SHA:-} | |
|
||
ENV CARGO_HOME="${APP_HOME}/.cargo/" | ||
|
||
# Copy the entrypoint script to be used on both images | ||
COPY ./docker/entrypoint.sh /etc/zebrad/entrypoint.sh | ||
COPY ./docker/entrypoint.sh /usr/local/bin/entrypoint.sh | ||
|
||
# In this stage we build tests (without running then) | ||
# 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. | ||
|
@@ -116,9 +117,9 @@ RUN --mount=type=bind,source=zebrad,target=zebrad \ | |
--mount=type=cache,target=${APP_HOME}/target/ \ | ||
--mount=type=cache,target=/usr/local/cargo/git/db \ | ||
--mount=type=cache,target=/usr/local/cargo/registry/ \ | ||
cargo test --locked --release --features "${ENTRYPOINT_FEATURES}" --workspace --no-run && \ | ||
cp ${APP_HOME}/target/release/zebrad /usr/local/bin && \ | ||
cp ${APP_HOME}/target/release/zebra-checkpoints /usr/local/bin | ||
cargo test --locked --release --features "${ENTRYPOINT_FEATURES}" --workspace --no-run && \ | ||
cp ${APP_HOME}/target/release/zebrad /usr/local/bin && \ | ||
cp ${APP_HOME}/target/release/zebra-checkpoints /usr/local/bin | ||
|
||
# Copy the lightwalletd binary and source files to be able to run tests | ||
COPY --from=electriccoinco/lightwalletd:latest /usr/local/bin/lightwalletd /usr/local/bin/ | ||
|
@@ -130,8 +131,8 @@ ENV ENTRYPOINT_FEATURES=${ENTRYPOINT_FEATURES} | |
ARG EXPERIMENTAL_FEATURES="journald prometheus filter-reload" | ||
ENV ENTRYPOINT_FEATURES_EXPERIMENTAL="${ENTRYPOINT_FEATURES} ${EXPERIMENTAL_FEATURES}" | ||
|
||
# By default, runs the entrypoint tests specified by the environmental variables (if any are set) | ||
ENTRYPOINT [ "/etc/zebrad/entrypoint.sh" ] | ||
# Run tests specified by the env vars | ||
ENTRYPOINT [ "entrypoint.sh", "test" ] | ||
|
||
# In this stage we build a release (generate the zebrad binary) | ||
# | ||
|
@@ -161,68 +162,48 @@ RUN --mount=type=bind,source=tower-batch-control,target=tower-batch-control \ | |
--mount=type=cache,target=${APP_HOME}/target/ \ | ||
--mount=type=cache,target=/usr/local/cargo/git/db \ | ||
--mount=type=cache,target=/usr/local/cargo/registry/ \ | ||
cargo build --locked --release --features "${FEATURES}" --package zebrad --bin zebrad && \ | ||
cp ${APP_HOME}/target/release/zebrad /usr/local/bin | ||
cargo build --locked --release --features "${FEATURES}" --package zebrad --bin zebrad && \ | ||
cp ${APP_HOME}/target/release/zebrad /usr/local/bin | ||
|
||
# This stage is only used when deploying nodes or when only the resulting zebrad binary is needed | ||
# | ||
# To save space, this step starts from scratch using debian, and only adds the resulting | ||
# binary from the `release` stage | ||
# This step starts from scratch using Debian and only adds the resulting binary | ||
# from the `release` stage. | ||
FROM debian:bookworm-slim AS runtime | ||
|
||
# Set the default path for the zebrad binary | ||
ARG APP_HOME | ||
ENV APP_HOME=${APP_HOME} | ||
WORKDIR ${APP_HOME} | ||
Comment on lines
-174
to
-176
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should set a The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. System users should have no home dir and should not even be able to log in to the machine. Our users should use
I wanted to describe this in our docs in a subsequent PR. Is it OK if we do it like that? |
||
|
||
RUN apt-get update && \ | ||
apt-get install -y --no-install-recommends \ | ||
ca-certificates \ | ||
curl \ | ||
rocksdb-tools \ | ||
gosu \ | ||
&& rm -rf /var/lib/apt/lists/* /tmp/* | ||
COPY --from=release /usr/local/bin/zebrad /usr/local/bin/ | ||
COPY --from=release /usr/local/bin/entrypoint.sh /usr/local/bin/ | ||
|
||
# Create a non-privileged user that the app will run under. | ||
# Running as root inside the container is running as root in the Docker host | ||
# If an attacker manages to break out of the container, they will have root access to the host | ||
# See https://docs.docker.com/go/dockerfile-user-best-practices/ | ||
ARG USER=zebra | ||
# Create a non-privileged user for running `zebrad`. | ||
# | ||
# ## Security | ||
# | ||
# If an attacker manages to break out of the container, they will have root | ||
# access to the host. [1][1] | ||
# | ||
# [1]: https://docs.docker.com/go/dockerfile-user-best-practices/ | ||
ARG USER="zebra" | ||
ENV USER=${USER} | ||
ARG UID=10001 | ||
ENV UID=${UID} | ||
ARG GID=10001 | ||
ENV GID=${GID} | ||
|
||
RUN addgroup --system --gid ${GID} ${USER} \ | ||
&& adduser \ | ||
--system \ | ||
--disabled-login \ | ||
--shell /bin/bash \ | ||
--home ${APP_HOME} \ | ||
--uid "${UID}" \ | ||
--gid "${GID}" \ | ||
${USER} | ||
Comment on lines
-192
to
-205
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There might be instances where a user would like to (re-)build the image with a custom UID:GUID, as they might require to mount files from their host, which will be incompatible with the UID:GUID of the container user, and it's also a good Docker practice to specify the UID for the default user for other edge-cases. Unless there's a good reason to remove this, I'd suggest to keep it. The PR that added this has some references to the reasoning behind it: #8803 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that we're creating a system user. Those users should have UIDs in [1, 999]. In Debian, the docs for Moreover, the Linux spec says that system UIDs in [100, 499] should be reserved for dynamic allocation: https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/uidrange.html I'm surprised the Docker docs don't mention this.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unfortunately, this is not clear in Docker's documentation. But some of their tools, ARG UID=10001
RUN adduser \
--disabled-password \
--gecos "" \
--home "/nonexistent" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
appuser
USER appuser In any case, to match their recommendation in
They main reasons to keep this instruction are:
Additionally, this is very common in Docker, and plenty of projects use this approach to deal with these and other use-cases: https://github.com/search?q=%22useradd%22+%22--uid%22++language%3ADockerfile&type=code |
||
|
||
# Config settings for zebrad | ||
ARG FEATURES | ||
ENV FEATURES=${FEATURES} | ||
Comment on lines
-208
to
-209
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, but that var is not used in any meaningful way in There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's used here: From our documentation, if we suggest: docker build -f ./docker/Dockerfile --target runtime --build-arg FEATURES='default-release-binaries prometheus' --tag local/zebra.mining:latest . The |
||
|
||
# Path and name of the config file | ||
# These are set to a default value when not defined in the environment | ||
ENV ZEBRA_CONF_DIR=${ZEBRA_CONF_DIR:-/etc/zebrad} | ||
ENV ZEBRA_CONF_FILE=${ZEBRA_CONF_FILE:-zebrad.toml} | ||
RUN adduser --system ${USER} | ||
|
||
RUN mkdir -p ${ZEBRA_CONF_DIR} && chown ${UID}:${UID} ${ZEBRA_CONF_DIR} \ | ||
&& chown ${UID}:${UID} ${APP_HOME} | ||
Comment on lines
-216
to
-217
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having a There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. System users should have no home dir. Our users should go with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we're not allowing the user to log in with the user running Zebra, then we should document the approach they can use to get a |
||
ARG ZEBRA_CONF_DIR="/etc/zebrad" | ||
ENV ZEBRA_CONF_DIR=${ZEBRA_CONF_DIR} | ||
RUN mkdir -p ${ZEBRA_CONF_DIR} && chown ${USER} ${ZEBRA_CONF_DIR} | ||
|
||
COPY --from=release /usr/local/bin/zebrad /usr/local/bin | ||
COPY --from=release /etc/zebrad/entrypoint.sh /etc/zebrad | ||
# TODO: Shorten `ZEBRA_CACHED_STATE_DIR` to `ZEBRA_CACHE_DIR` | ||
ARG ZEBRA_CACHED_STATE_DIR="/var/cache/zebrad" | ||
ENV ZEBRA_CACHED_STATE_DIR=${ZEBRA_CACHED_STATE_DIR} | ||
RUN mkdir -p ${ZEBRA_CACHED_STATE_DIR} && chown ${USER} ${ZEBRA_CACHED_STATE_DIR} | ||
|
||
# Expose configured ports | ||
EXPOSE 8233 18233 | ||
gustavovalverde marked this conversation as resolved.
Show resolved
Hide resolved
|
||
USER $USER | ||
|
||
# Update the config file based on the Docker run variables, | ||
# and launch zebrad with it | ||
ENTRYPOINT [ "/etc/zebrad/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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although very simple, the objective of this test is to confirm that the
entrypoint
is able to handle a custom configuration path ($ZEBRA_CONF_PATH
), run with it and confirm that path is being used.This could be extended to validate is running with a mounted file using
--mount type=bind,source="$(pwd)"/target,target=/app
as part of thetest_variables
, but that's out of scope.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test was using a custom config file set in
test_variables
.However, the file was not included in the Docker image, and the
entrypoint script created a new, default one under the original file's
path. Zebra then loaded this new file, and the test passed because the
pattern in
grep_patterns
matched Zebra's output containing theoriginal path, even though the config file was different.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test fails in this PR due to the fixes in the entrypoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd suggest commenting this and adding a TODO in top of it, or creating an issue. Just so we don't forget later on.
Either of them I'd suggest indicating something like: