Control plane failures

Where the control plane lives on a kubeadm node, what each part's failure looks like from kubectl, and how to debug with crictl and the kubelet's log when kubectl itself does not work.

40 min 3 hands-on tasksTroubleshooting · 30% of the exam

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

What you will be able to do

  • Tell from one symptom which part is down: the API server, the scheduler, the controller manager or etcd.
  • Find and fix a typo in a static Pod file under /etc/kubernetes/manifests, and watch the kubelet bring the part back.
  • Read a part's logs with crictl and journalctl when the API server is not answering.

This lesson and the next cover two exam topics: Troubleshoot clusters and and Troubleshoot cluster components.

In a typical task, you ssh to the node and find a file with one wrong character. You fix it and wait for the part to come back. These tasks look scary, because may not work when you start. But a control plane is just four files in one folder, and every tool you need is on the node.

Where the control plane lives

A quick recap from Control plane and node components: the four control plane parts are . The runs them from files in /etc/kubernetes/manifests, the folder named by staticPodPath in /var/lib/kubelet/config.yaml. In kubectl, each shows up as a read-only mirror named <part>-<node>, such as kube-apiserver-cka-control-plane. So to fix a part, edit its file, never the mirror Pod.

Find them (exam: ssh cka-control-plane; lab: docker exec -it cka-control-plane bash)
grep staticPodPath /var/lib/kubelet/config.yaml
ls -l /etc/kubernetes/manifests
# etcd.yaml  kube-apiserver.yaml  kube-controller-manager.yaml  kube-scheduler.yaml

# From anywhere, while the API server works
kubectl -n kube-system get pods -o wide
kubectl -n kube-system get pod kube-apiserver-cka-control-plane -o jsonpath='{.metadata.annotations.kubernetes\.io/config\.source}'   # file

Each part reads its settings from flags in its file. These are the ones that break most often:

Part and its fileTalks toSettings worth checking
, kube-apiserver.yaml on 127.0.0.1:2379. Listens on port 6443--etcd-servers, --client-ca-file, --tls-cert-file, --service-cluster-ip-range, and every path under /etc/kubernetes/pki
, kube-scheduler.yamlthe API server, through /etc/kubernetes/scheduler.conf--kubeconfig, --authentication-kubeconfig, --authorization-kubeconfig
, kube-controller-manager.yamlthe API server, through /etc/kubernetes/controller-manager.conf--kubeconfig, --cluster-signing-cert-file and -key-file, --service-account-private-key-file, --root-ca-file
etcd, etcd.yamllistens on 2379 (clients) and 2380 (other etcd members). Keeps its data in /var/lib/etcd--data-dir, --listen-client-urls, --cert-file, --key-file, --trusted-ca-file

Symptoms by part

Which part is down? Read the symptom

API server

kubectl: connection refused

Scheduler

new Pods Pending, no events

Controller manager

Deployments make no Pods

etcd

kubectl hangs or times out

Each part fails in its own way. In all four cases, Pods that are already running keep running.

  • kube-apiserver down. Every kubectl command fails with The connection to the server <host>:6443 was refused, or with an i/o timeout. Pods already running keep serving traffic, but nothing can be created, scaled or deleted. This is the one failure you must debug entirely on the node.
  • kube-scheduler down. New Pods stay Pending with NODE <none> and no events at all, not even FailedScheduling. Nothing is looking at them. kubectl -n kube-system get pods shows the scheduler Pod in CrashLoopBackOff or Error, or missing.
  • kube-controller-manager down. The API accepts every change, but nothing acts on it. A new shows 0/3, with no and no Pods. Scaling does nothing, never start, and a node you shut down is never marked NotReady.
  • etcd down. The API server runs, but cannot read or write its data. kubectl hangs, or says etcdserver: request timed out or context deadline exceeded. On the node, crictl ps -a shows the etcd Exited or missing.

Debugging while kubectl works

While the API server answers, read the other parts through it
kubectl -n kube-system get pods
kubectl -n kube-system describe pod kube-scheduler-cka-control-plane | tail -15
kubectl -n kube-system logs kube-scheduler-cka-control-plane
kubectl -n kube-system logs kube-controller-manager-cka-control-plane --previous
kubectl get --raw '/readyz?verbose'             # one [+] ok or [-] failed line per check, etcd included

A mirror Pod has events and logs like any other Pod, so describe and logs usually show the typo. The table in What goes wrong in a below lists which typo gives which message. Whatever you find, fix it in the manifest file.

Debugging when kubectl does not work

When the API server is down, kubectl cannot reach anything. Two tools still work, because they run on the node and do not need the API server:

ToolWhat it asksWorks when the API server is down?
kubectlthe API serverNo
crictlthe () on this nodeYes
journalctl -u kubeletthe kubelet's own log on this nodeYes

In crictl ps -a, read two columns. STATE says Running or Exited. ATTEMPT counts restarts: if it keeps climbing, the part is crash-looping. If a part has no container at all, it never started. The kubelet could not pull its image or could not read its file.

On the control-plane node
crictl ps -a                                   # every container, including Exited ones
crictl ps -a --name kube-apiserver
crictl logs <container-id>                     # the component's own output; add --tail 50
crictl pods                                    # sandboxes, including ones with no container
journalctl -u kubelet --since '10 min ago' --no-pager | grep -iE 'apiserver|manifest|static|failed' | tail -20
journalctl -u kubelet -f                       # watch while you fix
systemctl status kubelet --no-pager
cat /etc/kubernetes/manifests/kube-apiserver.yaml

On the lab, run those after docker exec -it cka-control-plane bash. On the exam, run them after ssh <control-plane-node>, and sudo -i if you are not root. Either way, type exit before the next question. kubectl on the node has no , so it fails with connection refused to localhost:8080. That looks like a second outage, but it is not.

What goes wrong in a manifest

MistakeWhat you see
A typo in the image tagNo container in crictl ps -a. The kubelet journal says Failed to pull image, with the bad name. Once the API server is up, the mirror Pod shows ErrImagePull. Compare with the other manifests: the API server, controller manager and scheduler use the same version tag.
A typo in the commandThe container cannot start. describe on the mirror Pod, or the kubelet journal, quotes exec: "kube-schedulerr": executable file not found in $PATH.
A typo in a flagThe container starts and exits within a second. crictl logs prints Error: unknown flag: --etcd-serverss. ATTEMPT climbs.
A wrong path in a flag--kubeconfig or a certificate flag points at a missing file. The log says open /etc/kubernetes/…: no such file or directory. Check that the path exists on the node, and that a hostPath volume mounts it into the container.
that does not parseThe part simply disappears: no mirror Pod, no container. Only the kubelet journal says why: Could not process manifest file, with the path.

A file moved out of the folder makes its part stop, too. And never keep a backup copy inside the folder: the kubelet runs every file there, as Control plane and node components warns.

Three fast checks for a suspicious manifest
cd /etc/kubernetes/manifests
grep -n 'image:' *.yaml                                   # tags agree? (etcd has its own)
grep -o '/etc/kubernetes/[a-z./-]*' kube-apiserver.yaml | sort -u | xargs ls -ld    # every path exists?
diff /tmp/kube-apiserver.yaml.bak kube-apiserver.yaml     # if you (or the task) made a backup

Fix, then wait: the rhythm

The kubelet watches the folder, so it notices a saved file within seconds. It stops the old container and starts a new one. After an API server fix, allow up to a minute before kubectl answers. The server must start, pass its own health checks and reconnect to etcd. Watch with crictl ps on the node, or with watch kubectl -n kube-system get pods once kubectl answers.

The rhythm for a manifest fix

Back up

outside the folder

cp … /​tmp/​

Edit the file

fix the one wrong character

Watch

the kubelet restarts the part

crictl ps

Exit and prove

from your own terminal

kubectl get …

The rhythm for a manifest fix
cp /etc/kubernetes/manifests/kube-apiserver.yaml /tmp/kube-apiserver.yaml.bak   # outside the directory
vim /etc/kubernetes/manifests/kube-apiserver.yaml                               # fix the one character
journalctl -u kubelet -f | grep -i apiserver                                    # Ctrl-C when it says the pod was created
crictl ps --name kube-apiserver                                                 # Running, ATTEMPT stable
exit
kubectl get nodes                                                               # back in business

In the official docs· open on exam day too

Hands-on task 1 of 3ts-cp-1
~4 min2% weightTroubleshooting

Map the control plane's static Pods

On cka-control-plane the kubelet runs the control-plane components as static Pods. Write to /tmp/cka/static-pods.txt: on the first line, the absolute path of the directory the kubelet on that node reads static Pod manifests from, taken from the kubelet's configuration file rather than from memory; then the names of the control plane's static Pods exactly as kubectl get pods -n kube-system shows them, one per line.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ts-cp-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/ts-cp-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/ts-cp-1/cleanup | bash
Hands-on task 2 of 3ts-cp-2
~10 min7% weightTroubleshooting

Nothing gets scheduled

The Deployment web in namespace ts-cp was created a few minutes ago and all of its Pods are still Pending; new Pods anywhere in the cluster do not start either. Find the cause on the control-plane node and fix it there. When you are done the Deployment must have 2 Pods Running and the component you repaired must be healthy.

Cluster:kubectl config use-context kind-cka

Setup breaks part of your lab on purpose, like the exam does. Run the clean-up step when you finish.
  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ts-cp-2/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/ts-cp-2/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/ts-cp-2/cleanup | bash
Hands-on task 3 of 3ts-cp-3
~10 min7% weightTroubleshooting

A Deployment that creates nothing

The Deployment api in namespace ts-cp was created with 3 replicas but has no Pods at all, and kubectl get rs -n ts-cp shows nothing. Find the failing control-plane component on cka-control-plane and repair it. When you are done the Deployment must have 3 Pods Running.

Cluster:kubectl config use-context kind-cka

Setup breaks part of your lab on purpose, like the exam does. Run the clean-up step when you finish.
  1. 1

    Set up the scenario

    curl -fsSL https://codewithmuh.com/labs/cka/t/ts-cp-3/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/ts-cp-3/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/ts-cp-3/cleanup | bash

Finished this lesson?

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