Files
ihp-railiance-probe/DeploymentBlueprint.md
tegwick b818866c7f docs: document Gitea registry token workaround
Gitea's registry token realm is misconfigured — it points to
gitea.coulomb.social:80 but Gitea only listens on port 32166. iptables
is not available on haskelseed (Alpine). Workaround: pre-fetch the bearer
token via curl against port 32166 and pass it to skopeo with
--dest-registry-token, bypassing the broken token service URL entirely.

Validated with inter-hub:11ff61c on 2026-05-02.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-02 17:09:48 +02:00

6.6 KiB

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/<APP>:push,pull" \
    │    -u 'tegwick:<GITEA_API_KEY>' | 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/<APP>:<SHA>
    ▼
[CoulombCore — Registry]
    │  image stored as coulomb/ihp-railiance-probe:<SHA>
    │
    ▼
[Railiance01 — Kubernetes / k3s]
    │  helm upgrade --install ihp-railiance-probe ./chart
    │    --set image.tag=<SHA>
    │    --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 <SHA> (short, from git rev-parse --short HEAD) permanent in Gitea
OCI image coulomb/ihp-railiance-probe:<SHA> 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<N>.log
k3s registries config Railiance01 /etc/rancher/k3s/registries.yaml