Right, so you’ve got a pod running. Maybe it’s a beautiful, elegant piece of software. Or maybe it’s a burning dumpster fire of 500 errors. Either way, your first move is almost always kubectl logs. It’s the debugging equivalent of a trusty flashlight. But like any good tool, it has its quirks, and if your pod has more than one container, it gets a little… opinionated.

Let’s say you run a simple:

kubectl logs my-pod

If my-pod has only one container, this works perfectly. Kubernetes hands you the logs and you go about your day. But the moment you have a multi-container pod—a sidecar for logging, a helper for secrets, you name it—Kubernetes throws its hands up in the air and says, “I can’t read your mind, pal!” You’ll be greeted with this masterpiece of passive-aggressive error messaging:

error: a container name must be specified for pod my-pod, choose one of: [web-app nginx-proxy]

It’s not wrong, but it’s deeply unhelpful by default. The designers decided that blindly grabbing logs from the first alphabetically-sorted container was a path to madness, so they force you to be explicit. Annoying? Sometimes. The right call? Absolutely.

Specifying the Container

This is the bread and butter. When your pod has multiple containers, you must tell kubectl which one you want to peer into using the -c or --container flag.

kubectl logs my-pod -c web-app
kubectl logs my-pod -c nginx-proxy

Think of it like a house with multiple roommates. You can’t just yell “Who left the milk out?” into the void; you have to ask the specific suspect. The -c flag is you knocking on the right door.

The –previous Flag: For When Things Have Already Gone Horribly Wrong

Here’s a classic pitfall. Your pod is in a CrashLoopBackOff. It starts, crashes, starts again, and crashes. You try to get its logs:

kubectl logs my-pod -c web-app

And you get… nothing. Or worse, logs from the current attempt that died so fast it barely had time to say “hello.” This is where --previous saves the day. It grabs the logs from the last instance of the container before it terminated.

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

This flag is a lifesaver. It’s the Kubernetes equivalent of checking the security footage to see what happened before the explosion. The rough edge here is that this only works if the node hasn’t garbage collected the dead container yet. If the pod crashed a week ago, those logs are long gone. It’s a window into the immediate past, not a permanent archive.

Following Logs in Real-Time (-f)

When you’re actively debugging, you want to watch the logs stream in, like a high-stakes episode of your application’s life. The -f or --follow flag does exactly that. It works exactly like tail -f.

kubectl logs my-pod -c web-app -f

Combine it with --previous if you’re watching a restarted pod and want to see what the new instance does. Pro tip: kubectl logs -f will eventually time out on you if there’s no activity. It’s a long timeout, but it’s there. Don’t assume it’s a forever-running connection.

Using Labels Selectors: Because You’re Not a Caveman

You are not memorizing pod names. You’re a professional. You use labels. The -l flag is your best friend for getting logs from a pod that’s part of a deployment, especially when it gets recreated with a new random name.

kubectl logs -l app=my-glorious-app -c web-app --prefix

Notice the --prefix flag? That’s a pro move. It prepends the pod name to each log line. When you’re watching logs from multiple pods (which you can do by omitting the container flag if all pods have a container of the same name), this is essential to untangle which line came from where.

kubectl logs -l app=my-glorious-app --prefix -f

Output looks like:

[pod/my-app-pod-abcde] 127.0.0.1 - - [15/May/2024:13:37:04 +0000] "GET / HTTP/1.1" 200 1234
[pod/my-app-pod-vwxyz] 127.0.0.1 - - [15/May/2024:13:37:05 +0000] "GET / HTTP/1.1" 200 5678

The Rough Edges and Best Practices

Let’s be direct: kubectl logs is fantastic for quick, interactive debugging, but it is not a long-term logging solution. It pulls from the container runtime’s ephemeral log storage on the node, which is usually just a set of JSON files that get rotated out. If a node dies, those logs die with it. If a pod gets evicted and rescheduled on another node, the old logs are gone.

This is why the first thing you do in any real cluster is install a proper log shipping system like Loki, Elasticsearch, or Datadog. They scrape logs from all pods and containers all the time, index them, and make them searchable. kubectl logs is for when you’re putting out a fire. A centralized logging system is the fire alarm and sprinkler combo you install so you have fewer fires to fight.

So use kubectl logs for what it is: a brilliant, immediate, and indispensable tool for real-time troubleshooting. But never, ever rely on it as your system of record.