New Datacenter Never Elects a Leader
Globex is standing up a new production datacenter: five m5.large instances across three AWS AZs tagged consul-server=true env=prod, plus 60 clients in a second VPC that peers over a transit gateway. Every server config uses retry_join with provider=aws tag_name=consul-server,env=prod and a shared encrypt key. Four servers were templated with bootstrap_expect = 3; one was rebuilt from an old template that still has bootstrap_expect = 5. Ports 8300-8302 and 8600 are open inside each AZ's security group, but the cross-AZ rule was only added to the client security group. After 20 minutes, two servers report No cluster leader, consul members on a third shows only itself, and all 60 clients sit in a failed state. The AWS auto-join step logs show a successful instance lookup.
1. The AWS auto-join step succeeded, so why is there no leader? Give a diagnostic order that separates the two faults quickly.
Read the worked answer
Auto-join success only proves the IAM call to ec2:DescribeInstances returned addresses. It says nothing about whether gossip or RPC on those addresses is reachable, which is the classic trap here.
Diagnostic order:
consul memberson each server. A node that lists only itself has no LAN gossip peers - that points at the network, not at Raft. If a node lists peers but they are markedfailed, you are looking at a different problem.- Agent log for the join error text.
dial tcp <ip>:8301: i/o timeoutmeans the security group is blocking;encryption key mismatchmeans theencryptkey differs; a log line namingbootstrap_expectpoints at the template fault. The three lines have completely different remedies, so read before changing. - Verify the actual port matrix on the cross-AZ path: 8300/tcp (server RPC), 8301/tcp and 8301/udp (LAN gossip), 8302/tcp and 8302/udp (WAN gossip), and 8600 for DNS where clients query directly. The scenario has cross-AZ rules only on the client security group, so server-to-server gossip across AZs is blocked - and with one server per AZ, no three servers can see each other, which alone explains "no cluster leader".
- Diff
bootstrap_expectacross all five config files. A mismatched value is a second, independent defect that will keep the cluster from converging cleanly even after the networking is fixed.
Fix the network first, then normalize every server's config to the same bootstrap_expect, then restart one at a time and watch for a leader before touching the clients.
2. What should `bootstrap_expect` actually be for this deployment, and what are the consequences of each of the two values in play?
Read the worked answer
bootstrap_expect declares how many servers should participate in Raft before the cluster considers itself formed, and it must be identical on every server. Here the intended steady state is five servers, so it should be 5, with quorum of 3 and tolerance of two failures.
Consequences of the values in the configs:
bootstrap_expect = 3on a five-node deployment: the first three servers to see each other will form a cluster and elect a leader immediately, which masks the missing cross-AZ connectivity during rollout. The remaining two eventually join as voters, silently taking the peer set from three to five and moving quorum from 2 to 3. You end up with the right number of voters but no deliberate step where that happened, and the initial three-server window gives you a false sense of a working deployment.bootstrap_expect = 5on only one node: the values disagree, so the cluster does not converge consistently and the divergence shows up as odd, partial join behaviour rather than a clean error. Treat any mismatch as a defect to fix before further debugging.
Also: never set bootstrap and bootstrap_expect together on the same agent - they conflict. For a cluster this size, the durable answer is a single templated config rendered from one value, so a rebuilt box cannot reintroduce a stale setting, and Autopilot's steady-state health checks are then meaningful because the expected server count never moves underneath them.
3. The clients in the second VPC were copied from a previous environment and carry a different `encrypt` key. What happens, and how should gossip encryption be rolled out and later rotated?
Read the worked answer
Gossip encryption operates on the Serf layer, which is separate from RPC TLS and from Connect mTLS. Members must share the same key: a client with a different key fails the handshake and never appears in the gossip pool, so the server never learns about it and it can never register services - matching the 'all 60 clients failed' symptom, and it would persist even after the security group is fixed.
Rollout:
- Put the same
encryptvalue in every server and client config, across both VPCs. The WAN gossip pool also uses gossip encryption, so if this datacenter later federates with another, both sides need the same key. - Set
encrypt_verify_incomingandencrypt_verify_outgoingtotrueonce every agent is on the key. Leaving verification off means an agent accepts unencrypted gossip, which defeats the purpose. - Restart clients in batches and confirm each appears in
consul membersbefore moving on.
Rotation, later, without downtime:
consul keyring -install <newkey>on every agent (installs without using it),consul keyring -use <newkey>to make it primary,consul keyring -remove <oldkey>after all members are on the new key.
Note the boundary: gossip encryption protects Serf traffic only. It does nothing for RPC or HTTP, which need verify_incoming/verify_outgoing/verify_server_hostname, and it is unrelated to Connect's mTLS. Also remember the gossip key is agent configuration, so it is not captured in a Consul snapshot and must be stored in your secrets system alongside the restore runbook.