Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ concurrency:

permissions:
contents: write
packages: write

jobs:
build-and-release:
Expand All @@ -30,7 +31,13 @@ jobs:
# - rust toolchain matching rust-toolchain.toml (rustup default <ver>)
# - gh CLI (`apt install gh` via cli.github.com apt repo)
# - build deps: clang llvm libclang-dev build-essential pkg-config
# libssl-dev libudev-dev
# libudev-dev
# (libssl-dev no longer needed — bin/gravity_node and bin/gravity_cli
# both vendor OpenSSL via `openssl = { features = ["vendored"] }`,
# so openssl-sys self-compiles. Perl is required for the vendored
# OpenSSL Configure script; usually present already on Debian.)
# - docker (BuildKit enabled) — used by the release docker image step
# to wrap the native binary into ghcr.io/galxe/gravity_node:$TAG
timeout-minutes: 180
env:
RUSTFLAGS: "--cfg tokio_unstable"
Expand Down Expand Up @@ -100,6 +107,34 @@ jobs:
if-no-files-found: error
retention-days: 7

- name: Build gravity_node docker image
# Uses the `runtime-host-binary` target of docker/gravity_node/Dockerfile,
# which COPYs the binary the previous cargo step just produced. BuildKit
# stage pruning skips the `builder` stage entirely — no double compile.
# Runs on both PR (build-only, no push) and tag pushes.
#
# Note: the repo's .dockerignore excludes `target/` from the build
# context, so we stage the binary into docker/gravity_node/bin/ (a path
# that IS in the context) before invoking `docker build`. This matches
# the pre-existing pattern used by regression/pfn_chain_stress/run.sh.
shell: bash
env:
IMAGE_REF: gravity_node:build-${{ github.sha }}
run: |
set -euo pipefail
mkdir -p docker/gravity_node/bin
cp -f target/quick-release/gravity_node docker/gravity_node/bin/gravity_node
DOCKER_BUILDKIT=1 docker build \
--target runtime-host-binary \
--build-arg HOST_BINARY=docker/gravity_node/bin/gravity_node \
-t "${IMAGE_REF}" \
-f docker/gravity_node/Dockerfile .
echo "--- image size ---"
docker images --format '{{.Repository}}:{{.Tag}} {{.Size}}' | grep "^${IMAGE_REF}"
# Don't leave the binary in the repo working dir after the build —
# the runner reuses the checkout between jobs.
rm -f docker/gravity_node/bin/gravity_node

- name: Resolve tag
id: tag
if: github.event_name != 'pull_request'
Expand Down Expand Up @@ -133,3 +168,27 @@ jobs:
"$ASSETS_DIR/gravity_cli" \
"$ASSETS_DIR/gravity_cli.sha256" \
--clobber

- name: Login to ghcr.io
if: github.event_name != 'pull_request'
shell: bash
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
echo "${GH_TOKEN}" | docker login ghcr.io -u "${GITHUB_ACTOR}" --password-stdin

- name: Tag and push docker image to ghcr.io
if: github.event_name != 'pull_request'
shell: bash
env:
TAG: ${{ steps.tag.outputs.tag }}
BUILT_IMAGE: gravity_node:build-${{ github.sha }}
run: |
set -euo pipefail
# GHCR namespaces are lowercase; convert the github org name to be safe.
OWNER_LC="$(echo "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]')"
IMAGE="ghcr.io/${OWNER_LC}/gravity_node:${TAG}"
docker tag "${BUILT_IMAGE}" "${IMAGE}"
docker push "${IMAGE}"
echo "pushed: ${IMAGE}"
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions bin/gravity_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ gaptos = { workspace = true, features = ["gcp-secret-manager"] }
block-buffer-manager.workspace = true
proposer-reth-map.workspace = true
build-info.workspace = true
# Force libssl to be statically linked into the binary so it can ship as a
# single self-contained artifact across libssl1.1 (Debian 11) and libssl3
# (Debian 12+) hosts. native-tls (pulled transitively via aptos-vault-client
# and google-cloud-* under gaptos's gcp-secret-manager feature) is the
# consumer; with `vendored`, openssl-sys compiles OpenSSL from source and
# statically links it, removing the runtime libssl.so.* dependency.
# gravity_cli applies the same trick — keep them in sync. Without this,
# `cargo build -p gravity_node` (e.g. via `make gravity_node`) scopes the
# feature resolve to gravity_node only and openssl-sys defaults to dynamic
# system linkage, producing a binary that fails on hosts whose libssl ABI
# differs from the build host.
openssl = { version = "0.10", features = ["vendored"] }
rayon = "1.7.0"
tracing-flame = "0.2"
tracing-timing = "0.6"
Expand Down
60 changes: 49 additions & 11 deletions docker/gravity_node/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
# syntax=docker/dockerfile:1.7
#
# Two build targets:
#
# 1. `runtime` (default) — compile gravity_node from source inside the
# container's `builder` stage:
# docker build -t gravity_node:src \
# -f docker/gravity_node/Dockerfile .
#
# 2. `runtime-host-binary` — skip the cargo build; copy a pre-built
# binary from the host build context. Used by the release pipeline so
# we don't recompile after the runner has already produced a native
# binary, and by regression/pfn_chain_stress for the same reason:
# docker build --target runtime-host-binary \
# --build-arg HOST_BINARY=target/quick-release/gravity_node \
# -t gravity_node:rel \
# -f docker/gravity_node/Dockerfile .
#
# Stage pruning means `--target runtime-host-binary` does not enter the
# `builder` stage — the cargo build is genuinely skipped, not just cached.

# ─── Stage 1: builder ────────────────────────────────────────────────
# ─── Stage 1: builder (used only by the `runtime` target) ────────────
FROM rust:1.93-slim-bookworm AS builder

ARG CARGO_PROFILE=release
Expand All @@ -12,13 +31,13 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
libclang-dev \
build-essential \
pkg-config \
libssl-dev \
libudev-dev \
libzstd-dev \
cmake \
git \
ca-certificates \
protobuf-compiler \
perl \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /build
Expand All @@ -32,33 +51,52 @@ RUN --mount=type=cache,target=/build/target,id=gravity-target \
&& mkdir -p /out \
&& cp "target/${CARGO_PROFILE}/${CARGO_BIN}" /out/gravity_node

# ─── Stage 2: runtime ────────────────────────────────────────────────
FROM debian:12-slim AS runtime
# ─── Stage 2: runtime-base (shared apt + user setup + entrypoint) ────
# Common to both leaf targets. The binary itself is added in the leaves
# so we can pick the source (builder vs build context) per target.
FROM ubuntu:24.04 AS runtime-base

RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
libssl3 \
libudev1 \
libzstd1 \
jq \
tini \
curl \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid 10001 gravity \
&& useradd --system --uid 10001 --gid gravity --home-dir /gravity --shell /usr/sbin/nologin gravity \
&& mkdir -p /gravity/config /gravity/data /gravity/logs \
&& chown -R gravity:gravity /gravity

COPY --from=builder /out/gravity_node /usr/local/bin/gravity_node
COPY docker/gravity_node/entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/gravity_node /usr/local/bin/entrypoint.sh
RUN chmod +x /usr/local/bin/entrypoint.sh

USER gravity
WORKDIR /gravity

ENV GRAVITY_CONFIG_DIR=/gravity/config \
GRAVITY_DATA_DIR=/gravity/data \
RUST_BACKTRACE=1

# Note: USER and ENTRYPOINT/CMD are set in each leaf so that the binary
# COPY can happen as root (default user in runtime-base) before dropping
# to `gravity`.

# ─── Stage 3a: runtime-host-binary — copy a pre-built host binary ────
# Used by the release pipeline and regression/pfn_chain_stress.
FROM runtime-base AS runtime-host-binary

ARG HOST_BINARY=docker/gravity_node/bin/gravity_node
COPY --chmod=755 ${HOST_BINARY} /usr/local/bin/gravity_node

USER gravity
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"]
CMD ["node"]

# ─── Stage 3b: runtime (default target) — copy from in-container build ─
# Put last so `docker build .` (no --target) picks this and the
# from-source build is the default behaviour, matching prior versions.
FROM runtime-base AS runtime

COPY --from=builder --chmod=755 /out/gravity_node /usr/local/bin/gravity_node

USER gravity
ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/entrypoint.sh"]
CMD ["node"]
47 changes: 0 additions & 47 deletions docker/gravity_node/Dockerfile.host-binary

This file was deleted.

6 changes: 3 additions & 3 deletions regression/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,6 @@ Drop a new subdirectory with at minimum:
- `stop.sh` — tear down
- `README.md` — topology, baselines, caveats

Reuse `docker/gravity_node/Dockerfile.host-binary` for the node image —
no good reason to in-container-compile for a regression test that needs
fast iteration.
Reuse `docker/gravity_node/Dockerfile` with `--target runtime-host-binary`
for the node image — no good reason to in-container-compile for a regression
test that needs fast iteration.
7 changes: 4 additions & 3 deletions regression/pfn_chain_stress/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,10 @@ cd regression/pfn_chain_stress
1. **Build on host, wrap in Docker.** `run.sh` first runs
`cargo build --bin gravity_node --profile quick-release` on the host
(incremental — only seconds when sources unchanged), then stages the
binary at `docker/gravity_node/bin/gravity_node`. The Docker image
(`docker/gravity_node/Dockerfile.host-binary`) `COPY`s that binary
into a slim debian runtime — image build is ~12s after first time.
binary at `docker/gravity_node/bin/gravity_node`. The Docker image is
built with `docker/gravity_node/Dockerfile` using `--target
runtime-host-binary`, which `COPY`s that binary into an ubuntu:24.04
runtime — image build is ~12s after first time.

In-container builds from source were tried and abandoned: ~65 min
apt install + cargo git-fetch SSL errors. Not worth it for a stress
Expand Down
3 changes: 2 additions & 1 deletion regression/pfn_chain_stress/docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ x-node-common: &node-common
# runtime image. run.sh does `cargo build` on the host before invoking
# this — no in-container Rust compile (in-container builds chronically
# hit SSL/cargo-git issues; not worth the 30-60 min cost).
dockerfile: docker/gravity_node/Dockerfile.host-binary
dockerfile: docker/gravity_node/Dockerfile
target: runtime-host-binary
restart: unless-stopped
network_mode: host
# cpuset pins all nodes of this cluster to a fixed core range. Empty
Expand Down
3 changes: 2 additions & 1 deletion regression/pfn_chain_stress/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,8 @@ if ! docker image inspect gravity_node:pfn-stress >/dev/null 2>&1; then
echo "[run] building gravity_node:pfn-stress…"
DOCKER_BUILDKIT=1 docker build \
-t gravity_node:pfn-stress \
-f "$REPO_ROOT/docker/gravity_node/Dockerfile.host-binary" \
-f "$REPO_ROOT/docker/gravity_node/Dockerfile" \
--target runtime-host-binary \
"$REPO_ROOT" \
|| { echo "[run] gravity_node image build failed"; exit 1; }
fi
Expand Down
Loading