Containerization
Responsibility
Package each of the three binaries into a minimal, secure container image and orchestrate them with Docker Compose on a private network.
Dockerfiles
All three (Dockerfile.backend, Dockerfile.web, Dockerfile.client) use the
same multi-stage pattern:
- Build stage (
golang:1.27.2-alpine):CGO_ENABLED=0 GOOS=linux,go build -ldflags="-s -w"into/app/binary. - Runtime stage (
gcr.io/distroless/static-debian12:nonroot): copy the binary, run as non-root UID 65532,ENTRYPOINT ["/binary"]. Backend and web expose 8080; client is outbound only.
Layer caching: go.mod/go.sum are copied and go mod download runs before
the source COPY . ..
.dockerignore
Excludes .git, build outputs, secrets (.env, keys), docs, IDE files, and
the Dockerfiles themselves, keeping the build context small and protecting
layer cache from irrelevant changes.
Docker Compose
compose.yaml defines four services on a shared private network:
postgres(postgres:16-alpine) — persistent store.backend— control plane API,STORE=postgres, depends on postgres.frontend— dashboard + gateway, only service with a host-published port (8080), depends on backend.client— data plane example, depends on backend.
Only the frontend maps a port to the host, so all backend traffic stays on the private network.
Build commands
docker build -f Dockerfile.backend -t flaggo-backend:local .
docker compose up -d
Related
openwiki/architecture/overview.mdopenwiki/build/ci-pipeline.md