# Deployment Blueprint — ihp-railiance-probe Textual equivalent of a C4 Deployment Diagram covering the full build-to-production cycle. Read top-to-bottom as the artifact flows through each node. --- ## Deployment Nodes ### Node: Developer Workstation - **Host**: `localhost` (WSL2 on Windows, `linux/x86_64`) - **Role**: source editing, flake authoring, orchestration - **Key tools**: git, sshpass, skopeo (client), nix (local, for dry-runs only) - **Constraints**: not used for Haskell compilation — insufficient RAM for GHC on large module graphs ### Node: haskelseed (Build Server) - **Host**: `192.168.178.135` (Alpine Linux VM, LAN-local to workstation) - **SSH access**: `root` / `hcs26!x` (password) or via `ssh haskelseed` alias - **Role**: sole Haskell compilation and `nix build` host - **Resources**: 2 CPU, ~3.8 GiB RAM, 100 GB NVMe at `/nix` (`/dev/sdb1`) - **Nix store**: `/nix/store` on dedicated volume; store paths survive reboots - **Key constraint**: `libHSghc-9.10.3-5702.a` in the Nix store may be truncated (287 MB vs full 289 MB); must be patched before production builds if affected (see `inter-hub/HaskellVibePrimer.md` §Bug 2) - **GHC version**: 9.10.3 (from IHP v1.5 flake) - **GHCRTS**: `-A32m -M2g` (heap ceiling to prevent OOM) ### Node: CoulombCore VPS (Registry + Gitea) - **Host**: `92.205.130.254` - **SSH access**: `tegwick` via `id_ops` key (alias `coulombcore`) - **Role**: Gitea source hosting + built-in OCI container registry - **Gitea SSH**: port `30022`, alias `gitea-remote` in `~/.ssh/config` - **Registry endpoint**: `92.205.130.254:32166` (HTTP, no TLS — internal use) - **Image namespace**: `coulomb/ihp-railiance-probe` - **Registry auth**: Gitea credentials (same user as Gitea login) ### Node: Railiance01 (Production Cluster) - **Host**: `92.205.62.239` - **SSH access**: `tegwick` via `id_custodian_agent` key (alias `railiance01`) - **Role**: k3s Kubernetes cluster, deployment target - **Namespace**: `coulomb` (shared with inter-hub) - **Image pull**: cluster pulls from `92.205.130.254:32166` (LAN-adjacent VPS, no auth needed if registry is public or cluster has credentials configured) - **Ingress**: Traefik (k3s default); routes via IngressRoute or Ingress manifest --- ## Deployment Pipeline — Step by Step ``` [Workstation] │ │ git push (SSH via gitea-remote) ▼ [CoulombCore — Gitea] │ │ (no CI yet; developer triggers manually) │ ▼ [Workstation] │ │ scp flake.nix + source → haskelseed │ (or: git push + git pull on haskelseed) ▼ [haskelseed — Build] │ nix build .#docker │ → evaluates flake.nix │ → builds inter-hub-models (GHC, 477 modules) ← cached after first build │ → builds inter-hub-lib (GHC, 199 modules) │ → builds inter-hub-binaries │ → assembles OCI tarball (result → /root/ihp-railiance-probe/result) │ │ # Gitea's registry token realm points to port 80; skopeo must use a │ # pre-fetched token to avoid following that misconfigured URL. │ TOKEN=$(curl -s \ │ "http://92.205.130.254:32166/v2/token?service=container_registry\ │&scope=repository:coulomb/:push,pull" \ │ -u 'tegwick:' | awk -F'"' '/token/{print $4}') │ skopeo copy --insecure-policy --dest-tls-verify=false \ │ --dest-registry-token "$TOKEN" \ │ docker-archive:result \ │ docker://92.205.130.254:32166/coulomb/: ▼ [CoulombCore — Registry] │ image stored as coulomb/ihp-railiance-probe: │ ▼ [Railiance01 — Kubernetes / k3s] │ helm upgrade --install ihp-railiance-probe ./chart │ --set image.tag= │ --namespace coulomb │ │ k3s pulls image from 92.205.130.254:32166 │ Deployment → ReplicaSet → Pod (RunProdServer binary) │ Service (ClusterIP) → IngressRoute (Traefik) ▼ [External / Browser] GET https://probe.railiance.example/ ``` --- ## Container: ihp-railiance-probe Application - **Base**: IHP unoptimized Docker image (`config.packages.unoptimized-docker-image`) - **Entry point**: `/bin/RunProdServer` - **Exposed port**: `8000` (IHP default) - **Environment variables** (injected via Kubernetes Secret / ConfigMap): | Variable | Purpose | |----------|---------| | `IHP_SESSION_SECRET` | Session encryption key (32+ random bytes, base64) | | `DATABASE_URL` | PostgreSQL connection string | | `IHP_BASEURL` | External URL shown in links (e.g. `https://probe.coulomb.example`) | - **PostgreSQL**: deployed as a separate pod (`bitnami/postgresql`) or uses the shared CoulombCore postgres — TBD per cluster capacity --- ## Artifact Versioning | Artifact | Identifier | Retention | |----------|------------|-----------| | Git commit | `` (short, from `git rev-parse --short HEAD`) | permanent in Gitea | | OCI image | `coulomb/ihp-railiance-probe:` | keep last 5 tags | | Helm release | `ihp-railiance-probe` in namespace `coulomb` | single release, upgraded in-place | | Nix build result | `/root/ihp-railiance-probe/result` symlink on haskelseed | GC'd by `nix store gc` | --- ## Known Infrastructure Constraints | Constraint | Impact | Mitigation | |------------|--------|------------| | haskelseed 2 CPU / 3.8 GB RAM | Full GHC build saturates RAM | `GHCRTS=-A32m -M2g`; `-j1` in flake | | GHC 9.10.3 `.hi` overflow (>274 MB) | Crash after all modules compile | ActualTypes postUnpack overlay in flake.nix | | GHC 9.10.3 `libHSghc.a` truncated | Crash at position 287,686,318 | Direct archive patch on haskelseed (one-time; check after flake lock update) | | Registry on HTTP (no TLS) | k3s defaults to HTTPS for pulls | Configure k3s `registries.yaml` with mirror entry for `92.205.130.254:32166` | | Gitea registry token realm misconfigured | `Bearer realm` points to `gitea.coulomb.social:80` but Gitea is on port 32166; skopeo follows the realm URL and gets 404 | Pre-fetch token via `curl` against port 32166 and pass with `--dest-registry-token`; do NOT rely on skopeo's automatic token fetch | | No CI runner yet | Manual build + push | Phase 6 of workplan adds Gitea Actions runner on haskelseed | --- ## Key File Locations | File | Node | Path | |------|------|------| | Nix flake | Workstation + haskelseed | `flake.nix` | | Helm chart | Workstation | `chart/` | | GHC archive (may be truncated) | haskelseed | `/nix/store/ffg3yf2ypnbz3hc31y7nglrkihz0if01-ghc-9.10.3/lib/ghc-9.10.3/lib/x86_64-linux-ghc-9.10.3/ghc-9.10.3-5702/libHSghc-9.10.3-5702.a` | | Build log | haskelseed | `/tmp/build.log` | | k3s registries config | Railiance01 | `/etc/rancher/k3s/registries.yaml` |