Repository navigation
Expand file tree
/
Copy pathDockerfile
More file actions
56 lines (44 loc) · 1.95 KB
/
Copy pathDockerfile
File metadata and controls
56 lines (44 loc) · 1.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# syntax=docker/dockerfile:1
# Single-container build for Cloud Run (docs/demo.md).
#
# This is NOT the file `docker compose up` uses. Compose builds server/Dockerfile
# and web/Dockerfile into two containers, with nginx serving the SPA and
# proxying /api. Cloud Run's GitHub integration builds one image from one
# Dockerfile, so here the SPA is compiled into the Go binary via go:embed
# (server/internal/webui) and one process serves both halves on one origin.
#
# Build context is the repository root — hence the web/ and server/ prefixes.
# docker build -t elms .
# gcloud run deploy elms --source .
# ---------------------------------------------------------------- web bundle
FROM node:24-alpine AS web
WORKDIR /web
# Lockfile first: source changes constantly, dependencies rarely, and npm ci is
# the slow step.
COPY web/package.json web/package-lock.json ./
RUN npm ci
COPY web/ ./
RUN npm run build
# ---------------------------------------------------------------- api binary
# Pinned to the same patch release as go.mod's `go 1.26.5`.
FROM golang:1.26.5-alpine AS api
WORKDIR /src
COPY server/go.mod server/go.sum ./
RUN go mod download
COPY server/ ./
# go:embed cannot reach outside its own package directory, so the bundle is
# copied in rather than referenced. This overwrites the placeholder index.html
# committed at that path; if this COPY were ever dropped, the placeholder page
# would ship instead — which is exactly what it says on it.
COPY --from=web /web/dist/ ./internal/webui/dist/
RUN CGO_ENABLED=0 go build -trimpath -ldflags="-s -w" -o /out/api ./cmd/api
# ---------------------------------------------------------------- runtime
# Static binary, no libc, no shell, non-root.
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=api /out/api /api
# Cloud Run injects PORT and the binary honours it (cmd/api/main.go); this is
# only the default for a plain `docker run`.
ENV PORT=8080
EXPOSE 8080
USER nonroot:nonroot
ENTRYPOINT ["/api"]