From f5a3cffd7f7973eca6d4279085f49680143314bc Mon Sep 17 00:00:00 2001 From: Gustavo Valverde Date: Fri, 13 Sep 2024 18:10:53 +0100 Subject: [PATCH 1/2] ref(docker): use a single Dockerfile with multistage --- .dockerignore | 36 ++++++++++++++------ .env.sample | 5 ++- Dockerfile | 90 ++++++++++++++++++++++++++++++++++++-------------- Dockerfile.dev | 70 --------------------------------------- 4 files changed, 95 insertions(+), 106 deletions(-) delete mode 100644 Dockerfile.dev diff --git a/.dockerignore b/.dockerignore index 4a28350..819bd5e 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,10 +1,26 @@ -.git/* -.dockerignore -.gitignore -**Dockerfile -**.Dockerfile - -/target/ - -*db* -cache/ +**/.DS_Store +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/charts +**/docker-compose* +**/compose.y*ml +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/secrets.dev.yaml +**/values.dev.yaml +/bin +/target +LICENSE +README.md diff --git a/.env.sample b/.env.sample index 374bbe3..7773f4e 100644 --- a/.env.sample +++ b/.env.sample @@ -1 +1,4 @@ -DATABASE_URL="sqlite://prisma/test.db" \ No newline at end of file +DATABASE_URL="postgres://myuser:mypassword@db:5432/mydb" +ETH_RPC_URL="" +OPT_RPC_URL="" +SQLX_OFFLINE=true diff --git a/Dockerfile b/Dockerfile index c70e5b2..c5c9bf5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,25 +1,65 @@ -FROM lukemathwalker/cargo-chef:latest-rust-1.78 AS chef -WORKDIR /app - -FROM chef AS planner -COPY . . -RUN cargo chef prepare --recipe-path recipe.json - -FROM chef AS builder -COPY --from=planner /app/recipe.json recipe.json -RUN apt-get update && apt-get install -y libclang-dev -# Build dependencies (this is the caching Docker layer) -RUN cargo chef cook --release --recipe-path recipe.json -# Build application -COPY . . -RUN cargo build --release --bin indexers - -# You do not need the Rust toolchain to run the binary! -FROM ubuntu:24.04 AS runtime -RUN apt-get update && \ - apt-get upgrade -y && \ - apt-get install ca-certificates -y -WORKDIR /app -COPY --from=builder /app/config.json ./config.json -COPY --from=builder /app/target/release/indexers /usr/local/bin -CMD ["/usr/local/bin/indexers"] \ No newline at end of file +# syntax=docker/dockerfile:1 + +ARG RUST_VERSION=1.81.0 +ARG APP_NAME=indexers +ARG APP_HOME=/app + +FROM rust:${RUST_VERSION}-bookworm AS build +ARG APP_NAME +ARG APP_HOME +WORKDIR ${APP_HOME} + +# Install host build dependencies. +RUN apt-get -qq update && \ + apt-get -qq install -y --no-install-recommends \ + libclang-dev \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* /tmp/* + +# Build time environment variables. +ENV CARGO_HOME="${APP_HOME}/.cargo/" +ARG SQLX_OFFLINE=true +ENV SQLX_OFFLINE=${SQLX_OFFLINE} + +# Build the application leveraging cache mounts to speed up the build process. +RUN --mount=type=bind,source=src,target=src \ + --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ + --mount=type=bind,source=Cargo.lock,target=Cargo.lock \ + --mount=type=bind,source=config.json,target=config.json \ + --mount=type=cache,target=/app/target/ \ + --mount=type=cache,target=/usr/local/cargo/git/db \ + --mount=type=cache,target=/usr/local/cargo/registry/ \ +cargo build --locked --release --bin ${APP_NAME} && \ +cp ./target/release/${APP_NAME} /bin/indexers + +######################################## +# Create a new image that only contains the runtime artifacts. +######################################## +FROM debian:bookworm AS runtime + +ARG APP_HOME + +# Create a non-privileged user that the app will run under. +ARG USER=appuser +ARG UID=10001 +ARG GID=10001 +RUN addgroup --system --gid ${GID} ${USER} \ + && adduser \ + --system \ + --disabled-login \ + --shell /bin/bash \ + --home ${APP_HOME} \ + --uid "${UID}" \ + --gid "${GID}" \ + ${USER} + +USER ${USER} + +# Copy the executable from the "build" stage. +COPY --from=build /bin/indexers /usr/local/bin + +# Expose the port that the application listens on. +EXPOSE 3000 + +# What the container should run when it is started. +CMD ["indexers"] diff --git a/Dockerfile.dev b/Dockerfile.dev deleted file mode 100644 index 11275fa..0000000 --- a/Dockerfile.dev +++ /dev/null @@ -1,70 +0,0 @@ -# Builder stage -FROM rust:1.78.0-slim-bullseye AS builder - -ARG APP_NAME=indexers - -WORKDIR /app - -# Install build dependencies -RUN apt-get update && \ - apt-get install -y \ - ca-certificates \ - pkg-config \ - libssl-dev \ - libclang-dev \ - clang \ - cmake \ - build-essential && \ - rm -rf /var/lib/apt/lists/* - -# Set environment variables for libclang -ENV LIBCLANG_PATH=/usr/lib/llvm-11/lib -ENV LLVM_CONFIG_PATH=/usr/bin/llvm-config-11 - -# Copy only the Cargo.toml and Cargo.lock files -COPY Cargo.toml Cargo.lock ./ - -# Create a dummy main.rs to build dependencies -RUN mkdir src && echo "fn main() {}" > src/main.rs - -# Build dependencies -RUN cargo build --release - -# Remove the dummy main.rs -RUN rm src/main.rs - -# Copy the actual source code -COPY . . - -ENV SQLX_OFFLINE=true - -# Build the application -RUN touch src/main.rs && cargo build --release - -# Strip the binary to reduce size -RUN strip target/release/$APP_NAME - -# Final stage -FROM debian:bullseye-slim AS release - -ARG APP_NAME=indexers -ENV APP_NAME=$APP_NAME - -WORKDIR /app - -# Copy the binary from the builder stage -COPY --from=builder /app/target/release/$APP_NAME ./$APP_NAME - -# Copy the config file -COPY --from=builder /app/config.json ./config.json - -# Install only the necessary runtime dependencies -RUN apt-get update && \ - apt-get install -y \ - ca-certificates \ - libssl1.1 && \ - rm -rf /var/lib/apt/lists/* - -EXPOSE 3000 - -CMD /app/$APP_NAME \ No newline at end of file From 888140423a59958fbffdbe6473ee89bc368af2d8 Mon Sep 17 00:00:00 2001 From: Gustavo Valverde Date: Sun, 15 Sep 2024 11:05:15 +0100 Subject: [PATCH 2/2] fix(build): missing files, permissions, and envs --- .env.sample | 3 +++ Dockerfile | 37 ++++++++++++++++++++++++++++++++----- docker-compose.yml | 17 +++++++++++------ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/.env.sample b/.env.sample index 7773f4e..689e0e3 100644 --- a/.env.sample +++ b/.env.sample @@ -1,3 +1,6 @@ +POSTGRES_DB=mydb +POSTGRES_USER=myuser +POSTGRES_PASSWORD=mypassword DATABASE_URL="postgres://myuser:mypassword@db:5432/mydb" ETH_RPC_URL="" OPT_RPC_URL="" diff --git a/Dockerfile b/Dockerfile index c5c9bf5..0f4bd8d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,10 @@ # syntax=docker/dockerfile:1 ARG RUST_VERSION=1.81.0 -ARG APP_NAME=indexers ARG APP_HOME=/app FROM rust:${RUST_VERSION}-bookworm AS build -ARG APP_NAME + ARG APP_HOME WORKDIR ${APP_HOME} @@ -16,21 +15,40 @@ RUN apt-get -qq update && \ ca-certificates \ && rm -rf /var/lib/apt/lists/* /tmp/* -# Build time environment variables. +# Build arguments and variables set for tracelog levels and debug information +# +# We set defaults to all variables. +ARG RUST_LOG +ENV RUST_LOG=${RUST_LOG:-info} + +ARG RUST_BACKTRACE +ENV RUST_BACKTRACE=${RUST_BACKTRACE:-1} + +ARG RUST_LIB_BACKTRACE +ENV RUST_LIB_BACKTRACE=${RUST_LIB_BACKTRACE:-1} + ENV CARGO_HOME="${APP_HOME}/.cargo/" + +# Application specific environment variables. ARG SQLX_OFFLINE=true ENV SQLX_OFFLINE=${SQLX_OFFLINE} +ARG ETH_RPC_URL +ENV ETH_RPC_URL=${ETH_RPC_URL} +ARG OPT_RPC_URL +ENV OPT_RPC_URL=${OPT_RPC_URL} # Build the application leveraging cache mounts to speed up the build process. RUN --mount=type=bind,source=src,target=src \ + --mount=type=bind,source=abis,target=abis \ + --mount=type=bind,source=.sqlx,target=.sqlx \ --mount=type=bind,source=Cargo.toml,target=Cargo.toml \ --mount=type=bind,source=Cargo.lock,target=Cargo.lock \ --mount=type=bind,source=config.json,target=config.json \ --mount=type=cache,target=/app/target/ \ --mount=type=cache,target=/usr/local/cargo/git/db \ --mount=type=cache,target=/usr/local/cargo/registry/ \ -cargo build --locked --release --bin ${APP_NAME} && \ -cp ./target/release/${APP_NAME} /bin/indexers +cargo build --locked --release --bin indexers && \ +cp ./target/release/indexers /bin/indexers ######################################## # Create a new image that only contains the runtime artifacts. @@ -38,6 +56,12 @@ cp ./target/release/${APP_NAME} /bin/indexers FROM debian:bookworm AS runtime ARG APP_HOME +WORKDIR ${APP_HOME} + +RUN apt-get -qq update && \ + apt-get -qq install -y --no-install-recommends \ + ca-certificates \ + && rm -rf /var/lib/apt/lists/* /tmp/* # Create a non-privileged user that the app will run under. ARG USER=appuser @@ -53,10 +77,13 @@ RUN addgroup --system --gid ${GID} ${USER} \ --gid "${GID}" \ ${USER} +RUN chown ${UID}:${UID} ${APP_HOME} + USER ${USER} # Copy the executable from the "build" stage. COPY --from=build /bin/indexers /usr/local/bin +COPY config.json ./config.json # Expose the port that the application listens on. EXPOSE 3000 diff --git a/docker-compose.yml b/docker-compose.yml index 482dea4..c83d7eb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,16 +1,15 @@ -version: '3.8' services: db: image: postgres:16 restart: always environment: - POSTGRES_DB: mydb - POSTGRES_USER: myuser - POSTGRES_PASSWORD: mypassword + POSTGRES_USER: ${POSTGRES_USER} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} + POSTGRES_DB: ${POSTGRES_DB} ports: - "5432:5432" healthcheck: - test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U postgres" ] + test: [ "CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}" ] interval: 2s timeout: 5s retries: 1 @@ -26,9 +25,15 @@ services: condition: service_healthy build: context: . - dockerfile: Dockerfile.dev + dockerfile: Dockerfile + args: + - SQLX_OFFLINE=${SQLX_OFFLINE} + - ETH_RPC_URL=${ETH_RPC_URL} + - OPT_RPC_URL=${OPT_RPC_URL} env_file: - .env + environment: + - RUST_BACKTRACE=1 ports: - "3000:3000" dns: