# syntax=docker/dockerfile:1.4
# zakuroai/zc — Zakuro Compute Broker
#
# zakuro-client is fetched from the private zakuro-ai/zakuro-drive repo over
# SSH, so the build needs an ssh-agent holding a key with read access
# (CI forwards the repo deploy key; locally your own agent works):
#
# Build: docker build --ssh default -f docker/Dockerfile -t zakuroai/zc:latest .
# Run: docker run -p 9000:9000 zakuroai/zc broker
# Pin the rust builder to bookworm so its glibc matches the runtime
# stage below (debian:bookworm-slim = glibc 2.36). The unpinned
# `rust:latest` floats to whatever Debian release the upstream image
# tracks (currently trixie, glibc 2.39), which produces a binary that
# fails to start in bookworm-slim with:
# /usr/local/bin/zc: /lib/x86_64-linux-gnu/libc.so.6:
# version `GLIBC_2.39' not found
FROM rust:1-bookworm AS builder
RUN apt-get update && apt-get install -y --no-install-recommends \
pkg-config libssl-dev git openssh-client \
&& rm -rf /var/lib/apt/lists/*
# The private zakuro-drive git dep is fetched over SSH via the BuildKit
# ssh mount (`RUN --mount=type=ssh` below): pin GitHub's host key and
# rewrite the dep's https URL to SSH. cargo shells out to the git CLI
# (.cargo/config.toml: git-fetch-with-cli).
RUN mkdir -p -m 0700 ~/.ssh \
&& ssh-keyscan github.com >> ~/.ssh/known_hosts 2>/dev/null \
&& git config --global url."ssh://git@github.com/zakuro-ai/".insteadOf "https://github.com/zakuro-ai/"
WORKDIR /build
# Dependency build layer.
#
# Deliberately NOT using `--mount=type=cache`: BuildKit cache mounts are
# scratch space that the `type=gha` cache backend does NOT persist across
# CI runs (gha caches image *layers*, not cache-mount contents). With the
# mounts, every CI build started with an empty target/ and recompiled the
# entire dependency graph (quinn/rustls/ring/tokio/ratatui…) from scratch
# — ~15-20 min per push. By compiling deps into a normal layer keyed on
# Cargo.toml/Cargo.lock/build.rs, `cache-to/from: type=gha,mode=max` stores
# and restores the compiled deps, so unchanged deps are a cache hit and the
# real build below only recompiles this crate (~2-3 min).
COPY Cargo.toml Cargo.lock build.rs ./
COPY .cargo .cargo
RUN mkdir src && echo "fn main() {}" > src/main.rs
RUN --mount=type=ssh cargo build --release || true
# Build real binary — reuses the compiled deps baked into the layer above,
# so only the zc crate is recompiled.
COPY src ./src
RUN --mount=type=ssh touch src/main.rs && \
cargo build --release && \
cp /build/target/release/zc /tmp/zc
# -------------------------------------------------------------------
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
curl ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /tmp/zc /usr/local/bin/zc
RUN useradd -r -u 1001 -g root -s /sbin/nologin zc
USER zc
EXPOSE 9000
HEALTHCHECK --interval=10s --timeout=5s --retries=3 \
CMD curl -f http://localhost:9000/health || exit 1
ENTRYPOINT ["/usr/local/bin/zc"]
CMD ["broker"]