Highly available control planes

Stacked or external etcd, quorum math, a load balancer in front of the API servers, and the kubeadm flags that add more control plane nodes.

35 min 2 hands-on tasksArchitecture · 25% of the exam

Key ideas in this lesson · tap one for a simple explanation

What you will be able to do

  • Explain stacked and external etcd, and say how many failures three or five etcd members survive.
  • Start a cluster with a load-balanced controlPlaneEndpoint and join more control plane nodes with --control-plane and --certificate-key.
  • Read how an existing cluster's control plane is laid out, from the kubeadm-config ConfigMap and the API server's flags.

A highly available (HA) keeps working when one control plane machine dies. You get it by running the control plane on three machines instead of one. Example: your cluster has one control plane and its disk fails. Running apps keep going, but nobody can deploy, scale or fix anything until it is back. With three control plane nodes, the other two carry on.

This lesson covers the exam topic Implement and configure a highly-available control plane. The exam will not make you build a load balancer. It can ask you to join another control plane node, or to say how many members may fail. It can also ask how a cluster is laid out.

An HA control plane with stacked etcd

Clients

kubectl, kubelets and joining nodes

Load balancer

the controlPlaneEndpoint

k8s-api.lab.internal:6443

Three control plane nodes

cp1

API server, etcd, scheduler, controller manager

cp2

the same

cp3

the same

Everyone uses one address, the load balancer. It passes each request to any healthy API server.

What has to be redundant

In an HA cluster, each control plane part runs on several machines. But the copies work together in different ways:

PartHolds data?How the copies work together
NoAll copies serve requests at the same time. A load balancer in front spreads requests across them.
Scheduler, NoOnly one copy works at a time, the leader. The others wait, ready to take over.
etcdYes, all cluster dataEvery write needs a majority of the members to agree. This is the hard part.

Quorum: why three members, not two or four

Quorum means a majority of the etcd members. etcd saves a write only once a has it. The formula is floor(n/2) + 1: half the members, rounded down, plus one. Example: with 3 members, quorum is 2, so 1 member can fail.

etcd membersQuorum (majority)Failures tolerated
110
220
321
431
532
  • Even numbers add nothing. 4 members survive 1 failure, the same as 3, with one more machine that can break. 2 members are worse than 1.
  • Run 3, or 5 if you must survive 2 failures. More members make every write wait for more machines.
  • When quorum is lost, nothing can change. The API server cannot save anything. Running keep running, but you cannot create, change or delete objects.
etcd quorumTap a member to stop or start it.
writes ok0
MembersQuorumCan lose
321
431
532
3 of 3 members running, quorum is 2: writes succeed. This cluster can lose 1 more member and keep working.
members

Stacked or external etcd

There are two ways to place etcd. Stacked: each control plane node also runs an etcd member, so 3 machines give you 3 API servers and 3 etcd members. This is what builds by default. External: etcd runs on its own machines, so the same takes 6 machines.

Stacked etcdExternal etcd
Where etcd runsA on every control plane node. kubeadm creates it.On its own machines, usually as a Linux service, set up before kubeadm init
The API server talks toIts own local member: --etcd-servers=https://127.0.0.1:2379Every member: --etcd-servers=https://10.0.0.21:2379,https://10.0.0.22:2379,…
Machines for three of each36
When one machine failsYou lose an API server and an etcd member togetherThe control plane and etcd fail separately
In kubeadm-configetcd.localetcd.external, with the members' addresses and client certificate paths
etcd.yaml in the folderYesNo

Building it with kubeadm

You build an HA cluster with the same kubeadm init and kubeadm join as a normal one, plus four flags:

FlagUsed withWhat it does
--control-plane-endpointkubeadm initThe one shared address of all API servers: the load balancer.
--upload-certskubeadm initStores the shared certificates in the cluster, encrypted, for two hours, so new control plane nodes can download them.
--control-planekubeadm joinMakes the new node a control plane node, not a worker.
--certificate-keykubeadm joinThe key that unlocks the uploaded certificates.
First control plane, then the others
# First control plane. The endpoint is the load balancer's DNS name (or VIP) and port.
sudo kubeadm init \
  --control-plane-endpoint "k8s-api.lab.internal:6443" \
  --upload-certs \
  --pod-network-cidr=192.168.0.0/16

# kubeadm prints two join commands. The control plane one adds two flags:
sudo kubeadm join k8s-api.lab.internal:6443 --token <token> \
  --discovery-token-ca-cert-hash sha256:<hash> \
  --control-plane --certificate-key <key>

# Two hours later the uploaded certificates are gone. On an existing control plane:
sudo kubeadm init phase upload-certs --upload-certs                  # prints a new key
sudo kubeadm token create --print-join-command --certificate-key <new-key>

controlPlaneEndpoint is the one address that every , and joining node uses. Set it on day one, even with a single control plane node: kubeadm cannot turn a cluster built without it into an HA one later. On this kind lab it is cka-control-plane:6443.

With external etcd you use a config file instead of flags. Only the etcd part differs:

External etcd in a kubeadm config file (kubeadm init --config … --upload-certs)
apiVersion: kubeadm.k8s.io/v1beta4
kind: ClusterConfiguration
controlPlaneEndpoint: "k8s-api.lab.internal:6443"
etcd:
  external:
    endpoints:
      - https://10.0.0.21:2379
      - https://10.0.0.22:2379
      - https://10.0.0.23:2379
    # plus caFile, certFile and keyFile: the client certificate the API server uses for etcd

Reading an existing cluster's layout

Exam questions about HA are mostly about reading. kubeadm saved its choices in the kubeadm-config , and the API server's flags show which etcd members it uses:

Reading the layout of a running cluster
# What kubeadm decided at init time
kubectl -n kube-system get cm kubeadm-config -o jsonpath='{.data.ClusterConfiguration}' | grep '^controlPlaneEndpoint:'
kubectl -n kube-system get cm kubeadm-config -o jsonpath='{.data.ClusterConfiguration}' | grep -A3 '^etcd:'

# Which etcd members the API server uses (one argument per line, so commas stay intact)
kubectl -n kube-system get pod -l component=kube-apiserver \
  -o jsonpath='{range .items[0].spec.containers[0].command[*]}{@}{"\n"}{end}' | grep -- --etcd-servers

# Control plane nodes and their Pods
kubectl get nodes -l node-role.kubernetes.io/control-plane
kubectl -n kube-system get pods -l tier=control-plane -o wide

In the official docs· open on exam day too

Hands-on task 1 of 2ar-ha-1
~6 min4% weightArchitecture

Describe this cluster's control plane layout

Find out how this cluster's control plane is wired, without changing anything, and write each answer as a bare value. (1) The control plane endpoint kubeadm configured, as host:port, to /tmp/cka/ar-cp-endpoint.txt. (2) The etcd topology, as the single word stacked or external, to /tmp/cka/ar-etcd-topology.txt. (3) The full value of kube-apiserver's --etcd-servers flag to /tmp/cka/ar-etcd-servers.txt. (4) If this cluster were grown to five control plane nodes with the same etcd topology, how many etcd members could fail at once without losing quorum? Write the number to /tmp/cka/ar-etcd-tolerance.txt.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ha-1/setup | bash
  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ha-1/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.
  4. 4

    Clean up (optional)

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ha-1/cleanup | bash
Hands-on task 2 of 2ar-ha-2
~12 min7% weightArchitecture

Join a third control plane node

Clients reach this cluster's API through a load balancer at k8s-api.lab.internal:6443. Control plane nodes cp1 and cp2 run stacked etcd. Node cp3 is prepared with containerd and v1.37 packages and is already in the load balancer's backend pool. Join cp3 as a third control plane node. The cluster was initialized days ago, so neither its bootstrap token nor its certificate key is valid anymore. You work on cp1; ssh cp3 reaches the new node.

Runs on a kubeadm cluster (VM lab), not on the kind lab.

This one needs a cluster built with kubeadm. Read it and study the solution now, then run it on your VM lab.
  1. 1

    Start from a healthy lab

    No setup needed for this one.

  2. 2

    Solve it in your terminal

    Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under /tmp/cka/.

  3. 3

    Check your work

    curl -fsSL https://codewithmuh.com/labs/cka/t/ar-ha-2/verify | bash
    Got FAIL? Read which check failed, fix it, run it again.

Finished this lesson?

0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.