70 lines
4 KiB
Markdown
70 lines
4 KiB
Markdown
|
|
# 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.
|