spreadlab/Dockerfile
Justin Visser 33df4d33eb deploy-only Dockerfile, slice 2 of M4
Three stages: npm build, Go build with the real dist copied over the
placeholder before compiling, distroless/static (nonroot) runtime.
The container listens on :8080 (all interfaces, unlike the localhost
dev default). Verified locally: 16.6 MB image, /, /healthz and /api
all answer. Dev loop unchanged, Docker stays out of it.
2026-06-11 14:22:21 +02:00

31 lines
1.2 KiB
Docker

# Multi-stage build: the frontend and the Go binary are built in their
# own throwaway stages, and only the final static binary ships. Docker
# is deploy-only; the dev loop stays native (./dev.sh).
# Stage 1: build the frontend. lts/* in CI; pin the major here so image
# builds don't shift under us when a new LTS lands.
FROM node:22-alpine AS web
WORKDIR /src/web
COPY web/package.json web/package-lock.json ./
RUN npm ci
COPY web/ ./
RUN npm run build
# Stage 2: build the binary, with the real frontend embedded in place of
# the committed placeholder (see internal/webdist).
FROM golang:1.26-alpine AS build
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
COPY --from=web /src/web/dist/ internal/webdist/dist/
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /spreadlab ./cmd/spreadlab
# Stage 3: minimal runtime. distroless/static has CA certs and tzdata
# but no shell, which is all a static Go binary needs.
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=build /spreadlab /spreadlab
EXPOSE 8080
# 0.0.0.0, not the dev default localhost: inside a container the
# loopback interface is unreachable from outside.
ENTRYPOINT ["/spreadlab", "-addr", ":8080"]