| 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.
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
YAMLThe 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:
kubectl wait pod \
-n logs-lab \
-l app=web \
--for='jsonpath={.status.containerStatuses[?(@.name=="logger")].state.waiting.reason}=CrashLoopBackOff' \
--timeout=120sThen confirm Pod status:
kubectl get pods -n logs-labSample output:
NAME READY STATUS RESTARTS AGE
web-xxxxxxxxxx-aaaaa 1/2 CrashLoopBackOff 1 25s
web-xxxxxxxxxx-bbbbb 1/2 CrashLoopBackOff 1 25sSTATUS 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:
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:
kubectl get pods -n logs-labSample output:
NAME READY STATUS RESTARTS AGE
web-xxxxxxxxxx-aaaaa 1/2 CrashLoopBackOff 1 25s
web-xxxxxxxxxx-bbbbb 1/2 CrashLoopBackOff 1 25sREADY 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:
kubectl get pods -n logs-lab --watchThe 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:
kubectl get pods --all-namespaces | head -8Sample 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 18hAdd -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:
kubectl get pods -n logs-lab -o wideSample 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:
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 -12Sample 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: webkubectl 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:
kubectl get pod "$POD" \
-n logs-lab \
-o jsonpath='owner={.metadata.ownerReferences[0].kind}/{.metadata.ownerReferences[0].name}{"\n"}'Sample output:
owner=ReplicaSet/web-85c97ffd56The 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:
kubectl describe pod "$POD" -n logs-labThe 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 state —
Running,Waiting, orTerminatedper 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.
Read container state and related events
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.
kubectl describe pod "$POD" -n logs-lab | grep -A12 '^Events:'Sample 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 startedWarning 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:
kubectl describe pods -n logs-lab -l app=web | head -8Sample 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=85c97ffd56The 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:
kubectl describe deployment web -n logs-lab | head -20Sample 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.
RS=$(kubectl get rs -n logs-lab -l app=web -o jsonpath='{.items[0].metadata.name}')
kubectl describe rs "$RS" -n logs-lab | head -18ReplicaSet describe shows how many Pods are running versus desired and repeats the Pod template.
kubectl describe service web -n logs-labExpected relevant 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,StartedFailedScheduling,FailedMountBackOff,Unhealthy
Filter with kubectl events
kubectl events provides straightforward filtering with --for, --types, and --watch on the tested kubectl version.
kubectl events -n logs-labSample 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 worker01Filter to warnings when you want failures without normal noise:
kubectl events -n logs-lab --types=WarningSample 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:
kubectl events -n logs-lab --for "pod/$POD"Sample 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:
kubectl events -n logs-lab --for "pod/$POD" --watchPress Ctrl+C to stop watching. The stream does not change the Pod.
List events cluster-wide when the namespace is unknown:
kubectl events --all-namespaces | head -6Sample 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-gsk9sSort and select with kubectl get events
The traditional form still works on every cluster:
kubectl get events -n logs-lab --sort-by=.metadata.creationTimestampSample 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:
kubectl get events -n logs-lab --field-selector type=WarningSample 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:
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:
kubectl logs "$POD" -n logs-lab -c nginxSample 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:
kubectl get pod "$POD" -n logs-lab -o jsonpath='{.spec.containers[*].name}{"\n"}'Sample output:
nginx loggerRead the failing logger container:
kubectl logs "$POD" -n logs-lab -c logger --tail=5Sample output:
logger-start
logger-crashThat output matches the script: the container prints logger-start, sleeps, prints logger-crash, then exits with code 1.
Read every container in one stream:
kubectl logs "$POD" -n logs-lab --all-containers=true --tail=3Follow 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:
kubectl wait pod "$POD" \
-n logs-lab \
--for='jsonpath={.status.containerStatuses[?(@.name=="logger")].state.running.startedAt}' \
--timeout=120skubectl logs -f "$POD" -n logs-lab -c loggerPress 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:
kubectl logs "$POD" -n logs-lab -c logger --previousSample 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:
kubectl logs "$POD" -n logs-lab -c nginx --tail=2Sample 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 29Display logs from a recent period:
kubectl logs "$POD" -n logs-lab -c nginx --since=1h --tail=1Sample 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:
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:
kubectl logs "$POD" -n logs-lab -c nginx --timestamps --tail=1Sample output:
2026-07-26T18:46:02.122204733+05:30 2026/07/26 13:16:02 [notice] 1#1: start worker process 29The 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:
kubectl logs -n logs-lab -l app=web -c nginx --tail=1 --prefixSample 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 29Add --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:
kubectl logs deployment/web -n logs-lab -c nginx --tail=2Sample 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 29That workload shortcut chooses one backing Pod.
Read all Pods owned by the Deployment:
kubectl logs deployment/web -n logs-lab -c nginx --all-pods=true --tail=2--all-pods=true automatically enables prefixes.
For a finished Job:
kubectl create job data-import -n logs-lab --image=busybox:1.36 -- sh -c 'echo import-start; echo done'kubectl wait --for=condition=complete job/data-import -n logs-lab --timeout=60skubectl logs job/data-import -n logs-labSample output:
import-start
doneKubernetes 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:
kubectl get pods -n logs-lab -o wide— confirm names, node, and restart countkubectl describe pod <name>— read conditions, container last state, and inline eventskubectl events --for pod/<name> --types=Warningorkubectl get eventswith field selectors — scan warnings without describe noisekubectl logs <name> -c logger— read the failing container's current outputkubectl logs <name> -c logger --previous— read the instance that exited before the latest restartkubectl 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
- Debug Kubernetes Pods with kubectl exec and kubectl debug
- Build Immutable Containers in Kubernetes
- Kubernetes Audit Logging with Policy Examples
References
- kubectl Reference — upstream command overview
- kubectl logs — log flags and workload selectors
- kubectl events —
--for,--types, and--watch - Debug Pods — upstream debugging overview
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.

