The template's files at a77fd30, without its history or LICENSE, after script/rename simplexcalc. Model: opus-5-5
115 lines
4.5 KiB
Docker
115 lines
4.5 KiB
Docker
# Lint stage — fast feedback on formatting and lint issues. Tools are
|
|
# invoked directly (not via make/script): the docker build is its own
|
|
# single path.
|
|
# This stage must stay the one that runs golangci-lint, and its name must
|
|
# match $lint_stage in script/cibuild, which cache-busts it by name.
|
|
# golangci/golangci-lint:v2.12.2 (Debian-based), 2026-08-07
|
|
FROM golangci/golangci-lint:v2.12.2@sha256:5cceeef04e53efe1470638d4b4b4f5ceefd574955ab3941b2d9a68a8c9ad5240 AS lint
|
|
|
|
WORKDIR /src
|
|
|
|
# Copy go mod files first for better layer caching
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy source code
|
|
COPY . .
|
|
|
|
# Inventory of the sources that actually arrived here. script/cibuild
|
|
# reads these lines out of the build log and compares them against the
|
|
# git index, so a .dockerignore entry or a narrowed COPY that hides a
|
|
# package fails the run instead of yielding a clean report over a tree
|
|
# the linter never saw. Keep it immediately after `COPY . .`, and keep
|
|
# `echo context-manifest-begin` as its first command:
|
|
# script/assert-context-complete matches the step by that prefix.
|
|
RUN echo context-manifest-begin; \
|
|
{ find . -type f -name '*.go'; \
|
|
for f in go.mod go.sum .golangci.yml .golangci.yaml; do \
|
|
if [ -f "$f" ]; then echo "./$f"; fi; \
|
|
done; } \
|
|
| sed 's|^\./||' | LC_ALL=C sort | sed 's|^|context-file: |'; \
|
|
echo context-manifest-end
|
|
|
|
# Formatting check, config check, linter
|
|
RUN test -z "$(gofmt -s -l .)" || { echo "gofmt needed on:"; gofmt -s -l .; exit 1; }
|
|
RUN golangci-lint config verify --config .golangci.yml
|
|
RUN golangci-lint run --config .golangci.yml ./...
|
|
|
|
# Build stage. Must stay the one that runs go test, and its name must
|
|
# match $test_stage in script/cibuild, which cache-busts it by name.
|
|
# golang:1.25.7-bookworm (Debian-based: the race detector used by the
|
|
# test run requires glibc), 2026-08-07
|
|
FROM golang:1.25.7-bookworm@sha256:564e366a28ad1d70f460a2b97d1d299a562f08707eb0ecb24b659e5bd6c108e1 AS builder
|
|
|
|
# Depend on lint stage passing (forces BuildKit ordering)
|
|
COPY --from=lint /src/go.sum /dev/null
|
|
|
|
WORKDIR /build
|
|
|
|
# Copy go mod files first for better layer caching
|
|
COPY go.mod go.sum ./
|
|
RUN go mod download
|
|
|
|
# Copy source code
|
|
COPY . .
|
|
|
|
# Same inventory as the lint stage, and separately checked: this stage
|
|
# has its own COPY, so an intact context over there is no evidence about
|
|
# the tree `go test ./...` is about to walk here. A package that did not
|
|
# arrive is a package the tests never run, and the run still ends `ok`.
|
|
RUN echo context-manifest-begin; \
|
|
{ find . -type f -name '*.go'; \
|
|
for f in go.mod go.sum .golangci.yml .golangci.yaml; do \
|
|
if [ -f "$f" ]; then echo "./$f"; fi; \
|
|
done; } \
|
|
| sed 's|^\./||' | LC_ALL=C sort | sed 's|^|context-file: |'; \
|
|
echo context-manifest-end
|
|
|
|
# Run tests: quiet first, verbose rerun on failure (and still fail).
|
|
# -count=1 disables the test result cache, matching script/test.
|
|
RUN go test -count=1 -timeout 90s -race -cover ./... || \
|
|
{ echo "--- Rerunning with -v for details ---"; \
|
|
go test -count=1 -timeout 90s -race -v ./...; exit 1; }
|
|
|
|
# Static build; modernc.org/sqlite is pure Go, so CGO_ENABLED=0 yields
|
|
# a fully static binary that runs on the Alpine runtime.
|
|
ARG VERSION=dev
|
|
RUN CGO_ENABLED=0 go build -trimpath \
|
|
-ldflags "-s -w -X main.version=${VERSION}" \
|
|
-o bin/simplexcalc ./cmd/simplexcalc
|
|
|
|
# Runtime stage, and the last one: script/cibuild passes no --target, so
|
|
# BuildKit builds whichever stage is last and appending one drops lint,
|
|
# builder and their checks out of the run. Nothing asserts the name; it
|
|
# is here so that failure reads as `[runtime n/m]` in the build log.
|
|
# alpine:3.22, 2026-08-07
|
|
FROM alpine:3.22@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce AS runtime
|
|
|
|
RUN apk --no-cache add ca-certificates
|
|
|
|
# Create non-root user
|
|
RUN addgroup -g 1000 -S simplexcalc && \
|
|
adduser -u 1000 -S simplexcalc -G simplexcalc
|
|
|
|
WORKDIR /app
|
|
|
|
# Copy binary from builder
|
|
COPY --from=builder /build/bin/simplexcalc /app/simplexcalc
|
|
|
|
# Data directory: the sqlite database lives here. Mount a volume over
|
|
# it in production; everything else in the image is read-only.
|
|
RUN mkdir -p /var/lib/simplexcalc
|
|
|
|
RUN chown -R simplexcalc:simplexcalc /app /var/lib/simplexcalc
|
|
|
|
USER simplexcalc
|
|
|
|
ENV DATA_DIR=/var/lib/simplexcalc
|
|
|
|
EXPOSE 8080
|
|
|
|
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
|
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/.well-known/healthcheck.json || exit 1
|
|
|
|
CMD ["/app/simplexcalc", "serve"]
|