Sign in
← Kubernetes: observability
7 min · medium · Lesson 1 of 3

kubectl logs and the multi-container Pod

Where kubectl gets logs from, which flags people actually use, and why --previous sometimes returns nothing.

Why this matters

A Pod crashed, restarted and is running again, but monitoring only shows a restart counter. You can almost always see why it crashed in the logs: the application had time to write an error before exiting. You need to know where kubectl logs gets them from, which container it shows by default, and how to pull the output of the previous run.

How Kubernetes collects logs

container stdout, stderr writes runtime 0.log on the node reads kubelet serves via the API serves kubectl logs what you see
kubectl logs shows the file on the node, not a live stream from the container.

A container writes to stdout and stderr. The container runtime (containerd or CRI-O) intercepts both streams and writes them to a file on the node: /var/log/pods/<namespace>_<pod>_<uid>/<container>/0.log. Kubelet reads this file. kubectl logs sends a request to the API server (GET /api/v1/namespaces/<ns>/pods/<pod>/log), the API server forwards it to kubelet on the right node, and kubelet returns the file's contents.

Two things follow from this.

First: if the application writes its log to a file inside the container, kubectl logs won't see it. The log has to go to stdout or stderr. That's how the nginx image works, for example: in it, /var/log/nginx/access.log is a symlink to /dev/stdout.

Second: the file on the node gets rotated. By default kubelet starts a new file after 10 MiB (containerLogMaxSize) and keeps up to 5 files per container (containerLogMaxFiles). kubectl logs only returns the latest file, so at most 10 MiB. For long-term storage, people run an external collector (Loki, Elasticsearch, Fluent Bit), which is a topic for separate lessons.

kubectl logs: the main flags

Basic command:

kubectl logs <pod>

Instead of a Pod name you can give a Deployment: kubectl logs deploy/web. kubectl will pick one of its Pods.

Useful flags:

kubectl logs <pod> --tail=50 --timestamps
kubectl logs <pod> -c <container> --previous
kubectl logs -l app=web --tail=20 --prefix

The multi-container Pod

A Pod can hold several containers. They share the network and volumes, but each has its own stdout, and its own log in a separate file.

Pod my-pod
 ├─ app      own stdout   -c app
 └─ sidecar  own stdout   -c sidecar

Standard patterns:

If you don't give -c, kubectl doesn't error out. It picks a default container: the one named in the Pod annotation kubectl.kubernetes.io/default-container, or without it, the first one in the containers list. It prints one line about this to stderr:

Defaulted container "report" out of: report, log-shipper

This line is easy to miss. Then you're reading the sidecar's log and not finding the application's error in it. That's why in a multi-container Pod it's better to name the container explicitly:

kubectl logs my-pod -c app
kubectl logs my-pod -c sidecar

Everything from every container in the Pod at once, including init containers, comes from --all-containers:

kubectl logs my-pod --all-containers --prefix

--prefix adds a source tag to every line, like [pod/my-pod/app]. Without it, lines from different containers get mixed together.

--previous and why you need it

When a container crashes, kubelet starts it again in the same Pod and writes the new run's log to a new file (0.log, then 1.log, and so on). A plain kubectl logs shows the current run. The error the container crashed with is left in the previous file, and --previous pulls it out:

kubectl logs my-pod --previous
kubectl logs my-pod -c app --previous

Limits:

How many times a container has restarted shows up in the RESTARTS column of kubectl get pods, and per container in kubectl describe pod (the Restart Count field and the Last State block with the exit code).

Common mistakes

What you'll need for the tasks

Homework

Practice the theory on your own cluster: 2 steps with a check. Set up the cluster with the Kubernetes locally track, the tasks live in the k8s-practice repository.

./run.sh start k8s-logging     # set up the starting state
./run.sh verify k8s-logging    # check the current step

In short

Done reading?

Mark the lesson as read to move your track progress forward.

Go through it with an AI agent

The agent explains anything unclear in plain words, gives you 2 labs for this lesson and drills you on interview questions. $49 one-time, lifetime access.

Get access for $49

Tell the agent: use MCP izi, give me lesson k8s-observability-01-logs