Make it durable
light is one app replica and a single-instance database. ha is two app
replicas that join into one Erlang cluster — so a conversation streaming from
either pod survives — over a Postgres the CNPG operator runs replicated at
2/2. This page stands that up on the same laptop cluster as
Stand it up locally, so the
first time you run the durable shape is not on a cluster that matters.
Install the operators, once
Section titled “Install the operators, once”The replicated database is run by an operator, and operators are the one thing the build does not create:
just operatorsThat installs cert-manager, CNPG and the barman-cloud plugin into the
cluster, cluster-wide. On k3d this is free to undo — just down deletes the
whole cluster.
just params="--param tier=ha --param postgres=cnpg --param dataPlane=sprites --param storage=s3" upOne command, four parameters. tier=ha is the one you wanted; the other
three exist because the laptop defaults are emulators, and ha refuses to
stand on an emulator. Leave one off and the build stops and tells you, one at
a time:
postgres=bundledis a single instance and cannot back anhadeployment →postgres=cnpgdataPlane=spritzeris an in-memory emulator in a single pod →dataPlane=spritesstorage=flociis an emulator whose buckets do not survive a restart, and cannot hold the backups of anhadeployment →storage=s3
The errors are the documentation here: you can start from
just params="--param tier=ha" up and let each refusal hand you the next
parameter.
First boot takes a little longer than light: the app pods wait for CNPG to
bring the primary up before starting. On a brand-new database you may still
see RESTARTS 1 on one replica — both replicas race to create the
migrations table, and the loser retries and wins. Once, on first boot, on an
empty database; not a pattern to watch for after that.
What you get
Section titled “What you get”kubectl get pods -n fountainNAME READY STATUS RESTARTS AGEfountain-6bb8986694-x4sm7 1/1 Running 1 97sfountain-6bb8986694-z89wk 1/1 Running 0 97sfountain-pg-1 1/1 Running 0 84sfountain-pg-2 1/1 Running 0 64sTwo app replicas, and a two-instance Postgres named fountain-pg. The
replicas find each other through a headless Service and form one Erlang
cluster — the proof is in the logs:
kubectl logs deploy/fountain -n fountain | grep "connected to"# [libcluster:fountain] connected to :"fountain_server@10.42.0.14"Only the replica that initiated the connection logs it, so an empty grep on one pod means try the other, not that the cluster failed to form.
A PodDisruptionBudget (kubectl get pdb -n fountain) keeps at least one
replica up through node drains. Reaching it, registering and the first admin
are unchanged from the light
walkthrough:
just forward, then http://localhost:4000.
What is still not real
Section titled “What is still not real”Two of the four parameters name things this laptop does not have, and the stand-up works anyway because the placeholders are only exercised later:
dataPlane=spritespoints at the real Sprites API, but the token in the platform Secret is stilllocal-dev-not-a-real-token. The app boots and serves; starting a conversation is what needs the realSPRITES_TOKEN.storage=s3means backups upload to a real bucket with the AWS credentials in the Secret — which are also placeholders, so the nightly backup job will dump and then fail to upload until you put real ones there. Backups and restore covers both halves.
That is the honest shape of ha on a laptop: the durability is real, the
outside services are not yet. Putting real values in the Secret is the same
step it would be on a real cluster —
Secrets.
just downDeletes the cluster, operators and all.