Skip to content

Migration Path

The one-page sequence. Do these in order. Do not skip ahead — every later stage assumes the earlier ones are done. Each stage lists its entry gate (what must be true before you start) and its done signal.

[0] Foundation        ->  [1] Compose-in-Git  ->  [2] Hardened Postgres DR
    (static IPs,           (services declared      (pg_dump warm-standby +
     stable names)          in git, health-           tested promote +
                            checked, restart)         restore-verify)
                                   |
                                   v
                    [3] (OPTIONAL) Swarm for STATELESS only
                                   |
                                   v
                    [4] (LATER / LEARNING) k3s

Stage 0 — Foundation (do this first, always)

Why first: every clustering tech (Swarm, k3s, full k8s) and even the DR failover scripts assume nodes can find each other by a name that does not change. Home Wi-Fi hands out churning DHCP leases and one subnet here is an isolated island. That instability is exactly what breaks etcd quorum, Swarm raft, and any PRIMARY_HOST reference. Fix addressing before anything else.

  • Do: foundation/Set-HomelabHostsAliases.ps1 to pin stable names, read foundation/README.md for DHCP-reservation guidance, optionally install Tailscale for MagicDNS (survives subnet islands + IP churn).
  • Entry gate: none.
  • Done when: every node resolves every other node by a stable name that does not change across reboots/lease renewals (ping homelab-node2 works from all nodes, including across the isolated subnet if you took the Tailscale option).

Why: declarative, diffable, trivially restartable, no control plane to keep quorate. This is the pragmatic substrate the council endorsed.

  • Do: compose/scripts/Deploy-ComposeStack.ps1 for each stack; commit the compose files. Health checks + restart: unless-stopped give you single-node self-healing without a scheduler.
  • Entry gate: Stage 0 done.
  • Done when: claude-mem stack + sample daemon come up healthy from a clean git clone on any node with one script call.

Stage 2 — Hardened Postgres DR

Why: no orchestrator (Swarm, k3s, k8s) replicates your Postgres data for you. Statefulness is solved at the database layer, deliberately, or not at all.

  • Do: schedule compose/scripts/Backup-PostgresWarmStandby.ps1 hourly; keep Promote-PostgresStandby.ps1 and Test-PostgresRestore.ps1 tested; use the primary-marker (Set-PrimaryMarker.ps1) so two nodes never both think they are primary.
  • Entry gate: Stage 1 done.
  • Done when: a scheduled restore-verification passes on a standby, and a rehearsed promote brings claude-mem back on a second node within your RTO.

Stage 3 — (OPTIONAL) Swarm for stateless only

Why optional: Swarm is the only clustering worth a look here, and only after the network is genuinely stable, and only for stateless daemons. Never put Postgres in it.

  • Do: compose/swarm/Init-Swarm.ps1 + Deploy-SwarmStack.ps1.
  • Entry gate: Stage 0 rock-solid for weeks (no name/IP churn incidents), Stage 1+2 done, and you actually have 2+ stateless daemons worth spreading.
  • Done when: a stateless service survives a node drain by rescheduling.
  • See: docs/when-to-graduate.md.

Stage 4 — (LATER / LEARNING) k3s

Why last: full/real k8s here is overkill and fragile (Linux control plane on Windows via WSL2/VMs, Wi-Fi/DHCP churn breaks etcd quorum, k8s does not replicate Postgres). But it is the best hands-on way to practice k8s for a job. Treat kubernetes/ as a lab, not production.

  • Do: kubernetes/ — stand up k3s on Linux nodes (WSL2/VMs), run the practice runbook, tear it down.
  • Entry gate: you want k8s practice, OR the graduation triggers in docs/when-to-graduate.md fire (e.g. you own an always-on Linux mini-PC with a static IP).
  • Done when (learning): you can create → deploy → kill a node → watch reschedule → teardown from the runbook unaided.

See docs/README.md for the scored decision matrix and docs/how-we-got-here.md for the council reasoning behind this ordering.