From 970d7751033d5239d25b7c7384bcd60aa1fc651d Mon Sep 17 00:00:00 2001 From: bruwbird Date: Mon, 28 Apr 2025 10:27:36 +0900 Subject: [PATCH] testserver: slim testserver image Introduce multi-stage build to separate build from runtime. Reduce final image size Keep minimal Python env for test usage. Also enable multi-architecture support to ensure proper downloads based on the build environment. This fixes issues on ARM64 where the x86_64 binary was previously being downloaded. --- docker/gl-testserver/Dockerfile | 251 ++++++++++++++++++++++---------- 1 file changed, 177 insertions(+), 74 deletions(-) diff --git a/docker/gl-testserver/Dockerfile b/docker/gl-testserver/Dockerfile index ab1362397..bb3d249f7 100644 --- a/docker/gl-testserver/Dockerfile +++ b/docker/gl-testserver/Dockerfile @@ -1,84 +1,187 @@ -FROM ubuntu:22.04 AS python-builder - +############################ +# Stage 1: builder +############################ +FROM rust:slim-bullseye AS builder + +#--------------------------------------------------------------------- +# Build-time arguments & environment variables +#--------------------------------------------------------------------- ARG BITCOIN_VERSION=24.0 ARG GID=0 ARG UID=0 ARG DOCKER_USER=dev ARG REPO_PATH=/repo +ARG TARGETPLATFORM +ARG TARGETARCH -ENV RUST_VERSION=1.74 -ENV PATH=$CARGO_HOME/bin:$PATH ENV PROTOC_VERSION=3.19.3 ENV CFSSL_VERSION=1.6.5 -ENV GL_TESTING_IGNORE_HASH=False -ENV PATH=$PATH:/home/$DOCKER_USER/.local/bin/:/opt/bitcoin/bin:/home/$DOCKER_USER/.cargo/bin -ENV REPO=$REPO_PATH - -# Force this target dir, so the scripts can find all the binaries. -#ENV CARGO_TARGET_DIR=${REPO}/target -ENV CARGO_TARGET_DIR=/tmp/target/ - -RUN apt update && apt install -qqy \ - curl \ - python3 \ - python3-pip \ - python3-venv \ +ENV PATH=/home/${DOCKER_USER}/.local/bin:/opt/bitcoin/bin:/usr/local/bin:$PATH +ENV CARGO_TARGET_DIR=/tmp/target +ENV REPO=${REPO_PATH} + +#--------------------------------------------------------------------- +# Base packages required for building +#--------------------------------------------------------------------- +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive \ + apt-get install -y --no-install-recommends \ + python3 python3-venv python3-pip \ + python3-dev \ libpq-dev \ - unzip \ - sudo \ - git \ build-essential \ - wget - -RUN groupadd -g $GID -o $DOCKER_USER &&\ - useradd -m -u $UID -g $GID -G sudo -o -s /bin/bash $DOCKER_USER && \ - echo '%sudo ALL=(ALL:ALL) ALL' >> /etc/sudoers - -RUN wget -q https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssl_${CFSSL_VERSION}_linux_amd64 -O /usr/bin/cfssl && \ - chmod a+x /usr/bin/cfssl -RUN wget -q https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssljson_${CFSSL_VERSION}_linux_amd64 -O /usr/bin/cfssljson && \ - chmod a+x /usr/bin/cfssljson - -RUN mkdir /tmp/protoc && \ - cd /tmp/protoc && \ - wget --quiet \ - -O protoc.zip \ - https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-x86_64.zip && \ - unzip protoc.zip && \ - sudo mv /tmp/protoc/bin/protoc /usr/local/bin && \ - chmod a+x /usr/local/bin/protoc && \ - rm -rf /tmp/protoc - -RUN cd /tmp/ && \ - wget "https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/bitcoin-${BITCOIN_VERSION}-x86_64-linux-gnu.tar.gz" -O bitcoin.tar.gz && \ - tar -xvzf bitcoin.tar.gz && \ - mv /tmp/bitcoin-$BITCOIN_VERSION/ /opt/bitcoin && \ - rm -rf bitcoin.tar.gz /tmp/bitcoin-$BITCOIN_VERSION - -RUN mkdir -p ${REPO_PATH} && \ - chown $DOCKER_USER:users ${REPO_PATH} - -ADD ../../libs/ ${REPO_PATH}/libs -ADD ../../pyproject.toml ${REPO_PATH}/ - -ADD ../../ ${REPO_PATH}/ -RUN chown $DOCKER_USER:users -R ${REPO_PATH} -RUN chown $DOCKER_USER:users -R /home/$DOCKER_USER -USER $DOCKER_USER - -RUN curl \ - --proto '=https' \ - --tlsv1.2 \ - -sSf https://sh.rustup.rs | sh \ - -s -- -y --default-toolchain ${RUST_VERSION} -RUN rustup default stable - -WORKDIR ${REPO_PATH}/libs/gl-testserver/ - -RUN cargo build --bin gl-plugin -RUN cargo build --bin gl-signerproxy - -RUN curl -LsSf https://astral.sh/uv/install.sh | sh - -RUN uv lock && uv sync --locked -v -CMD uv run gltestserver run --metadata ${REPO}/ --directory ${REPO}/.gltestserver + git \ + curl wget unzip sudo ca-certificates \ + && rm -rf /var/lib/apt/lists/* + +#--------------------------------------------------------------------- +# Additional Rust components +#--------------------------------------------------------------------- +RUN rustup component add rustfmt + +#--------------------------------------------------------------------- +# Create dev user with password-less sudo +#--------------------------------------------------------------------- +RUN groupadd -g ${GID} -o ${DOCKER_USER} && \ + useradd -m -u ${UID} -g ${GID} -G sudo -o -s /bin/bash ${DOCKER_USER} && \ + echo '%sudo ALL=(ALL:ALL) NOPASSWD:ALL' >> /etc/sudoers + +USER ${DOCKER_USER} +WORKDIR /home/${DOCKER_USER} + +#--------------------------------------------------------------------- +# Directories for build tools and staged artifacts +#--------------------------------------------------------------------- +RUN sudo mkdir -p /opt/build-tools /opt/bitcoin /opt/stage && \ + sudo chown ${DOCKER_USER}:${DOCKER_USER} /opt/build-tools /opt/bitcoin /opt/stage + +#--------------------------------------------------------------------- +# cfssl & cfssljson +#--------------------------------------------------------------------- +RUN wget -q https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssl_${CFSSL_VERSION}_linux_${TARGETARCH} -O /opt/build-tools/cfssl && \ + wget -q https://github.com/cloudflare/cfssl/releases/download/v${CFSSL_VERSION}/cfssljson_${CFSSL_VERSION}_linux_${TARGETARCH} -O /opt/build-tools/cfssljson && \ + chmod +x /opt/build-tools/cfssl /opt/build-tools/cfssljson + +#--------------------------------------------------------------------- +# protoc +#--------------------------------------------------------------------- +RUN PLATFORM=$(case "${TARGETPLATFORM}" in \ + linux/amd64) echo "x86_64";; \ + linux/arm64) echo "aarch_64";; \ + esac) && \ + wget -q https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PLATFORM}.zip -O /tmp/protoc.zip && \ + unzip -q /tmp/protoc.zip -d /tmp/protoc && \ + mv /tmp/protoc/bin/protoc /opt/build-tools/protoc && \ + chmod +x /opt/build-tools/protoc && \ + rm -rf /tmp/protoc /tmp/protoc.zip + +#--------------------------------------------------------------------- +# bitcoind (static binaries) +#--------------------------------------------------------------------- +RUN ARCH=$(case "${TARGETPLATFORM}" in \ + linux/amd64) echo "x86_64";; \ + linux/arm64) echo "aarch64";; \ + esac) && \ + wget -q https://bitcoincore.org/bin/bitcoin-core-${BITCOIN_VERSION}/bitcoin-${BITCOIN_VERSION}-${ARCH}-linux-gnu.tar.gz -O /tmp/bitcoin.tgz && \ + tar -xf /tmp/bitcoin.tgz -C /tmp && \ + mv /tmp/bitcoin-${BITCOIN_VERSION}/* /opt/bitcoin && \ + rm -rf /tmp/bitcoin.tgz /tmp/bitcoin-${BITCOIN_VERSION} + +ENV PATH=/opt/build-tools:$PATH + +#--------------------------------------------------------------------- +# Copy source code +#--------------------------------------------------------------------- +WORKDIR ${REPO_PATH} +COPY --chown=${DOCKER_USER}:users ../../Cargo.toml ${REPO_PATH}/ +COPY --chown=${DOCKER_USER}:users ../../pyproject.toml ../../uv.lock ${REPO_PATH}/ +COPY --chown=${DOCKER_USER}:users ../../libs ${REPO_PATH}/libs +COPY --chown=${DOCKER_USER}:users ../../examples ${REPO_PATH}/examples + +#--------------------------------------------------------------------- +# Build Rust binaries (release, stripped) +#--------------------------------------------------------------------- +WORKDIR ${REPO_PATH} +RUN cargo build --release \ + --manifest-path libs/gl-plugin/Cargo.toml --bin gl-plugin && \ + cargo build --release \ + --manifest-path libs/gl-signerproxy/Cargo.toml --bin gl-signerproxy && \ + strip ${CARGO_TARGET_DIR}/release/gl-plugin ${CARGO_TARGET_DIR}/release/gl-signerproxy + +#--------------------------------------------------------------------- +# Lock and sync Python dependencies using uv +#--------------------------------------------------------------------- +WORKDIR ${REPO_PATH}/libs/gl-testserver +COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/ +RUN --mount=type=cache,target=/root/.cache/uv \ + uv lock && uv sync --locked -v --no-editable + +#--------------------------------------------------------------------- +# Collect all artifacts into /opt/stage +#--------------------------------------------------------------------- +RUN mkdir -p /opt/stage/bin /opt/stage/bitcoin && \ + # Rust binaries + cp ${CARGO_TARGET_DIR}/release/gl-plugin ${CARGO_TARGET_DIR}/release/gl-signerproxy /opt/stage/bin/ && \ + # Helper tools + cp /opt/build-tools/* /opt/stage/bin/ && \ + # bitcoind + cp -r /opt/bitcoin /opt/stage/ && \ + # uv binaries + cp /bin/uv /bin/uvx /opt/stage/bin/ && \ + # uv virtual environment + cp -r ${REPO_PATH}/.venv /opt/stage/uv + +############################ +# Stage 2: runtime +############################ +FROM ubuntu:22.04 + +#--------------------------------------------------------------------- +# Minimal runtime packages +#--------------------------------------------------------------------- +RUN apt-get update && \ + DEBIAN_FRONTEND=noninteractive \ + apt-get install -y --no-install-recommends \ + python3 \ + libpq5 \ + curl \ + && apt-get clean && rm -rf /var/lib/apt/lists/* + +#--------------------------------------------------------------------- +# Arguments & environment variables (kept identical with builder) +#--------------------------------------------------------------------- +ARG GID=0 +ARG UID=0 +ARG DOCKER_USER=dev +ARG REPO_PATH=/repo + +ENV PATH=/home/${DOCKER_USER}/.local/bin:/usr/local/bin:/opt/bitcoin/bin:$PATH +ENV REPO=${REPO_PATH} +ENV GL_TESTING_IGNORE_HASH=False + +#--------------------------------------------------------------------- +# Create runtime user +#--------------------------------------------------------------------- +RUN groupadd -g ${GID} -o ${DOCKER_USER} && \ + useradd -m -u ${UID} -g ${GID} -s /bin/bash ${DOCKER_USER} + +#--------------------------------------------------------------------- +# Copy artifacts from the builder stage +#--------------------------------------------------------------------- +COPY --from=builder /opt/stage/bin/* /usr/local/bin/ +COPY --from=builder /opt/stage/bitcoin /opt/bitcoin + +#--------------------------------------------------------------------- +# Application code (copy only libs to keep image small) +#--------------------------------------------------------------------- +ADD . ${REPO} +COPY --from=builder /opt/stage/uv ${REPO}/.venv +RUN chown -R ${DOCKER_USER}:${DOCKER_USER} ${REPO} + +USER ${DOCKER_USER} +WORKDIR ${REPO}/libs/gl-testserver/ + +#--------------------------------------------------------------------- +# ENTRYPOINT +#--------------------------------------------------------------------- +CMD . ${REPO}/.venv/bin/activate && python3 gltestserver run --metadata ${REPO}/ --directory ${REPO}/.gltestserver