Lesson 06 of 7 · Fleet-scale scenarios
Cold-start dependency loops
Services that can't start because each needs the other: find circular dependencies (DNS, registry, identity, Git, secrets) before a full outage does, recover stateful clusters after unclean shutdowns, and design and drill a bootstrap order that works from zero.
The problem nobody tests
Platforms usually start incrementally: first the cluster, then the registry, then SSO, then GitOps, all while the previous pieces were already running. Years later, a full outage (power loss, a network event, a bad global change) forces everything to start at once, and hidden loops appear:
- The registry runs in the cluster; pods (including the registry) can't pull images.
- The identity provider runs on the platform; nobody can log in to fix it.
- GitOps pulls from a Git server hosted on the same platform.
- DNS runs as pods whose images come from the in-cluster registry.
- The secrets manager must be unsealed by a process that itself needs secrets.
Two friends each lock their bike key in the other's bike basket. Everything is fine while one bike is unlocked. The day both bikes are locked at the same time, neither can get their key out. A cold start is that day. You fix it by keeping a spare key at home (out-of-band access) and never locking keys inside each other's baskets (no loops).
Build a dependency map in tiers
| Tier | Examples | May depend on |
|---|---|---|
| 0 | Power, network, time (NTP), DNS for infrastructure | Nothing above |
| 1 | Storage, container registry/mirrors, secrets manager, identity/break-glass access | Tier 0 |
| 2 | Kubernetes control planes, GitOps, observability | Tiers 0–1 |
| 3 | Platform services (ingress, service mesh, databases) | Tiers 0–2 |
| 4 | Applications | Tiers 0–3 |
Any arrow pointing upwards (a lower tier needing a higher one) is a potential cold-start loop. Break it: host the registry mirror outside the clusters it serves (or pre-load images), keep break-glass credentials that don't need SSO, keep a Git mirror outside the platform, document the manual unseal path.
Stateful clusters after unclean shutdown
Scenario: the message queue won't recover after a power cut
After a site-wide power cut, a 3-node RabbitMQ cluster (a StatefulSet) never comes back. Pod-0 logs show it waiting for its peers; pod-1 and pod-2 were never created.
What's happening, and how do you recover and prevent it?
What's happening. A RabbitMQ node that restarts waits for the cluster peers it knew when it stopped (for a limited time, with retries), because the last node to stop has the most recent state. The StatefulSet uses the default OrderedReady policy: pod-1 isn't created until pod-0 is Ready, and pod-0 isn't Ready until it sees its peers. Deadlock.
Recover.
- Allow all members to start: set
podManagementPolicy: Parallel(this field can't be changed on an existing StatefulSet; recreate it with--cascade=orphanto keep pods and PVCs, or use the RabbitMQ Cluster Operator, which uses Parallel). - If a node still can't find peers and you've determined which node has the most recent data, RabbitMQ's
force_bootlets that node start without waiting (follow the RabbitMQ docs; forcing the wrong node can lose recent messages). - Check queues and consumers once the cluster forms.
Prevent. Use the vendor's operator (it encodes these rules), Parallel pod management for peer-discovering clusters, quorum queues, and a power-loss drill in staging. The same class of problem appears in other clustered systems (etcd, Galera, Kafka controllers): know each one's recovery procedure before the outage.
Break-glass and out-of-band access
- Break-glass accounts: local cluster credentials (stored securely offline or in a separate vault) that work when SSO is down; usage alerts on every login.
- Out-of-band network access to BMCs/consoles and management networks.
- Printed/offline runbooks for the cold-start order: when the wiki is on the platform, it's down too.
Cold-start drills
In a staging environment that mirrors production's dependencies:
- Shut everything down (or cut power to a lab rack).
- Start in tier order, timing each step and noting anything that needed manual help.
- Fix every loop or manual step found; repeat until the cold start is boring.
Try it: find and break a loop
- Draw your platform's dependency map in tiers and mark every upward arrow.
- In a kind cluster, create a 3-replica StatefulSet of a small app that waits for all peers' DNS names before becoming ready (a shell loop with
nslookup); observe the OrderedReady deadlock, then recreate it withpodManagementPolicy: Parallel. - Stop and restart the whole kind cluster (
docker stopall nodes, then start) and note what fails to come back on its own. - Create a break-glass kubeconfig (a client certificate or token for an emergency admin), store it offline, and test it with SSO disabled.
- Write a one-page cold-start runbook in tier order.
Going deeper: designing for zero
- Make "can this platform start from nothing?" a design review question (see Cluster Design — Architect Track, lesson 13).
- Keep tier-0/1 services outside the clusters they support, or duplicated with independent fate.
- Re-run cold-start drills after major architecture changes; new loops sneak in with every convenience.
Recap
- Full outages force everything to start at once, exposing hidden circular dependencies.
- Build a tiered dependency map; every upward dependency is a loop to break.
- Stateful clusters need known recovery procedures (e.g. Parallel pod management, RabbitMQ force_boot used carefully).
- Keep break-glass access, out-of-band paths and offline runbooks, and run cold-start drills.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.