Back to Blog

Cluster & Application Observability for the CKA Exam: metrics-server, kubectl top, kubectl logs & Component Logs

The monitoring and logging half of the CKA Troubleshooting domain, made mechanical. Install and use metrics-server, read resource usage with kubectl top, master kubectl logs flags, and find control-plane, kubelet, and container logs — with the exact commands the exam expects.

By Sailor Team , July 19, 2026

Most CKA candidates drill Pods, Deployments, and networking until they’re reflex — then lose points on the quiet half of the Troubleshooting domain: monitoring resource usage and reading logs. Troubleshooting is the single largest slice of the Certified Kubernetes Administrator exam at 30%, and the curriculum spells out two objectives that have nothing to do with fixing a broken manifest: “monitor cluster and application resource usage” and “manage container stdout and stderr logs.” These are the skills that tell you where a problem is before you start fixing it.

The good news is that this material is small and mechanical. There’s no Prometheus, no Grafana, no third-party stack to learn — the exam expects you to observe a cluster with the tools that ship in the box: metrics-server, kubectl top, kubectl logs, kubectl get events, and the log files on the node itself. This guide turns all of them into muscle memory. For the fixing side of the same domain — pods stuck in CrashLoopBackOff, services with no endpoints, DNS failures — pair this with the CKA troubleshooting guide; the two together cover the full 30%.

The Observability Toolbox on a Vanilla Cluster

Before touching individual commands, fix the mental model. Observability on a bare kubeadm cluster comes from four sources, and each answers a different question:

QuestionToolCommand
How much CPU/memory is being used?metrics-serverkubectl top nodes / kubectl top pods
What is a container printing?container logskubectl logs <pod>
What did the control plane decide?component logskubectl logs -n kube-system or journalctl
What happened to this object over time?eventskubectl get events / kubectl describe

If you can instantly map a scenario to the right row, half the observability tasks answer themselves. The other half is knowing the flags — which is where most of the exam points hide.

metrics-server: The Source of kubectl top

kubectl top does not work on a fresh cluster. It reads from the Metrics API (metrics.k8s.io), which is served by metrics-server — a lightweight component that scrapes the kubelet’s summary API on every node and keeps a short window of CPU and memory data in memory. No metrics-server, no kubectl top. Running kubectl top nodes on a cluster without it returns:

error: Metrics API not available

That error is itself an exam signal: if a task asks you to report resource usage and top fails, your first job is to install or repair metrics-server.

Installing metrics-server

The canonical install is a single manifest from the upstream project:

kubectl apply -f https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml

On many exam-style clusters (self-signed kubelet certificates), the metrics-server Pod will start but stay not ready, because it can’t verify the kubelet’s TLS certificate. The standard fix is to tell it to skip that verification by adding one arg to the Deployment:

kubectl -n kube-system edit deployment metrics-server
    spec:
      containers:
      - args:
        - --cert-dir=/tmp
        - --secure-port=10250
        - --kubelet-insecure-tls          # add this line
        - --kubelet-preferred-address-types=InternalIP

Give it 30–60 seconds, then verify the API is live:

kubectl get deployment metrics-server -n kube-system
kubectl top nodes     # should now return numbers, not an error

You don’t need to memorize the whole manifest — you need to recognize the symptom (top fails, metrics-server not ready) and know the one arg that fixes the most common cause.

Reading Resource Usage with kubectl top

Once metrics-server is healthy, kubectl top is trivial — but the exam tests whether you can sort and filter to answer a specific question, not just dump numbers.

# Node-level pressure
kubectl top nodes

# Every pod in a namespace
kubectl top pods -n kube-system

# Per-container breakdown inside multi-container pods
kubectl top pods --containers -n kube-system

# Across all namespaces
kubectl top pods -A

# Sort to find the greediest consumer
kubectl top pods -A --sort-by=cpu
kubectl top pods -A --sort-by=memory

A classic task: “Find the Pod consuming the most CPU in the cluster and write its name to a file.” The answer is one piped command:

kubectl top pods -A --sort-by=cpu --no-headers | head -1 > /opt/greedy-pod.txt

Note the units. CPU is reported in millicores (250m = a quarter of a core); memory in mebibytes (Mi). These are the same units you write in resources.requests and resources.limits, so top output lets you sanity-check whether a Pod is near its limit — the usual precursor to an OOMKill or CPU throttling. When a container is OOMKilled, its usage was pushed against the memory limit; kubectl top plus the limit in the Pod spec is how you confirm it.

Container Logs: kubectl logs and Its Flags

Application-level observability is kubectl logs. Every container’s stdout and stderr are captured by the container runtime and surfaced here — that’s the whole point of the “manage container stdout and stderr logs” objective. The base command is simple; the flags win points.

# Basic
kubectl logs <pod>

# A specific container in a multi-container Pod (required, or you get an error)
kubectl logs <pod> -c <container>

# The PREVIOUS container instance — essential for CrashLoopBackOff
kubectl logs <pod> --previous
kubectl logs <pod> -p

# Follow live, like tail -f
kubectl logs <pod> -f

# Only the last N lines
kubectl logs <pod> --tail=50

# Only the last time window
kubectl logs <pod> --since=10m
kubectl logs <pod> --since=1h

# Timestamps on every line
kubectl logs <pod> --timestamps

# All containers at once
kubectl logs <pod> --all-containers=true

# Logs from every Pod behind a label
kubectl logs -l app=nginx --tail=20

The single most valuable flag on the exam is --previous (-p). When a Pod is in CrashLoopBackOff, the current container may have just restarted and printed nothing useful; the crash reason lives in the previous, dead instance. If you run kubectl logs without -p on a crash-looping Pod and see an empty or misleading result, that’s your cue to add --previous. Forgetting this flag is one of the most common ways candidates fail a troubleshooting task that they otherwise understand.

For multi-container Pods, kubectl logs <pod> alone errors with a container name must be specified. Add -c <container>, or --all-containers if you want everything. This ties directly into multi-container patterns where a sidecar’s logs, not the main container’s, hold the answer.

Where Logs Actually Live on the Node

kubectl logs works only while the API server, kubelet, and container runtime are healthy. When the problem is below Kubernetes — a broken kubelet, a node that won’t join, a container runtime that’s down — you have to read logs on the node directly. The exam’s node-troubleshooting tasks assume you can SSH to a node and find them.

Container logs on the node live under:

/var/log/pods/<namespace>_<pod>_<uid>/<container>/*.log
/var/log/containers/*.log        # symlinks to the above

You can read them with cat or crictl even when the API is unreachable:

crictl ps                        # list running containers (runtime-level)
crictl logs <container-id>       # logs without going through kubectl

crictl is the runtime-level equivalent of kubectl/docker and is invaluable when a Pod never becomes visible to the API server.

Cluster Component Logs: Static Pods vs systemd

This is the part that trips people up, because where the control-plane logs live depends on how the components run. There are two worlds:

1. kubeadm clusters — control plane runs as static Pods. On a kubeadm-built cluster, kube-apiserver, kube-controller-manager, kube-scheduler, and etcd run as static Pods managed by the kubelet from manifests in /etc/kubernetes/manifests/. Because they’re Pods, you read their logs with kubectl (when the API server itself is up):

kubectl logs -n kube-system kube-apiserver-<node>
kubectl logs -n kube-system kube-scheduler-<node>
kubectl logs -n kube-system kube-controller-manager-<node>
kubectl logs -n kube-system etcd-<node>

But if the API server itself is down, kubectl can’t help — so you fall back to the on-node static-Pod logs:

sudo crictl ps -a | grep apiserver
sudo crictl logs <apiserver-container-id>
# or the raw files:
sudo cat /var/log/pods/kube-system_kube-apiserver-*/kube-apiserver/*.log

Editing a control-plane static Pod is also done on-node by changing the manifest under /etc/kubernetes/manifests/ — the kubelet restarts the Pod automatically. This is the same mechanism you rely on during a cluster upgrade and an etcd backup/restore.

2. The kubelet — always a systemd service. The kubelet does not run as a Pod; it’s a host process managed by systemd. Its logs come from journalctl, and this is the first place to look when a node is NotReady:

sudo systemctl status kubelet
sudo journalctl -u kubelet          # full kubelet log
sudo journalctl -u kubelet -f       # follow live
sudo journalctl -u kubelet --since "10 min ago"

The container runtime is the same story — a systemd unit:

sudo journalctl -u containerd

Commit this split to memory: control-plane components → static Pods → kubectl logs -n kube-system (or crictl//var/log/pods if the API is down); kubelet and runtime → systemd → journalctl -u. A NotReady node almost always means “check journalctl -u kubelet,” while a scheduling anomaly means “check the scheduler Pod’s logs.”

Events: The Timeline You Keep Forgetting

Events are the cheapest observability signal in Kubernetes and the most under-used. They record what the control plane did — scheduling decisions, image pulls, probe failures, evictions, OOMKills — as a time-ordered stream.

# Everything, newest-relevant first
kubectl get events -A --sort-by=.lastTimestamp

# Scoped to one namespace, only warnings
kubectl get events -n default --field-selector type=Warning

# The events for one object, inline
kubectl describe pod <pod> | sed -n '/Events/,$p'

--sort-by=.lastTimestamp matters because raw kubectl get events output is unordered and nearly useless under time pressure. When a Pod won’t schedule, its Events almost always name the reason directly — Insufficient cpu, node(s) had taint, FailedScheduling, Back-off pulling image. Reading Events before diving into logs often saves several minutes. This connects straight into the taints, tolerations, and affinity rules covered in the workloads and scheduling guide.

A Symptom → First Command Cheat Sheet

Under exam pressure you want a reflex, not a decision tree. Memorize this mapping:

SymptomFirst command
kubectl top returns “Metrics API not available”Install/repair metrics-server
Need the top CPU/memory consumerkubectl top pods -A --sort-by=cpu
Pod in CrashLoopBackOff, empty logskubectl logs <pod> --previous
”a container name must be specified”add -c <container>
Pod stuck Pendingkubectl describe pod → read Events
Node NotReadysudo journalctl -u kubelet
API server unreachablecrictl ps -a + crictl logs on control-plane node
Scheduler not placing Podskubectl logs -n kube-system kube-scheduler-<node>
Intermittent cluster-wide odditieskubectl get events -A --sort-by=.lastTimestamp

Keep this beside the broader CKA kubectl cheat sheet while you practice.

How to Practice This Efficiently

Reading these commands isn’t the same as producing them cold in a terminal against the clock. Build a two-node cluster (kubeadm, kind, or minikube) and run these drills:

  1. Break top on purpose. Delete the metrics-server Deployment, confirm kubectl top nodes fails, then reinstall and repair it. Do it until the --kubelet-insecure-tls fix is automatic.
  2. Force a crash loop. Deploy a Pod with a command that exits non-zero, then retrieve the real error with kubectl logs --previous.
  3. Kill the kubelet. systemctl stop kubelet on a worker, watch the node go NotReady, diagnose it purely from journalctl -u kubelet, then recover.
  4. Find the greedy pod. Deploy a CPU-burner and locate it with a single kubectl top --sort-by command piped to a file.
  5. Read the scheduler. Add a taint with no matching toleration, watch a Pod stay Pending, and confirm the reason from both kubectl describe events and the scheduler Pod logs.

For the full breakdown of how each domain is weighted — so you spend the most time where the most points are — start with the CKA exam domains breakdown, and get the environment ready with the Kubernetes lab setup guide.

When you want these reps under realistic exam conditions — a browser-based terminal, a live multi-node cluster, timed and scored scenarios — the Sailor.sh CKA Certification Ready Mock Exam Bundle runs five full performance labs that include monitoring and log-hunting tasks, each with a detailed explanation of the accepted approach. It’s built as hands-on practice rather than a question dump, so you finish knowing you can find a problem, not just recognize its name. Warm up for free first with the free CKA practice guide and the free CKA practice questions.

Frequently Asked Questions

Is metrics-server installed by default on the CKA exam cluster?

Don’t assume so. Several troubleshooting tasks specifically require you to install or repair it, and kubectl top will fail until it’s healthy. Know the one-line apply command and the --kubelet-insecure-tls fix for self-signed kubelet certs.

What’s the difference between kubectl top and kubectl describe for resources?

kubectl top shows live usage from metrics-server. kubectl describe node shows requests and limits (allocations and capacity), not real-time consumption. You need both: describe tells you what’s reserved, top tells you what’s actually used.

Why does kubectl logs sometimes show nothing for a crashing Pod?

Because it reads the current container instance, which may have just restarted. The crash output is in the previous, terminated instance — retrieve it with kubectl logs <pod> --previous (or -p). This is the most common logging mistake candidates make.

Where do I find control-plane logs if the API server is down?

On a kubeadm cluster the control plane runs as static Pods, so when the API server is unreachable you read them on-node with crictl logs or directly from /var/log/pods/. The kubelet, which manages those static Pods, is always readable via sudo journalctl -u kubelet.

Do I need Prometheus or Grafana for the CKA?

No. The CKA tests observability with in-cluster, native tooling only — metrics-server, kubectl top, kubectl logs, kubectl get events, and node-level logs. Third-party monitoring stacks are out of scope for this exam.

How much of the exam is monitoring and logging?

There’s no fixed percentage, but monitoring and log management are explicit objectives inside the 30% Troubleshooting domain — the largest on the exam. Combined with node and control-plane troubleshooting, log-reading skills are involved in a meaningful share of the tasks you’ll face.

Putting It Together

Observability is the diagnostic layer that makes every other troubleshooting skill faster. kubectl top (backed by metrics-server) tells you what’s under pressure; kubectl logs tells you what a container thinks is wrong; component logs and journalctl tell you what the platform is doing; and Events give you the timeline. Learn to reach for the right one on reflex and you’ll cut minutes off every troubleshooting task — minutes that add up across the 30% domain. From here, move into the failure-mode drills in the CKA troubleshooting guide and the recovery workflows in the etcd backup and restore guide to complete your command of the exam’s biggest section.

Limited Time Offer: Get 80% off all Mock Exam Bundles | Sale ends in 7 days. Start learning today.

Claim Now