kubectl logs, Events and describe with Examples

Use kubectl get, describe, events, and logs to inspect Pod status, warning events, multi-container output, previous logs, and container restart failures.

Published

Updated

Read time 17 min read

Reviewed byDeepak Prasad

kubectl logs describe and events commands for inspecting Kubernetes Pod status and container output
Tested on Rocky Linux 10.2 (Red Quartz) workstation
Package kubectl 1.36.3
Applies to Bash-compatible Linux or macOS shell with kubectl configured; any compatible Kubernetes cluster
Cert prep CKA · CKAD · CKS
Lab environment Multi-node kubeadm cluster with containerd — install Kubernetes with kubeadm
Privilege Normal user (no sudo required on the workstation)
Scope kubectl get for quick status, kubectl describe for conditions and inline events, kubectl events and kubectl get events for warnings and sorting, kubectl logs for single and multi-container Pods, tail, since, follow, and previous instance output. Does not cover full Pod troubleshooting workflows, kubectl exec, ephemeral debug containers, node debugging, kubectl top, centralized logging, audit logs, or log retention configuration.
Related guides kubectl apply, edit, patch and replace

When a Deployment misbehaves, I start with a quick status check, then drill into conditions, events, and container output. This chapter uses stable nginx plus a second regular container named logger that deliberately exits after printing two lines. The walkthrough follows that inspection order on one failing multi-container web Deployment in the logs-lab namespace.

If kubectl basics are new, read kubectl command examples first. This page focuses on inspection commands, not a full Pod troubleshooting decision tree.


Prepare the Logs and Events Lab

Create the logs-lab namespace and a two-replica web Deployment. Container nginx stays up; the second regular container logger prints two lines and exits so you get restarts, warning events, and logger container logs to inspect.

bash
kubectl apply -f - <<'YAML'
apiVersion: v1
kind: Namespace
metadata:
  name: logs-lab
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: web
  namespace: logs-lab
  labels:
    app: web
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
        - name: nginx
          image: nginx:1.27.0
          ports:
            - containerPort: 80
        - name: logger
          image: busybox:1.36
          command:
            - sh
            - -c
            - echo logger-start; sleep 20; echo logger-crash; exit 1
          readinessProbe:
            exec:
              command:
                - "true"
            initialDelaySeconds: 30
            periodSeconds: 5
---
apiVersion: v1
kind: Service
metadata:
  name: web
  namespace: logs-lab
spec:
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 80
YAML

The logger readiness delay is longer than its runtime, so it never becomes Ready before crashing. This keeps the Deployment availability and Service endpoint examples deterministic. Service readiness is represented through EndpointSlice endpoint conditions.

Wait until both logger containers reach CrashLoopBackOff:

bash
kubectl wait pod \
  -n logs-lab \
  -l app=web \
  --for='jsonpath={.status.containerStatuses[?(@.name=="logger")].state.waiting.reason}=CrashLoopBackOff' \
  --timeout=120s

Then confirm Pod status:

bash
kubectl get pods -n logs-lab

Sample output:

output
NAME                   READY   STATUS             RESTARTS   AGE
web-xxxxxxxxxx-aaaaa   1/2     CrashLoopBackOff   1          25s
web-xxxxxxxxxx-bbbbb   1/2     CrashLoopBackOff   1          25s

STATUS can briefly show Running or Error between restart attempts. CrashLoopBackOff is the stable state to target for the later examples. kubectl wait waits for the requested JSONPath value on every selected Pod.

Store one Pod name for the examples below:

bash
POD=$(kubectl get pods -n logs-lab -l app=web -o jsonpath='{.items[0].metadata.name}')

The variable POD is reused in later sections.


Start with kubectl get

kubectl get answers what exists and what state it is in right now. I use it before describe or logs so I know which Pod name, node, and restart count to target.

Check Pod status and restarts

List Pods in the lab namespace:

bash
kubectl get pods -n logs-lab

Sample output:

output
NAME                   READY   STATUS             RESTARTS   AGE
web-xxxxxxxxxx-aaaaa   1/2     CrashLoopBackOff   1          25s
web-xxxxxxxxxx-bbbbb   1/2     CrashLoopBackOff   1          25s

READY shows 1/2 because nginx is running while the second regular container logger is failing. A Pod must have every regular container Ready before the Pod Ready condition becomes true, which is why one failing companion container makes the entire Pod NotReady. RESTARTS on the logger container is the first signal that logs and events deserve a closer look.

Watch status changes during a rollout or restart storm with --watch:

bash
kubectl get pods -n logs-lab --watch

The command keeps printing rows until you press Ctrl+C. I use it when I expect STATUS or RESTARTS to change within seconds.

List resources across namespaces when you are unsure where a workload runs:

bash
kubectl get pods --all-namespaces | head -8

Sample output:

output
NAMESPACE            NAME                                       READY   STATUS    RESTARTS       AGE
calico-system        calico-apiserver-f786987bb-bt84s           1/1     Running   0              8h
calico-system        calico-apiserver-f786987bb-x56xr           1/1     Running   0              8h
calico-system        calico-kube-controllers-86bbc9c477-hfxkb   1/1     Running   0              8h
calico-system        calico-node-hc7ph                          1/1     Running   1 (34h ago)    2d4h
calico-system        calico-node-sc7p2                          1/1     Running   0              18h
calico-system        calico-typha-6545b7d97f-htqpt              1/1     Running   10 (19h ago)   2d4h
calico-system        csi-node-driver-54j2p                      2/2     Running   0              18h

Add -n logs-lab when you already know the namespace. Use --all-namespaces when the namespace is unknown.

View node placement and exact fields

Add node placement and Pod IP with -o wide:

bash
kubectl get pods -n logs-lab -o wide

Sample output:

output
NAME                   READY   STATUS             RESTARTS   AGE   IP             NODE       NOMINATED NODE   READINESS GATES
web-xxxxxxxxxx-aaaaa   1/2     CrashLoopBackOff   1          25s   192.168.5.43   worker01   <none>           <none>
web-xxxxxxxxxx-bbbbb   1/2     CrashLoopBackOff   1          25s   192.168.5.34   worker01   <none>           <none>

Both replicas landed on worker01 with distinct Pod IPs. That is enough to confirm scheduling succeeded before you read scheduler events.

Inspect one resource as YAML when you need exact field values:

bash
POD=$(kubectl get pods -n logs-lab -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl get pod "$POD" -n logs-lab -o yaml | head -12

Sample output:

output
apiVersion: v1
kind: Pod
metadata:
  annotations:
    cni.projectcalico.org/containerID: d57f463e83e768964a0b4687e4672422295e8664079c3d2919b82265433d84d0
    cni.projectcalico.org/podIP: 192.168.5.43/32
    cni.projectcalico.org/podIPs: 192.168.5.43/32
  creationTimestamp: "2026-07-26T13:15:59Z"
  generateName: web-85c97ffd56-
  generation: 1
  labels:
    app: web

kubectl get -o yaml prints a detailed serialized representation of the object, including fields that describe omits. Kubectl hides managed fields unless you add --show-managed-fields. Use YAML output when describe does not expose the field you need.

Confirm controller ownership

generateName alone does not prove which controller owns the Pod. Read ownerReferences instead:

bash
kubectl get pod "$POD" \
  -n logs-lab \
  -o jsonpath='owner={.metadata.ownerReferences[0].kind}/{.metadata.ownerReferences[0].name}{"\n"}'

Sample output:

output
owner=ReplicaSet/web-85c97ffd56

The ReplicaSet is controlled by the Deployment. That chain helps when you describe parent objects to see rollout status and selector context.


Inspect Details with kubectl describe

kubectl get prints concise status columns. kubectl describe prints a detailed human-readable summary of important configuration, status, container state, conditions, ownership, and related events. kubectl get -o yaml prints a detailed serialized representation of the object, including fields that describe omits. Kubectl hides managed fields unless you add --show-managed-fields.

I reach for describe when kubectl get shows Error, CrashLoopBackOff, or rising RESTARTS but the column view does not explain why.

Describe the failing Pod

Pick a Pod from the web Deployment:

bash
kubectl describe pod "$POD" -n logs-lab

The top of the report names the node, Pod IP, and owner (ReplicaSet/web-85c97ffd56). Scroll to the container blocks for the fields I read most often:

  • Node — which worker runs the Pod
  • Status and conditions — whether the Pod is admitted and ready
  • Container stateRunning, Waiting, or Terminated per container
  • Last state — exit code and reason from the previous instance
  • Ready — per-container readiness
  • Restart count — how many times the kubelet restarted a container

In this lab, nginx stays Running while logger shows Waiting with reason CrashLoopBackOff and Last State: Terminated with Exit Code: 1.

The Events section ties recent scheduler, controller, and kubelet actions to timestamps. For one object, describe shows related events by default. For multiple resources or prefix matching, event display defaults to false.

bash
kubectl describe pod "$POD" -n logs-lab | grep -A12 '^Events:'

Sample output:

output
Events:
  Type     Reason     Age               From               Message
  ----     ------     ----              ----               -------
  Normal   Scheduled  25s               default-scheduler  Successfully assigned logs-lab/web-85c97ffd56-jfvjs to worker01
  Normal   Pulled     24s               kubelet            spec.containers{nginx}: Container image "nginx:1.27.0" already present on machine and can be accessed by the pod
  Normal   Created    24s               kubelet            spec.containers{nginx}: Container created
  Normal   Started    24s               kubelet            spec.containers{nginx}: Container started
  Warning  BackOff    3s                kubelet            spec.containers{logger}: Back-off restarting failed container logger in pod web-85c97ffd56-jfvjs_logs-lab(9c6ffc1f-4160-4969-804c-e664f4572714)
  Normal   Pulled     22s               kubelet            spec.containers{logger}: Container image "busybox:1.36" already present on machine and can be accessed by the pod
  Normal   Created    22s               kubelet            spec.containers{logger}: Container created
  Normal   Started    22s               kubelet            spec.containers{logger}: Container started

Warning events with reason BackOff mean the kubelet is throttling restarts after repeated failures. Pair that with logger logs, not only nginx logs.

When several Pods share a label, describe them in one pass:

bash
kubectl describe pods -n logs-lab -l app=web | head -8

Sample output:

output
Name:             web-85c97ffd56-gkmwp
Namespace:        logs-lab
Priority:         0
Service Account:  default
Node:             worker01/192.168.56.109
Start Time:       Sun, 26 Jul 2026 18:45:59 +0530
Labels:           app=web
                  pod-template-hash=85c97ffd56

The output concatenates every matching Pod. For a single Pod's events tail, prefer kubectl describe pod <name> or kubectl events --for.

Describe the Deployment, ReplicaSet, and Service

Use the same command shape on parent objects when you need selector, endpoint, or capacity context:

bash
kubectl describe deployment web -n logs-lab | head -20

Sample output:

output
Name:                   web
Namespace:              logs-lab
CreationTimestamp:      Sun, 26 Jul 2026 18:44:42 +0530
Labels:                 app=web
Annotations:            deployment.kubernetes.io/revision: 1
Selector:               app=web
Replicas:               2 desired | 2 updated | 2 total | 0 available | 2 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=web
  Containers:
   nginx:
    Image:        nginx:1.27.0
    Port:         80/TCP
    Host Port:    0/TCP
    Environment:  <none>
    Mounts:       <none>
   logger:

The nginx processes remain running, but each Pod is 1/2 Ready because the second regular container logger is failing. A Pod must have all regular containers Ready before its Pod Ready condition becomes true. Therefore, the Deployment normally reports zero available replicas while both logger containers are in backoff.

bash
RS=$(kubectl get rs -n logs-lab -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl describe rs "$RS" -n logs-lab | head -18

ReplicaSet describe shows how many Pods are running versus desired and repeats the Pod template.

bash
kubectl describe service web -n logs-lab

Expected relevant output:

output
Name:              web
Namespace:         logs-lab
...
Selector:          app=web
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.96.123.45
IPs:               10.96.123.45
Port:              <unset>  80/TCP
TargetPort:        80/TCP
Endpoints:         <none>

Pods that are not Ready are removed from normal Service endpoints unless the Service explicitly publishes unready addresses.

The same kubectl describe TYPE NAME syntax works for Services, PVCs, Nodes, Jobs, and other resources. Use it when events or status point toward that resource layer.


Inspect Kubernetes Events

Events record recent actions and failures reported by Kubernetes components and the kubelet. They answer what the control plane tried to do and whether that step succeeded.

Typical reasons you will see while inspecting workloads:

  • Scheduled, Pulling, Pulled, Created, Started
  • FailedScheduling, FailedMount
  • BackOff, Unhealthy

Filter with kubectl events

kubectl events provides straightforward filtering with --for, --types, and --watch on the tested kubectl version.

bash
kubectl events -n logs-lab

Sample output:

output
LAST SEEN           TYPE      REASON              OBJECT                      MESSAGE
26s                 Normal    ScalingReplicaSet   Deployment/web              Scaled up replica set web-85c97ffd56 from 0 to 2
26s                 Normal    SuccessfulCreate    ReplicaSet/web-85c97ffd56   Created pod: web-85c97ffd56-n4lsh
26s                 Normal    SuccessfulCreate    ReplicaSet/web-85c97ffd56   Created pod: web-85c97ffd56-jfvjs
26s                 Normal    Scheduled           Pod/web-85c97ffd56-jfvjs    Successfully assigned logs-lab/web-85c97ffd56-jfvjs to worker01
26s                 Normal    Scheduled           Pod/web-85c97ffd56-n4lsh    Successfully assigned logs-lab/web-85c97ffd56-n4lsh to worker01

Filter to warnings when you want failures without normal noise:

bash
kubectl events -n logs-lab --types=Warning

Sample output:

output
LAST SEEN   TYPE      REASON    OBJECT                     MESSAGE
12s         Warning   BackOff   Pod/web-85c97ffd56-jfvjs   Back-off restarting failed container logger in pod web-85c97ffd56-jfvjs_logs-lab(9c6ffc1f-4160-4969-804c-e664f4572714)
12s         Warning   BackOff   Pod/web-85c97ffd56-n4lsh   Back-off restarting failed container logger in pod web-85c97ffd56-n4lsh_logs-lab(02ac8bc7-fd47-4337-b08f-959a0731b1bd)

Scope events to one Pod with --for:

bash
kubectl events -n logs-lab --for "pod/$POD"

Sample output:

output
LAST SEEN          TYPE      REASON      OBJECT                     MESSAGE
26s                Normal    Scheduled   Pod/web-85c97ffd56-jfvjs   Successfully assigned logs-lab/web-85c97ffd56-jfvjs to worker01
25s                Normal    Pulled      Pod/web-85c97ffd56-jfvjs   Container image "nginx:1.27.0" already present on machine and can be accessed by the pod
25s                Normal    Created     Pod/web-85c97ffd56-jfvjs   Container created
25s                Normal    Started     Pod/web-85c97ffd56-jfvjs   Container started
12s                Warning   BackOff     Pod/web-85c97ffd56-jfvjs   Back-off restarting failed container logger in pod web-85c97ffd56-jfvjs_logs-lab(9c6ffc1f-4160-4969-804c-e664f4572714)

Watch new events while you reproduce a failure:

bash
kubectl events -n logs-lab --for "pod/$POD" --watch

Press Ctrl+C to stop watching. The stream does not change the Pod.

List events cluster-wide when the namespace is unknown:

bash
kubectl events --all-namespaces | head -6

Sample output:

output
NAMESPACE     LAST SEEN            TYPE      REASON              OBJECT                      MESSAGE
kube-system   60m                  Normal    Killing             Pod/kube-proxy-llr8k        Stopping container kube-proxy
kube-system   60m                  Normal    SuccessfulCreate    DaemonSet/kube-proxy        Created pod: kube-proxy-m2w8v
kube-system   60m                  Normal    Killing             Pod/kube-proxy-v9ccb        Stopping container kube-proxy
kube-system   60m                  Normal    Scheduled           Pod/kube-proxy-m2w8v        Successfully assigned kube-system/kube-proxy-m2w8v to worker01
kube-system   60m                  Normal    SuccessfulCreate    DaemonSet/kube-proxy        Created pod: kube-proxy-gsk9s

Sort and select with kubectl get events

The traditional form still works on every cluster:

bash
kubectl get events -n logs-lab --sort-by=.metadata.creationTimestamp

Sample output:

output
LAST SEEN   TYPE      REASON      OBJECT                     MESSAGE
27s         Normal    Scheduled   pod/web-85c97ffd56-jfvjs   Successfully assigned logs-lab/web-85c97ffd56-jfvjs to worker01
25s         Normal    Pulled      pod/web-85c97ffd56-jfvjs   Container image "nginx:1.27.0" already present on machine and can be accessed by the pod
25s         Normal    Created     pod/web-85c97ffd56-jfvjs   Container created
25s         Normal    Started     pod/web-85c97ffd56-jfvjs   Container started
12s         Warning   BackOff     pod/web-85c97ffd56-jfvjs   Back-off restarting failed container logger in pod web-85c97ffd56-jfvjs_logs-lab(9c6ffc1f-4160-4969-804c-e664f4572714)

This command sorts Event objects by their creation time. Repeated occurrences can be aggregated into an existing Event object, so this is not necessarily the order of each latest occurrence. Use kubectl events when you primarily want the recent-event view. Use kubectl get events --sort-by=.metadata.creationTimestamp when you specifically want Event objects ordered by creation.

Warning events only:

bash
kubectl get events -n logs-lab --field-selector type=Warning

Sample output:

output
LAST SEEN   TYPE      REASON    OBJECT                     MESSAGE
12s         Warning   BackOff   pod/web-85c97ffd56-jfvjs   Back-off restarting failed container logger in pod web-85c97ffd56-jfvjs_logs-lab(9c6ffc1f-4160-4969-804c-e664f4572714)
12s         Warning   BackOff   pod/web-85c97ffd56-n4lsh   Back-off restarting failed container logger in pod web-85c97ffd56-n4lsh_logs-lab(02ac8bc7-fd47-4337-b08f-959a0731b1bd)

Events for one Pod name:

bash
kubectl get events -n logs-lab --field-selector "involvedObject.name=$POD"

When you already know the Pod name, kubectl events --for pod/$POD is usually shorter than assembling field selectors by hand.

Understand event retention

Kubernetes API server events have a default retention period of one hour, but cluster administrators can change --event-ttl. Events are therefore temporary diagnostics, not an audit or long-term logging system. The current kube-apiserver default is 1h0m0s. For long-term retention use a cluster logging or event forwarding solution.


Read Container Logs

kubectl logs reads stdout and stderr the container runtime captured on the node. It does not open the Pod network or run a shell inside the container.

Select the correct container

Basic syntax for a named container:

bash
kubectl logs "$POD" -n logs-lab -c nginx

Sample output:

output
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/

Always pass -c in troubleshooting examples with multiple containers. Otherwise, a client-selected or annotated default container can hide the failure in another container.

List container names before you pick -c:

bash
kubectl get pod "$POD" -n logs-lab -o jsonpath='{.spec.containers[*].name}{"\n"}'

Sample output:

output
nginx logger

Read the failing logger container:

bash
kubectl logs "$POD" -n logs-lab -c logger --tail=5

Sample output:

output
logger-start
logger-crash

That output matches the script: the container prints logger-start, sleeps, prints logger-crash, then exits with code 1.

Read every container in one stream:

bash
kubectl logs "$POD" -n logs-lab --all-containers=true --tail=3

Follow current logs

By the time the opening wait finishes, logger is usually already in CrashLoopBackOff. Wait for the next running instance before you follow logs:

bash
kubectl wait pod "$POD" \
  -n logs-lab \
  --for='jsonpath={.status.containerStatuses[?(@.name=="logger")].state.running.startedAt}' \
  --timeout=120s
bash
kubectl logs -f "$POD" -n logs-lab -c logger

Press Ctrl+C to detach while the container is running. If the container terminates first, the follow command ends. Run the wait and follow pair again for the next instance, or use --previous for the last terminated instance.

Read previous-instance logs

After logger restarts, read the terminated instance:

bash
kubectl logs "$POD" -n logs-lab -c logger --previous

Sample output:

output
logger-start
logger-crash

--previous shows the last terminated instance of that container. It is the first place I look after CrashLoopBackOff or a rising restart count.

It does not recover logs from a Pod that has already been deleted. For exit codes and OOM kills, see OOMKilled and exit code 137. For probe-driven restarts, see Kubernetes health probes.

If the container has never restarted, kubectl returns previous terminated container not found.

Limit by lines, duration, bytes, and time

Display the latest log lines:

bash
kubectl logs "$POD" -n logs-lab -c nginx --tail=2

Sample output:

output
2026/07/26 13:16:02 [notice] 1#1: start worker processes
2026/07/26 13:16:02 [notice] 1#1: start worker process 29

Display logs from a recent period:

bash
kubectl logs "$POD" -n logs-lab -c nginx --since=1h --tail=1

Sample output:

output
2026/07/26 13:16:02 [notice] 1#1: start worker process 29

--since accepts durations such as 10m or 1h. Combine it with --tail when you only need the newest lines inside that window.

Display logs after a specific time:

bash
SINCE_TIME=$(kubectl get pod "$POD" -n logs-lab -o jsonpath='{.metadata.creationTimestamp}')
kubectl logs "$POD" -n logs-lab -c nginx --since-time="$SINCE_TIME" --tail=5

--since-time accepts an RFC3339 timestamp and returns only newer log entries.

Include timestamps:

bash
kubectl logs "$POD" -n logs-lab -c nginx --timestamps --tail=1

Sample output:

output
2026-07-26T18:46:02.122204733+05:30 2026/07/26 13:16:02 [notice] 1#1: start worker process 29

The leading field is the RFC3339 timestamp stored with the container log entry. Use it to correlate log lines with Kubernetes events.

--limit-bytes caps how many bytes kubectl returns from the log stream. I use it on chatty apps when even --tail would download too much data.

Read logs from multiple Pods

A label selector requests logs from all matching Pods, subject to concurrency limits:

bash
kubectl logs -n logs-lab -l app=web -c nginx --tail=1 --prefix

Sample output:

output
[pod/web-xxxxxxxxxx-aaaaa/nginx] 2026/07/26 13:16:02 [notice] 1#1: start worker process 29
[pod/web-xxxxxxxxxx-bbbbb/nginx] 2026/07/26 13:16:02 [notice] 1#1: start worker process 29

Add --prefix when several Pods or containers write at once so each line shows [pod/name/container]. Prefixing is essential when you follow many replicas; without it the lines blur together.

Following many Pods with -f can produce a wall of interleaved lines. I follow one Pod during reproduction, then widen the selector if I need correlation.

Read logs through a workload resource

kubectl resolves Deployments and Jobs to Pods on the backing workload. The two behaviors differ:

bash
kubectl logs deployment/web -n logs-lab -c nginx --tail=2

Sample output:

output
Found 2 pods, using pod/web-85c97ffd56-jfvjs
2026/07/26 13:14:45 [notice] 1#1: start worker processes
2026/07/26 13:14:45 [notice] 1#1: start worker process 29

That workload shortcut chooses one backing Pod.

Read all Pods owned by the Deployment:

bash
kubectl logs deployment/web -n logs-lab -c nginx --all-pods=true --tail=2

--all-pods=true automatically enables prefixes.

For a finished Job:

bash
kubectl create job data-import -n logs-lab --image=busybox:1.36 -- sh -c 'echo import-start; echo done'
bash
kubectl wait --for=condition=complete job/data-import -n logs-lab --timeout=60s
bash
kubectl logs job/data-import -n logs-lab

Sample output:

output
import-start
done

Kubernetes still reads container output from a Pod. The workload shortcut only picks which Pod name to query.


Combine get, describe, Events, and Logs

When web shows 1/2 Ready and climbing restarts, I walk this order:

  1. kubectl get pods -n logs-lab -o wide — confirm names, node, and restart count
  2. kubectl describe pod <name> — read conditions, container last state, and inline events
  3. kubectl events --for pod/<name> --types=Warning or kubectl get events with field selectors — scan warnings without describe noise
  4. kubectl logs <name> -c logger — read the failing container's current output
  5. kubectl logs <name> -c logger --previous — read the instance that exited before the latest restart
  6. kubectl logs -f <name> -c logger — watch new lines while reproducing

On the lab Deployment, step 2 showed CrashLoopBackOff on logger, step 3 showed BackOff warnings, and steps 4–5 printed logger-start and logger-crash. That is enough to know the logger container script exits on purpose rather than an image-pull or scheduling problem.

This sequence is an inspection checklist, not a complete troubleshooting workflow. Kubernetes Pods and Pod lifecycle covers broader Pod failure modes.

Command Best used for
kubectl get Current high-level resource status
kubectl describe Detailed state, conditions, and related events
kubectl events Recent actions and failures with simple --for filtering
kubectl get events Event lists with --sort-by and field selectors
kubectl logs Application output from running containers
kubectl logs --previous Output from the previous terminated container instance

Troubleshoot Common Command Problems

Symptom Likely cause Fix
Logs show the wrong application output A different container was selected or defaulted List container names and pass -c <name> explicitly
previous terminated container not found Container has not restarted yet, or the prior instance log is gone Use current logs first; reproduce the restart if you need --previous output
kubectl logs returns no output Wrong Pod or container, app logs to files only, or container never started Verify name with kubectl get pods; check events for Failed or Waiting; try --previous after a restart
Events are missing Events expired, wrong namespace, or object name mismatch Confirm -n; widen time window by reproducing; use kubectl get events --sort-by=.metadata.creationTimestamp
Logs disappear after Pod deletion Node log files are tied to the Pod UID lifecycle Use centralized logging when you need retention beyond the Pod lifetime
describe shows errors but logs are empty Failure happened before the container started writing Read events for FailedMount, image pull, or probe failures before expecting app logs

What's Next


References


Summary

You practiced the inspection commands I use on every misbehaving workload: kubectl get for a fast health snapshot, kubectl describe for conditions, restart counts, and kubelet events, kubectl events and kubectl get events for warning filters and sorting, and kubectl logs for stdout and stderr from one or many containers.

The lab web Deployment made the multi-container lesson concrete. nginx stayed healthy while the second regular container logger exited after printing two lines, which drove BackOff events and restart loops. Reading only the nginx container logs would have shown startup noise and missed the failing logger container.

Remember that events are short-lived signals, not archival logs, and that kubectl logs only reaches what the node still holds for existing Pods. When containers restart, --previous is often the difference between an empty transcript and the error line you need.


Frequently Asked Questions

1. What is the difference between kubectl describe and kubectl get?

kubectl get prints concise status columns. kubectl describe prints a detailed human-readable summary of important configuration, status, container state, conditions, ownership, and related events. kubectl get -o yaml prints a detailed serialized representation of the object, including fields that describe omits. Kubectl hides managed fields unless you add --show-managed-fields.

2. Should I use kubectl events or kubectl get events?

Both list cluster events. kubectl events provides straightforward filtering with --for, --types, and --watch on the tested kubectl version. kubectl get events remains common on older clusters and works well with --sort-by and field selectors.

3. How do I view logs from a multi-container Pod?

List container names with kubectl get pod name -o jsonpath, then pass -c container-name or use --all-containers=true. Add --prefix when several Pods or containers write at once so each line shows its source.

4. When does kubectl logs --previous work?

It returns logs from the last terminated instance of the chosen container. Use it after a restart or CrashLoopBackOff. It does not recover logs after the Pod object is deleted.

5. Why does kubectl logs show no output?

Confirm the Pod and container name, check whether the container has started, verify the app writes to stdout or stderr, and try --previous if the current instance restarted before you looked.

6. Do Kubernetes events persist forever?

No. Kubernetes API server events have a default retention period of one hour, but cluster administrators can change --event-ttl. Events are therefore temporary diagnostics, not an audit or long-term logging system.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)