Logs, events and container output streams

Where a container's output goes, how to read exactly the lines you need, how to show a log file, and how events help.

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

  • Read the logs of any container: one named container, the run before a crash, or every Pod with a label.
  • Find a container's log file on its node.
  • Add a native sidecar that prints an app's log file to stdout, without changing the app container.
  • Sort and filter events, and you know when to use describe and when to use get events.

This exam skill is called Manage and evaluate output streams. The tasks are small and exact. Save one container's error lines to a file. Find the that crashed with a given message. Make an app's log file readable with kubectl logs.

A container's log is everything its app prints. A program prints to two output streams: stdout for normal output and stderr for errors. The saves both streams into one file on the . kubectl logs reads that file back for you.

Where a container's log goes

Your app

prints to stdout and stderr

Container runtime

saves both streams to one file

Log file on the node

/​var/​log/​pods/​…

kubectl logs

asks the kubelet to read the file

A file the app writes inside its own container is not on this path, so kubectl logs never sees it.

Reading logs with kubectl logs

kubectl logs, every option you will use
kubectl -n shop logs web-7d9c                      # the default container (see the trap below)
kubectl -n shop logs web-7d9c -c sidecar           # one named container (init containers too)
kubectl -n shop logs web-7d9c --all-containers     # every container, init containers included
kubectl -n shop logs web-7d9c --previous           # the instance before the current one (-p)
kubectl -n shop logs web-7d9c -f                   # follow; Ctrl-C to stop
kubectl -n shop logs web-7d9c --since=10m          # only recent lines (also --since-time=2026-10-17T09:00:00Z)
kubectl -n shop logs web-7d9c --tail=50            # last 50 lines
kubectl -n shop logs web-7d9c --timestamps         # prefix each line with the runtime's RFC3339 timestamp
kubectl -n shop logs -l app=web --prefix           # every Pod with the label; lines start [pod/<name>/<container>]
kubectl -n shop logs deploy/web                    # one Pod picked from the Deployment

# The typical exam shape: one container, one pattern, into a file
kubectl -n shop logs web-7d9c -c app | grep 'ERROR' > /tmp/cka/web-errors.txt
  • Name the container. In a Pod with several containers, kubectl logs without -c picks a default. That is the one named in the kubectl.kubernetes.io/default-container annotation, or else the first. It prints Defaulted container "app" out of: …. Always pass -c when the question names a container.
  • Labels cut the output. With -l, you get only the last 10 lines of each Pod. Add --tail=-1 when you need the full log.
  • The output is the answer. When you write a file the grader compares, do not add --timestamps or --prefix. You also do not need 2>&1: stderr lines are already in the container log.

Which run do you see after a crash?

When a container crashes, the starts it again. That is a new run, with a new log. The kubelet keeps the current run and normally one run before it.

Two runs of one container

Run 1: crashed

the kubelet keeps its log

kubectl logs POD --previous

Run 2: running now

started by the restart

kubectl logs POD

Once the container is Running again, the crash output is only in --previous.

The container…Where the crash output is
Crashed and is waiting to restart (CrashLoopBackOff)Plain kubectl logs shows the run that just died.
Crashed, restarted, and is Running againOnly in kubectl logs --previous. Plain logs show the fresh run.
Never restartedThere is no crash. --previous answers previous terminated container not found.

If --previous answers unable to retrieve container logs, the old run is already gone. When you are unsure, run both commands. All of these logs disappear when the Pod is deleted.

Where the logs live on the node

The log files sit on the node that runs the Pod. Each container has a folder: /var/log/pods/<namespace>_<pod>_<pod-uid>/<container>/. The file name is the restart count: 0.log for the first run, 1.log after one restart. /var/log/containers/ holds shortcuts (symlinks) to the same files.

On the node (exam: ssh <node>; lab: docker exec -it cka-worker bash)
kubectl -n shop get pod web-7d9c -o wide          # which node?
docker exec -it cka-worker bash

ls /var/log/pods/ | grep web-7d9c
tail -n 3 /var/log/pods/shop_web-7d9c_*/app/0.log
# 2026-10-17T10:35:46.709286291Z stderr F connection reset by peer
ls -l /var/log/containers/ | grep web-7d9c

When the is down, kubectl logs cannot work, but crictl logs on the node still can. Control plane failures shows how.

When the app writes to a file

Some apps write their log to a file instead of stdout. Then kubectl logs shows nothing. The fix is a helper container that reads the file and prints it to its own stdout.

The right helper is a native : an with restartPolicy: Always, which runs for the Pod's whole life. Pods, init containers and sidecars teaches it. Below is the block you add, for a Pod report whose app writes /data/report.log to a shared volume named data.

The sidecar block you add to the Pod
spec:
  initContainers:                      # add this list, beside containers
    - name: log-tail
      image: busybox:1.36
      restartPolicy: Always            # this line makes it a sidecar
      command: ["sh", "-c", "tail -n +1 -F /data/report.log"]
      volumeMounts:
        - name: data                   # the volume the app writes to
          mountPath: /data

You cannot add a container to a running Pod. So you rebuild the Pod:

  1. 1.Export it: kubectl -n shop get pod report -o yaml > report.yaml.
  2. 2.Add the initContainers block to the file.
  3. 3.Replace it: kubectl replace --force -f report.yaml deletes the Pod and creates it again, with the same name.
  4. 4.Check it: kubectl -n shop logs report -c log-tail shows the app's log.

For a , edit its Pod template instead. It then rolls out new Pods by itself.

Events

Events are short notes that Kubernetes writes about what it did and what failed: Scheduled, Pulled, BackOff, FailedScheduling. The , the kubelet and the controllers write them. There are two ways to read them:

CommandWhat it showsUse it when
kubectl describe pod web-7d9cThe events of that one object, at the bottom of the outputYou know which object is broken
kubectl get eventsEvery event in the , also for objects that are gone or that you did not describeYou do not know yet. Example: a 's FailedCreate when a quota blocks its Pods
  • Events expire after one hour by default. For an older problem, read the logs instead.
  • kubectl get events is not sorted by time. Add --sort-by=.metadata.creationTimestamp, or use kubectl events, which sorts by itself.
Events, sorted, filtered and watched
kubectl -n shop get events --sort-by=.metadata.creationTimestamp
kubectl -n shop get events --field-selector type=Warning
kubectl -n shop get events --field-selector involvedObject.kind=Pod,involvedObject.name=web-7d9c
kubectl -n shop get events -w                       # stream new events while you fix things
kubectl get events -A --sort-by=.metadata.creationTimestamp | tail -20
kubectl -n shop events --for pod/web-7d9c --types=Warning   # kubectl events sorts by time itself

kubectl describe pod also shows the exit code of the last crash, under Last State. Application failures explains what each exit code means.

In the official docs· open on exam day too

Hands-on task 1 of 3ts-logs-1
~8 min6% weightTroubleshooting

Stream a log file with a native sidecar

Pod ledger in namespace tsx-logs writes its log to /var/log/ledger/ledger.log, so kubectl logs shows nothing. Add a container named sidecar using image busybox:1.36 that streams that file to its standard output for the whole life of the Pod, so that kubectl -n tsx-logs logs ledger -c sidecar shows the ledger entries. Implement it as a native sidecar container. The Pod must keep the name ledger, and the container app must stay unchanged.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

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

Extract one container's error lines

Pod billing in namespace tsx-grep runs two containers. Write every log line of the container worker that contains the string ERROR to /tmp/cka/billing-errors.txt, one per line, in the order they were logged and exactly as the container printed them.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

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

Find the Pod that crashed with a given error

Some Pods in namespace tsx-crash keep restarting. One of them crashes right after logging connection refused. Write only that Pod's name to /tmp/cka/crashed-pod.txt.

Cluster:kubectl config use-context kind-cka

  1. 1

    Set up the scenario

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

Finished this lesson?

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