docs(contracts): add CONTRACT_001-004 — T00
Interface contracts unblocking the parallel fan-out (T01-T07): - 001 config schema (single stack, passphrase + VERSIONS + Pulumi config) - 002 Vault path layout (foundation/<service>/<type>-credentials, camelCase) - 003 container network/DNS/ports/volumes (foundation-net, named volumes) - 004 backup artifact format + restore order (Vault->PG->RustFS->Forgejo) ADR_F001 (layered platform) already satisfied by ADR-004. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f18676e6b3
commit
188e30e23e
5 changed files with 299 additions and 0 deletions
|
|
@ -0,0 +1,69 @@
|
|||
# Contract — CONTRACT_003 — Container Network, DNS, Ports & Volumes
|
||||
|
||||
**Between**: all `bootstrap/components/*` that create containers ↔ each other (service discovery)
|
||||
**Status**: Agreed (pending implementation validation)
|
||||
**Realizes**: PLAN-002 §0 (Layer-0 = containers), §3 · **Uses**: `packages/pulumi-docker` (`DockerDeployments`)
|
||||
|
||||
## Interface
|
||||
|
||||
### 3.1 Network
|
||||
- **Name**: `foundation-net` (Docker user-defined bridge — enables name-based DNS).
|
||||
- **Subnet**: `172.30.0.0/24` (configurable, CONTRACT_001 `network.subnet`).
|
||||
- **DNS**: containers reach each other by **container name** on `foundation-net`. No hardcoded IPs.
|
||||
|
||||
### 3.2 Containers, ports, exposure
|
||||
|
||||
| Container name | Image (digest in VERSIONS) | Internal port(s) | Published to host? | Reached by |
|
||||
|----------------|----------------------------|------------------|--------------------|------------|
|
||||
| `foundation-caddy` | caddy | 80, 443 | **Yes** 80/443 | the internet |
|
||||
| `foundation-forgejo` | forgejo | 3000 (http), 22 (sshd) | SSH **yes** as `:2222`; HTTP **no** (via Caddy) | Caddy → 3000; git over `:2222` |
|
||||
| `foundation-postgres` | postgres | 5432 | **No** (internal only) | forgejo |
|
||||
| `foundation-rustfs` | rustfs | 9000 (S3 API), 9001 (console) | optional (S3 via Caddy) | forgejo, backup |
|
||||
| `foundation-vault` | vault | 8200 | **No** (via Caddy, restricted) | pulumi, components |
|
||||
| `foundation-runner` | act_runner | — (egress only) | **No** | registers to forgejo |
|
||||
| `foundation-registry-cache` | registry:2 | 5000 | **No** (internal only) | runner (Docker Hub pull-through) |
|
||||
|
||||
**Exposure rule**: only Caddy publishes 80/443; Forgejo SSH is the one extra published port (`:2222`).
|
||||
Everything else is **internal to `foundation-net`** (PLAN-002 §9.4). The runner SHOULD run on a
|
||||
**separate privileged VM/network** (PLAN-001 §4a) — if co-located, fence it (NetworkPolicy-equivalent).
|
||||
|
||||
### 3.3 Internal endpoints (what components write into config/app.ini)
|
||||
```
|
||||
postgres: foundation-postgres:5432
|
||||
rustfs (S3): http://foundation-rustfs:9000
|
||||
vault: http://foundation-vault:8200
|
||||
forgejo (http): foundation-forgejo:3000
|
||||
registry cache: http://foundation-registry-cache:5000
|
||||
```
|
||||
|
||||
### 3.4 Named volumes (the stateful core — back these up, CONTRACT_004)
|
||||
|
||||
| Volume | Mounted by | Holds | Backup? |
|
||||
|--------|-----------|-------|---------|
|
||||
| `foundation-forgejo-data` | forgejo | **git repos** (POSIX FS — irreducible), app.ini, host SSH keys | **Yes — critical** |
|
||||
| `foundation-postgres-data` | postgres | relational data (users, orgs, CI, package metadata) | **Yes** (via pg_dump) |
|
||||
| `foundation-vault-data` | vault | raft storage | **Yes** (via raft snapshot) |
|
||||
| `foundation-rustfs-data` | rustfs | blobs: LFS, packages, Actions artifacts | **Yes** (bucket-level) |
|
||||
| `foundation-caddy-data` | caddy | ACME certs/account | recreatable (re-issue) — optional |
|
||||
| `foundation-caddy-config` | caddy | autosave config | recreatable |
|
||||
|
||||
Volume root maps under CONTRACT_001 `dataRoot` (e.g. `/srv/foundation/<volume>`).
|
||||
|
||||
## Ownership
|
||||
- `packages/pulumi-docker` provides the `DockerDeployments` primitive (name, image, ports, volumes,
|
||||
networks, envs) — vendored from olsicloud4 `modules/docker`.
|
||||
- Each service component owns exactly one container definition + its volumes; the **network is owned
|
||||
by `network.ts`** and created first.
|
||||
|
||||
## Assumptions
|
||||
- Single VM, single Docker daemon, RWO local volumes (no RWX — that's HA/Layer-1, PLAN-001 HA note).
|
||||
- Container restart policy `unless-stopped`; Vault re-seals on restart → unseal helper (ADR-004).
|
||||
|
||||
## Validation
|
||||
- After each component: `docker ps` shows the container healthy; an internal `curl`/`pg_isready`
|
||||
from a peer container resolves the name and connects.
|
||||
- Only ports 443/80/2222 are reachable from off-host (assert with an external probe).
|
||||
|
||||
## Change Process
|
||||
New service = add a row to §3.2 + §3.3, declare its volumes in §3.4, and (if external) justify the
|
||||
published port. Renaming a container is breaking (it is the DNS name) — version this contract.
|
||||
Loading…
Add table
Add a link
Reference in a new issue