# ctrl/addons.sh and ctrl/addons/*.sh ## addons.sh Each addon is its own idempotent script — adding one is adding a file, not editing a dispatcher. `ADDONS` names them, in install order; the overlay's `addons/.sh` is found before rig's `ctrl/addons/.sh`, and every one runs from rig's `ctrl/` with `RIG_CTRL` exported, wherever its file lives (see [overlay.md](overlay.md)). ## What rig ships, and what it does not rig's own addons make the *cluster* work, and are useless outside one: metallb, cert-manager, metrics-server. Things a workload happens to need — a database, a cache, a scheduler — are the workload's, and which workload needs which is not rig's business, so they live with the overlay. `examples/data/addons/` has postgres, redis and airflow as a worked example; an overlay that wants them copies them in. ## cert-manager.sh In a regulated estate almost everything is TLS, so the interesting question during onboarding is "does this service present a cert my client trusts" — not "can I reach a public ACME server". A local CA answers that offline, which is also what makes the air-gapped profile usable. ## metallb.sh — why it matters Real manifests use LoadBalancer, because a real cluster has one. On a bare kind cluster those Services sit at `EXTERNAL-IP ` forever with no error anywhere — the deployment looks fine and simply is not reachable. Without MetalLB, every such Service has to be edited to NodePort, which means the local manifests stop matching the ones being modelled. The address pool is derived from the kind Docker network at install time, not hardcoded: Docker picks that subnet, it differs between machines, and a pool outside it is silently unroutable. ## metallb.sh — waiting for the controller `kubectl wait` on a selector errors out immediately when nothing matches yet, and right after apply the ReplicaSet has not created the pod — so it loses a race it looks like it should win. `rollout status` waits for the Deployment itself and handles the not-yet-created case. ## metrics-server.sh kind nodes serve kubelet metrics over a self-signed cert, so the standard manifest never becomes ready without `--kubelet-insecure-tls`. That is fine here (it is a local cluster) and is the single most common reason metrics-server sits at 0/1 on kind.