GitHub Suggest a change

Inspecting Running Containers

kubectl get pods shows Running. kubectl describe shows a clean startup, no image pull errors, no scheduling failures. But the application is still not doing what you expect. Kubernetes has told you everything it knows about the object from the outside. To go further, you need to look inside the container.

Two commands give you that view. kubectl logs reads what the container wrote to its output. kubectl exec runs a command directly inside the container’s environment. This lesson introduces both and focuses on where each one applies.

Create the Pod you will use throughout:

Terminal window
nano inspect-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: inspect-pod
spec:
containers:
- name: web
image: nginx:1.28
Terminal window
kubectl apply -f inspect-pod.yaml

A quick look at kubectl logs

Kubernetes does not manage log files inside containers. It captures what the container writes to standard output and standard error, and makes that stream available through the API. kubectl logs reads it:

Terminal window
kubectl logs inspect-pod

A freshly started nginx with no incoming traffic produces near-empty output. That silence is informative: the container is alive, but nothing has reached it yet.

Two flags cover most situations. --tail limits output to the last N lines. -f follows the stream live:

Terminal window
kubectl logs inspect-pod --tail=20
Quiz

You run kubectl logs inspect-pod and see no output. What does that most likely mean?

  • The container is not running
  • The container has not written anything to stdout or stderr yet
  • kubectl logs requires a Deployment, not a bare Pod
Reveal answer

The container has not written anything yet. kubectl logs only captures stdout and stderr. An app that logs to a file, or a server waiting for its first request, produces no output here.

That covers the essentials. kubectl logs has more depth, including how to debug CrashLoopBackOff with --previous and how to target individual containers with -c. All of that is in the Logging and Monitoring module, where it belongs.

Running commands inside a container with kubectl exec

Logs show what the application wrote. They cannot tell you whether a configuration file was mounted at the right path, which environment variables were actually injected, or whether a binary the app depends on exists in the image. For those questions, you run a command inside the container directly.

Your terminalkubectl exec API server kubeleton the node Container(nginx)
Your terminalkubectl exec API server kubeleton the node Container(nginx)

kubectl exec opens a connection from your terminal to the API server, which forwards it to the kubelet on the node hosting the Pod. The kubelet runs the command inside the container’s own process namespace and filesystem. You see the result as if you had typed the command inside the container itself.

The syntax always separates the kubectl arguments from the container command with --:

Terminal window
kubectl exec inspect-pod -- ls

The -- is not optional. Without it, kubectl tries to interpret every word after the Pod name as its own flags, which produces confusing errors.

Quiz

Why is the -- required in kubectl exec inspect-pod -- ls?

Reveal answer

kubectl needs to know where its own arguments end and the container command begins. Without --, kubectl tries to parse ls as a kubectl flag, which fails. The separator makes the boundary explicit.

Checking environment variables

A more useful target than listing files is reading the container’s environment. ConfigMaps mounted as env vars, Service discovery variables, and any values from your Pod spec all appear here:

Terminal window
kubectl exec inspect-pod -- env

Look at the output. You will see standard variables like PATH and HOSTNAME. You will also see KUBERNETES_SERVICE_HOST and KUBERNETES_PORT, which Kubernetes injects into every Pod automatically. This is the actual environment your application runs in, not the one you wrote in the manifest.

Not every container image ships with a shell or common utilities. Minimal images, particularly distroless ones, may not have ls, cat, or env. If kubectl exec pod -- ls fails with executable file not found, the image does not include that binary. The Observability and Troubleshooting module covers kubectl debug, which attaches a separate debug container with a full toolset to those minimal images.

Targeting a specific container

A Pod can run more than one container. When it does, kubectl exec needs to know which one to target. Use -c with the container name:

Terminal window
kubectl exec inspect-pod -c web -- env

Without -c, kubectl defaults to the first container in the Pod spec. On a single-container Pod this is fine. On a multi-container Pod, always name the container explicitly to avoid reading from the wrong context.

Quiz

You have a Pod with two containers named app and sidecar. You run kubectl exec my-pod -- ls and get an unexpected filesystem layout. What is the likely cause?

  • The Pod is not running
  • kubectl exec defaulted to the first container, which may not be app
  • The -- separator is missing
Reveal answer

kubectl defaulted to the first container in the spec. If sidecar is listed first, you inspected sidecar rather than app. Use -c app to be explicit.

The debugging funnel

something is wrong container is failing need to inspect internals kubectl get podsStatus, READY, RESTARTS at a glance kubectl describe pod NAMEEvents, conditions, full spec kubectl logs NAMEWhat the container printed kubectl exec NAME — commandWhat the container contains
something is wrong container is failing need to inspect internals kubectl get podsStatus, READY, RESTARTS at a glance kubectl describe pod NAMEEvents, conditions, full spec kubectl logs NAMEWhat the container printed kubectl exec NAME — commandWhat the container contains

Each step in this sequence costs more than the last. kubectl get covers every Pod in the namespace in milliseconds. kubectl exec opens a live connection to a running process. Starting broad and narrowing down means you spend the minimum effort needed to find the root cause. Save kubectl exec for the cases where logs and describe have not given you enough.

Clean up before the next lesson:

Terminal window
kubectl delete pod inspect-pod

You now have four levels of observation: cluster-wide status with get, object history with describe, application output with logs, and direct internal inspection with exec. The next lesson covers how to create and edit resources efficiently, including how to modify live objects without deleting them.

Get hands-on with Kubernetes

Upgrade to Pro to unlock the terminal (free during early access)

Contact us