Artifact 764d142012a604d451e64978f34b7b29473ebdad935b4e3236ab4344f7db8a5d:
- File
Dockerfile
— part of check-in
[bbe731e042]
at
2026-08-17 16:40:19
on branch trunk
— deploy: Dockerfile, compose stack and a run book
quarry had no packaging at all while notify already had a working Dockerfile and compose. The image ships zit WITH quarry, deliberately: 0001 §2 makes the zit CLI the entire store interface, so zit's behaviour IS quarry's, and today alone three zit builds changed what quarry does — frames got faster, a card fix changed which artifacts parse, stat -R enabled bare-store serving. ZIT_REF is a build argument and /etc/quarry-build records the pair, so a container can answer which zit it carries.
compose follows notify's shape, including the constraint its own file documents: dagnats binds loopback in standalone mode, so everything shares its network namespace. quarry joins it too — its embedded NATS uses DontListen and binds nothing, so there is no port to collide with.
docs/running.md is the by-hand path, which is what this was actually developed against: the launchd-signed dagnats, notify's bootstrap and workflows, the topic-vs-subscriber addressing, and the two credentials that close the write and push gates.
Unverified, and said so in the doc: no container runtime is installed here, so the images have never been built. The two build recipes inside them ARE verified natively — zit compiles from a clean clone with zig build --release=fast, quarry builds fully static with CGO_ENABLED=0.
Also lands the publish-throughput measurement as an opt-in test. It is what disproved the hypothesis that synchronous publish was the ingest bottleneck (62k msg/s sync), which redirected the search to zit frames and quarry's folding. (user: dmestas, size: 3609) [annotate] [blame] [check-ins using]
# syntax=docker/dockerfile:1
#
# quarry ships WITH zit, deliberately.
#
# 0001 §2 makes the zit CLI the entire store interface: every read and
# every write is a subprocess call. So zit's behaviour IS quarry's
# behaviour, and the two cannot be allowed to drift. On 2026-08-16 alone,
# three zit builds changed what quarry does — `frames` got 31% faster,
# a card-parsing fix changed which artifacts parse AT ALL (before it,
# sqlite's 794 tickets were invisible), and a new `stat -R` let quarry
# serve a bare store. An image that resolved zit at run time from
# whatever happened to be on PATH would reintroduce exactly the class of
# silent divergence that cost a day to find.
#
# Hence: ZIT_REF is a build argument, the built binary is copied in, and
# `quarry version` is recorded next to `zit version` at build time so a
# running container can answer "which zit is this?".
#
# docker build --build-arg ZIT_REF=<commit> -t quarry .
# ---- zit builder ---------------------------------------------------------
# Zig rather than Go: zit is a Zig program, which is why this stage cannot
# simply be another golang builder.
FROM alpine:3.21 AS zit-builder
ARG ZIG_VERSION=0.16.0
ARG ZIT_REPO=https://github.com/danmestas/zit
# ZIT_REF pins the store implementation. Override it to move; do not
# leave it floating, or two deploys of the same quarry can disagree
# about what parses.
ARG ZIT_REF=trunk
RUN apk add --no-cache curl git xz
RUN case "$(uname -m)" in \
aarch64) ZIG_ARCH=aarch64 ;; \
x86_64) ZIG_ARCH=x86_64 ;; \
*) echo "unsupported architecture $(uname -m)" >&2; exit 1 ;; \
esac && \
curl -fsSL "https://ziglang.org/download/${ZIG_VERSION}/zig-linux-${ZIG_ARCH}-${ZIG_VERSION}.tar.xz" \
-o /tmp/zig.tar.xz && \
mkdir -p /opt/zig && tar -xJf /tmp/zig.tar.xz -C /opt/zig --strip-components=1 && \
ln -s /opt/zig/zig /usr/local/bin/zig
WORKDIR /src
RUN git clone "${ZIT_REPO}" zit && cd zit && git checkout "${ZIT_REF}"
# --release=fast, not -Doptimize: zit's build.zig uses Zig 0.16's spelling.
RUN cd zit && zig build --release=fast && ./zig-out/bin/zit version
# ---- quarry builder ------------------------------------------------------
# CGO stays off: quarry's SQLite is ncruces/go-sqlite3 (WASM, no C) and
# Pikchr runs on wazero, so the whole binary is pure Go and static.
FROM golang:1.26 AS quarry-builder
ARG VERSION=0.0.0-dev
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
ENV CGO_ENABLED=0
RUN go build -trimpath -ldflags "-s -w -X main.version=${VERSION}" -o /out/quarry ./cmd/quarry
# ---- runtime -------------------------------------------------------------
# busybox wget is present so compose and k8s health checks work, matching
# the notify image's posture.
FROM alpine:3.21
RUN apk add --no-cache ca-certificates && adduser -D -u 10001 quarry
COPY --from=zit-builder /src/zit/zig-out/bin/zit /usr/local/bin/zit
COPY --from=quarry-builder /out/quarry /usr/local/bin/quarry
# The pair, recorded together. `docker run <image> cat /etc/quarry-build`
# answers which zit a given quarry was shipped against without starting it.
RUN printf 'quarry: %s\nzit: %s\n' "$(quarry version)" "$(zit version)" > /etc/quarry-build && \
cat /etc/quarry-build
USER quarry
# /repos holds the zit stores quarry serves; /data holds derived state
# (indexes, embedded NATS, the OLTP database) and is disposable by 0001
# §11 — wiping it and re-ingesting must converge to identical state.
VOLUME ["/repos", "/data"]
EXPOSE 8080
ENTRYPOINT ["quarry"]
CMD ["serve", "--addr", "0.0.0.0:8080", "--data", "/data"]