Adds a multi-stage Containerfile, Quadlet unit, and operator walkthrough for a production deploy. The broker spawns forgejo-mcp per session, so the image bundles both binaries — broker built from this repo, forgejo-mcp pinned via FORGEJO_MCP_VERSION build-arg (default 2.18.0). Image stages: 1. golang:alpine compiles the broker with ldflags-stamped buildinfo 2. golang:alpine clones forgejo-mcp at the pinned tag and compiles it 3. distroless static-nonroot copies both binaries; uid 65532 Persistent state via the named volume `fjmcp-state` mounted at /data. SQLite WAL + SHM sidecars live alongside broker.db on the same volume, so a container swap or image upgrade preserves all OAuth clients, issued tokens, and refresh-token history. Verified end-to-end: podman run --rm -d -v fjmcp-test-state:/data ... fjmcp-broker:test curl /healthz # store: ok, broker.db created podman stop fjmcp-test podman run --rm -d -v fjmcp-test-state:/data ... fjmcp-broker:test curl /healthz # store: ok, same broker.db ls volume → broker.db, broker.db-shm, broker.db-wal all present Quadlet unit (deploy/podman/fjmcp-broker.container) drops into ~/.config/containers/systemd/, reads secrets from a 0600 env file outside the unit, publishes :8080 on loopback for Caddy to front. Makefile gains `image` and `image-run` targets. README links to the new docs/deploy-podman.md walkthrough. Closes forgejo-mcp-broker-8yd. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
73 lines
2.8 KiB
Docker
73 lines
2.8 KiB
Docker
# Multi-stage Containerfile for fjmcp-broker.
|
|
#
|
|
# Stage 1: build fjmcp-broker (this repo).
|
|
# Stage 2: build forgejo-mcp at a pinned version. The broker spawns it as
|
|
# a subprocess per session, so it must live in the final image.
|
|
# Stage 3: distroless static-nonroot. CGO_ENABLED=0 in both build stages
|
|
# keeps the final image free of glibc/musl entanglements and
|
|
# makes the image entirely static.
|
|
#
|
|
# Build labels and /etc/build-info wire BUILD_DATE and GIT_REVISION so
|
|
# operators can correlate a running container back to a commit.
|
|
|
|
ARG BUILD_DATE="unknown"
|
|
ARG GIT_REVISION="unknown"
|
|
ARG FORGEJO_MCP_VERSION="2.18.0"
|
|
|
|
# ---------- Stage 1: broker build ----------
|
|
FROM docker.io/library/golang:1.26-alpine AS broker-build
|
|
WORKDIR /src
|
|
RUN apk add --no-cache git
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
COPY . .
|
|
ARG BUILD_DATE
|
|
ARG GIT_REVISION
|
|
ENV CGO_ENABLED=0
|
|
RUN go build \
|
|
-trimpath \
|
|
-ldflags "-s -w \
|
|
-X kode.naiv.no/olemd/forgejo-mcp-broker/internal/buildinfo.Version=${GIT_REVISION} \
|
|
-X kode.naiv.no/olemd/forgejo-mcp-broker/internal/buildinfo.GitRevision=${GIT_REVISION} \
|
|
-X kode.naiv.no/olemd/forgejo-mcp-broker/internal/buildinfo.BuildDate=${BUILD_DATE}" \
|
|
-o /out/fjmcp-broker \
|
|
./cmd/broker
|
|
|
|
# ---------- Stage 2: forgejo-mcp build ----------
|
|
FROM docker.io/library/golang:1.26-alpine AS mcp-build
|
|
WORKDIR /src
|
|
RUN apk add --no-cache git
|
|
ARG FORGEJO_MCP_VERSION
|
|
RUN git clone --depth=1 --branch v${FORGEJO_MCP_VERSION} \
|
|
https://codeberg.org/goern/forgejo-mcp.git . \
|
|
&& CGO_ENABLED=0 go build -trimpath -ldflags "-s -w" -o /out/forgejo-mcp .
|
|
|
|
# ---------- Stage 3: runtime ----------
|
|
FROM gcr.io/distroless/static-debian12:nonroot
|
|
ARG BUILD_DATE
|
|
ARG GIT_REVISION
|
|
ARG FORGEJO_MCP_VERSION
|
|
|
|
LABEL org.opencontainers.image.title="fjmcp-broker"
|
|
LABEL org.opencontainers.image.description="OAuth 2.1 broker that fronts forgejo-mcp for MCP clients."
|
|
LABEL org.opencontainers.image.source="https://kode.naiv.no/olemd/forgejo-mcp-broker"
|
|
LABEL org.opencontainers.image.created="${BUILD_DATE}"
|
|
LABEL org.opencontainers.image.revision="${GIT_REVISION}"
|
|
LABEL org.opencontainers.image.licenses="MIT"
|
|
LABEL net.naiv.fjmcp.forgejo-mcp-version="${FORGEJO_MCP_VERSION}"
|
|
|
|
COPY --from=broker-build /out/fjmcp-broker /usr/local/bin/fjmcp-broker
|
|
COPY --from=mcp-build /out/forgejo-mcp /usr/local/bin/forgejo-mcp
|
|
|
|
# Persistent volume for the SQLite store (clients, tokens, audit data).
|
|
# Operators mount a named podman volume here so state survives container
|
|
# replacement. SQLite WAL writes auxiliary files (.db-wal, .db-shm) next
|
|
# to the main file — the volume contains them all.
|
|
VOLUME ["/data"]
|
|
WORKDIR /data
|
|
|
|
# Distroless nonroot user is uid 65532. Volumes inherit ownership from the
|
|
# host; document the chown step in deploy-podman.md.
|
|
USER 65532:65532
|
|
EXPOSE 8080
|
|
ENTRYPOINT ["/usr/local/bin/fjmcp-broker"]
|