Phase 8 plan: add Dockerfile step (Step 8.6)

- PROJECT_PLAN.md: insert Step 8.6 (Dockerfile) before the
  documentation step (renumbered to 8.7); acceptance criteria cover
  multi-stage build, non-root runtime user, EXPOSE ports, VOLUME /data,
  dist/mcias.conf.docker.example, Makefile docker target, and image
  size target (<50 MB)
- ARCHITECTURE.md §18: add Dockerfile to artifact inventory table;
  add Dockerfile Design section covering build stages, security
  properties (no shell, non-root uid 10001, TLS inside container),
  operator workflow, and the new Makefile docker target
This commit is contained in:
2026-03-11 14:47:07 -07:00
parent 7c79d00514
commit 8f706f10ec
2 changed files with 84 additions and 6 deletions

View File

@@ -842,12 +842,14 @@ neither depends on the other.
| Environment template | `dist/mcias.env.example` | Master key and other secrets |
| Reference config | `dist/mcias.conf.example` | Annotated production config |
| Dev config | `dist/mcias-dev.conf.example` | Local development defaults |
| Docker config | `dist/mcias.conf.docker.example` | Config template for container deployment |
| Install script | `dist/install.sh` | First-time setup on a Linux host |
| Dockerfile | `Dockerfile` | Multi-stage image for container deployment |
| Man page: mciassrv | `man/man1/mciassrv.1` | Server binary reference |
| Man page: mciasctl | `man/man1/mciasctl.1` | Admin CLI reference |
| Man page: mciasdb | `man/man1/mciasdb.1` | DB tool reference |
| Man page: mciasgrpcctl | `man/man1/mciasgrpcctl.1` | gRPC CLI reference |
| Makefile | `Makefile` | Build, test, lint, install, release targets |
| Makefile | `Makefile` | Build, test, lint, install, release, docker targets |
### systemd Unit Design
@@ -889,6 +891,57 @@ The unit does not start the service on install. Operators must run
mciasgrpcctl.1.gz
```
### Dockerfile Design
The image uses a two-stage build to keep the runtime image small and free of
build toolchain:
```
# Stage 1 — build
FROM golang:1.26-bookworm AS builder
CGO_ENABLED=1 (SQLite requires cgo)
-trimpath -ldflags="-s -w" (strip DWARF and symbol table)
Builds: mciassrv, mciasctl, mciasdb, mciasgrpcctl
# Stage 2 — runtime
FROM debian:bookworm-slim
Installs: ca-certificates, libc6
Copies binaries from builder stage only
Creates uid/gid 10001 (mcias:mcias)
EXPOSE 8443 (REST/TLS) and 9443 (gRPC/TLS)
VOLUME /data (SQLite database mount point)
ENTRYPOINT ["mciassrv"]
CMD ["-config", "/etc/mcias/mcias.conf"]
```
Security properties of the runtime image:
- No shell, no package manager, no Go toolchain — minimal attack surface
- Non-root user (`mcias`, uid 10001) — no escalation path
- TLS termination happens inside the container (same cert/key as bare-metal
deployment); the operator mounts `/etc/mcias/` as a read-only volume
containing the config file, TLS cert, and TLS key
- The SQLite database is on a named volume at `/data`; the operator is
responsible for backup; no network storage is assumed
Operator workflow:
```
# Build image
docker build -t mcias:$(git describe --tags --always) .
# Run (example)
docker run -d \
--name mcias \
-v /path/to/config:/etc/mcias:ro \
-v mcias-data:/data \
-p 8443:8443 \
-p 9443:9443 \
mcias:latest
```
The Makefile `docker` target automates the build step with the version tag.
### Makefile Targets
| Target | Action |
@@ -899,6 +952,7 @@ The unit does not start the service on install. Operators must run
| `generate` | `go generate ./...` (re-generates proto stubs) |
| `man` | Build man pages; compress to `.gz` in `man/` |
| `install` | Run `dist/install.sh` |
| `docker` | `docker build -t mcias:$(VERSION) .` |
| `clean` | Remove `bin/`, `gen/`, compressed man pages |
| `dist` | Cross-compile release tarballs for linux/amd64 and linux/arm64 |