railiance-infra/docs/deploy-stack.md
codex 61c6082ea8
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Gate reef web ports on exposure grants
Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02669-87ee-7a31-b111-edc95a16e0fa
2026-08-22 12:34:25 +02:00

4.8 KiB

Railiance Stack — Full Deploy Runbook

When to use this: Starting from a bare server (post-OS install) or rebuilding after a catastrophic failure. For day-to-day operations use the individual layer repos. See ADR-003 for layer boundaries and ADR-004 for connectivity posture.

Pre-conditions checklist

Before starting, verify you have:

  • SSH access to the selected inventory host. Railiance01 is the current primary; CoulombCore is legacy/frozen and is not a default deployment target.
  • SOPS age private key available (~/.config/sops/age/keys.txt or SOPS_AGE_KEY env)
  • ops-bridge running on the workstation (needed for state hub MCP): make mcp-http in ~/the-custodian/state-hub/
  • Forgejo accessible (git pull on remote): SSH via forgejo-remote:coulomb/<repo>.git
  • Gitea on coulombcore remains read-only fallback only (gitea-remote for emergency rollback)
  • If re-provisioning from scratch: Hetzner/HostEurope API credentials decryptable via SOPS

S1 — Infrastructure Substrate (railiance-infra)

# On workstation
cd ~/railiance-infra

# Provision server (skip if server already exists)
make tf-plan        # review Terraform plan
make tf-apply       # create/update server

# Converge OS baseline on the selected inventory host
ssh -i ~/.ssh/id_ops tegwick@92.205.62.239 \
  'cd ~/railiance-infra && git pull && \
   cd ansible && ansible-playbook playbooks/bootstrap.yaml \
     -c local --become -l Railiance01'

# Verify OS baseline
make verify

Checkpoint: UFW active, fail2ban running, swap enabled, nproc limits in place, SOPS/age installed.


S2 — Cluster Runtime (railiance-cluster)

# On the selected cluster host (Railiance01 for the current primary)
ssh -i ~/.ssh/id_ops tegwick@92.205.62.239

cd ~/railiance-cluster
make converge       # installs k3s, Helm, cert-manager, Traefik, cnpg operator
make smoke          # runs cluster health assertions

Checkpoint: k3s running, Helm available, cert-manager and Traefik pods Running, cnpg-system namespace active.


S3 — Platform Services (railiance-platform)

# On the current primary (kubectl available after S2)
cd ~/railiance-platform && git pull

# Deploy Forgejo database cluster (production on railiance01)
# Credentials via SOPS — see railiance-platform docs/forgejo-backup.md
make forgejo-db-deploy
make forgejo-db-status

# Legacy coulombcore Gitea DB (read-only fallback — retain until T12 retires Gitea)
# make db-deploy && make db-status

# Deploy an optional cache only when a named workload requirement and custody
# path exist. Cache installation is not an unconditional S3 baseline step.

Checkpoint: kubectl get cluster -n databases shows forgejo-db healthy on Railiance01; optional services are present only when explicitly required.


S4 — Developer Enablement (railiance-enablement)

Validate the consumer-facing paved paths; S4 does not deploy the forge runtime:

cd ~/railiance-enablement && git pull
make check
make test

S5 — Workloads & Experience (railiance-apps)

# Verify the forge through its operational owner.
cd ~/railiance-forge && git pull
make gitea-status

# Deploy each application through its owning rapp/release runbook. S5 does not
# own the forge runtime or generic rail/template behavior.

Checkpoint: https://forgejo.coulomb.social serves HTTPS; git clone/push via forgejo-remote; state-hub /state/health returns 200.


ops-bridge tunnel setup (workstation)

After S2 is up, establish the persistent tunnels from the workstation:

bridge up state-hub-coulombcore       # state-hub HTTP (port 18000 remote)
bridge up state-hub-mcp-coulombcore   # state-hub MCP (port 18001 remote)
bridge up k3s-api-coulombcore         # CoulombCore k3s API (port 16443 local)
bridge up k3s-api-railiance01         # Railiance01 k3s API (port 16444 local)

Verify: bridge status shows the tunnels needed for the selected host connected.


Recovery pointers

  • Forgejo backup/restore: railiance-platform/docs/forgejo-backup.md, docs/forgejo-restore-drill-evidence.md
  • Cutover rollback: docs/forgejo-cutover-rollback.md
  • Node overload / SSH unresponsive: See the-custodian/ops/runbooks/gitea-coulombcore.md Issue #3
  • Incident report: the-custodian/ops/incidents/2026-03-26-coulombcore-runaway-agent-overload.md
  • Cluster backup restore: railiance-cluster/tools/cmd/railiance-restore-s2
  • Forgejo SSH: NodePort 30022 on railiance01 (forgejo-ssh-nodeport in forgejo namespace)

Layer dependency chain

S1 (infra) → S2 (cluster) → S3 (platform) → S4 (enablement) → S5 (workloads)

Each layer must be fully converged and verified before starting the next. Never configure S2 concerns from S3+ repos (ADR-003 boundary rule).