The command is kubectl logs, not kubectl get logs. Use kubectl get pods to find the pod, then pass that pod name to kubectl logs:
kubectl get pods --namespace=production
kubectl logs api-7d8f6c7b9f-rxk2m --namespace=production
For a pod with more than one container, add --container:
kubectl logs api-7d8f6c7b9f-rxk2m \
--container=api \
--namespace=production
kubectl get reads Kubernetes resource state. Logs are exposed through the pod log subresource, so logs is its own kubectl command. The current Kubernetes kubectl logs reference defines the syntax as kubectl logs [-f] [-p] (POD | TYPE/NAME) [-c CONTAINER].
kubectl logs command cheat sheet
| Task | Command |
|---|---|
| Current logs from one pod | kubectl logs POD -n NAMESPACE |
| One container in a pod | kubectl logs POD -c CONTAINER -n NAMESPACE |
| Follow new output | kubectl logs -f POD -c CONTAINER -n NAMESPACE |
| Last 200 lines | kubectl logs POD --tail=200 -n NAMESPACE |
| Logs from the last 30 minutes | kubectl logs POD --since=30m -n NAMESPACE |
| Logs after an exact time | kubectl logs POD --since-time=2026-09-15T14:00:00Z -n NAMESPACE |
| Add timestamps | kubectl logs POD --timestamps=true -n NAMESPACE |
| Previous container instance | kubectl logs POD -c CONTAINER --previous -n NAMESPACE |
| All containers in one pod | kubectl logs POD --all-containers=true --prefix -n NAMESPACE |
| All pods in a deployment | kubectl logs deployment/NAME --all-pods=true -n NAMESPACE |
| Pods selected by label | kubectl logs -l app=api --all-containers=true --prefix -n NAMESPACE |
| Check log permission | kubectl auth can-i get pods --subresource=log -n NAMESPACE |
Replace the uppercase values with real names. Keep the namespace explicit during incidents, and check the context before assuming the command is pointed at the intended cluster.
Confirm the cluster, namespace, and pod first
Start with the current context and the target namespace:
kubectl config current-context
kubectl get pods --namespace=production
If the pod is not listed, do not broaden immediately to every cluster. Check the configured contexts and select the intended one explicitly:
kubectl config get-contexts
kubectl --context=production-ca-east get pods --namespace=production
kubectl --context=production-ca-east logs api-7d8f6c7b9f-rxk2m --namespace=production
A kubeconfig context combines a cluster, user, and optional default namespace. The official kubeconfig guidance warns that a specially crafted kubeconfig can execute code or expose files, so treat kubeconfig files from unknown sources like executable content.
Use the same context and namespace for discovery and log reading. Pod names change during rollouts, scaling, and rescheduling, so copy the current name rather than relying on an old incident note.
kubectl get pods reports Kubernetes state; it does not contain application output. When a pod is Pending, restarting, or failing a probe, pair logs with state and events:
kubectl describe pod api-7d8f6c7b9f-rxk2m --namespace=production
kubectl logs api-7d8f6c7b9f-rxk2m --container=api --namespace=production
The description can expose scheduling, image, mount, and probe failures that never reach the application logger.
Select the right application or init container
A pod may contain the application, a proxy, a metrics sidecar, and init containers. If the pod has more than one candidate, specify the exact container with -c or --container.
List regular container names:
kubectl get pod api-7d8f6c7b9f-rxk2m \
--namespace=production \
--output=jsonpath='{.spec.containers[*].name}{"\n"}'
Then read one container:
kubectl logs api-7d8f6c7b9f-rxk2m \
--container=api \
--namespace=production
To compare the containers in one pod, use source prefixes:
kubectl logs api-7d8f6c7b9f-rxk2m \
--all-containers=true \
--prefix \
--tail=100 \
--namespace=production
--prefix adds the pod and container source to each output line. It is essential when several sources are interleaved, but it does not create a perfectly ordered distributed timeline.
Read init container logs
A regular init container runs to completion before the application containers start. Current Kubernetes also implements native sidecars as restartable entries under initContainers, so that list can contain both one-shot setup containers and sidecars that remain running. List the names separately:
kubectl get pod api-7d8f6c7b9f-rxk2m \
--namespace=production \
--output=jsonpath='{.spec.initContainers[*].name}{"\n"}'
Pass an init container name to the same logs command:
kubectl logs api-7d8f6c7b9f-rxk2m \
--container=database-migration \
--namespace=production
This is often the useful command when the pod is stuck in initialization. The Kubernetes init-container debugging guide also recommends checking detailed pod status and events because an image pull, volume, or scheduling problem may prevent the init process from producing logs at all.
Ephemeral debug containers also have names. After an authorized operator adds one with kubectl debug, its output can be read with kubectl logs POD -c DEBUG_CONTAINER. Creating an ephemeral container changes the pod and requires separate permission; reading existing logs does not authorize that mutation.
Follow, tail, and limit the output
Use --follow or -f while reproducing a current problem:
kubectl logs --follow api-7d8f6c7b9f-rxk2m \
--container=api \
--namespace=production
Following begins with the selected existing output and then streams new lines. Reduce the starting volume with --tail or --since:
kubectl logs --follow api-7d8f6c7b9f-rxk2m \
--container=api \
--tail=200 \
--since=15m \
--timestamps=true \
--namespace=production
The main range flags are:
--tail=200returns the most recent number of lines;--since=30mreturns logs newer than a relative duration;--since-time=2026-09-15T14:00:00Zuses an RFC 3339 starting time;--timestamps=trueincludes the timestamp carried by the container log;--limit-bytes=1048576limits returned bytes.
Use only one of --since and --since-time. Set --tail explicitly when using a label selector: the current command defaults to all lines without a selector, but only 10 lines when a selector is present.
--timestamps helps compare events, but clocks and application timestamps can still differ. The Kubernetes-added container-log timestamp is not a substitute for a trusted event timestamp inside structured application output.
Read logs from deployments, jobs, and several pods
kubectl logs accepts a pod or a supported TYPE/NAME target. The official reference includes deployments and jobs:
kubectl logs deployment/api \
--container=api \
--tail=200 \
--namespace=production
kubectl logs job/database-migration \
--namespace=production
A deployment can own several replica pods. Without --all-pods=true, a workload command does not mean “combine every replica.” Request all deployment pods explicitly:
kubectl logs deployment/api \
--all-pods=true \
--all-containers=true \
--tail=100 \
--namespace=production
--all-pods also enables source prefixes. For more deliberate selection, inspect labels and query matching pods:
kubectl get pods \
--selector='app.kubernetes.io/name=api' \
--show-labels \
--namespace=production
kubectl logs \
--selector='app.kubernetes.io/name=api' \
--all-containers=true \
--prefix \
--tail=100 \
--namespace=production
When following a selector across many pods, --max-log-requests controls concurrent log streams and defaults to five. Increase it carefully; many concurrent requests can load the API server, kubelets, terminal, and local network.
kubectl logs --follow \
--selector='app.kubernetes.io/name=api' \
--all-containers=true \
--prefix \
--tail=50 \
--max-log-requests=10 \
--namespace=production
The output from several pods is interleaved. Prefixes identify sources, but network delay and buffering mean line order is not a guaranteed cluster-wide event order.
A Service can select pod logs but does not store them
A Kubernetes Service selects network endpoints; it does not run a container or store logs. Current kubectl can resolve a selector-based Service to matching pods, so this command reads the pod logs selected by the Service:
kubectl logs service/checkout \
--all-pods=true \
--all-containers=true \
--prefix \
--tail=100 \
--namespace=production
This is kubectl selector behavior, not a Service log stream. A selectorless Service cannot be resolved this way, and a stale or overly broad selector can return the wrong pods. Inspect the Service selector and matching pods before relying on the result:
kubectl get service checkout \
--output=jsonpath='{.spec.selector}{"\n"}' \
--namespace=production
kubectl get pods \
--selector='app=checkout' \
--namespace=production
kubectl logs \
--selector='app=checkout' \
--all-containers=true \
--prefix \
--tail=100 \
--namespace=production
The app=checkout label is only an example. Use the actual selector returned by the Service; do not assume every cluster uses an app label. Without --all-pods=true, a TYPE/NAME target may return only one selected pod rather than every replica.
Use --previous after a container restart
kubectl logs normally reads the current container instance. If that instance restarted, the failure may be in the previous instance:
kubectl logs worker-6cb9c76467-9m2qk \
--container=worker \
--previous \
--timestamps=true \
--namespace=production
This is the most useful sequence for CrashLoopBackOff:
kubectl get pod worker-6cb9c76467-9m2qk --namespace=production
kubectl describe pod worker-6cb9c76467-9m2qk --namespace=production
kubectl logs worker-6cb9c76467-9m2qk -c worker --previous -n production
--previous only works if a prior container instance exists and its log is still available. Kubernetes’ logging architecture documentation states that the kubelet keeps one terminated container with its logs by default. When a pod is evicted, its containers and logs are evicted with it. After a pod is deleted or replaced, do not rely on its former node-local files remaining reachable through kubectl.
This is not unlimited restart history. Centralized logging is required when an investigation must survive repeated restarts, pod replacement, or node loss.
RBAC must allow the pod log subresource
Reading logs is an API operation. The relevant namespaced resource is pods/log, usually with the get verb. Listing pods for discovery or a label selector also needs access to pods.
Check both operations:
kubectl auth can-i list pods --namespace=production
kubectl auth can-i get pods --subresource=log --namespace=production
The second form follows the current official kubectl auth can-i example. A minimal namespaced Role for direct pod-name and label-selector log reading can look like this:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: pod-log-reader
namespace: production
rules:
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get"]
A Role does nothing until an administrator binds it to the intended user, group, or service account. Keep the namespace and subjects narrow. Do not grant cluster-admin merely to resolve a Forbidden response.
The deployment/NAME, job/NAME, and service/NAME shortcuts also require permission to read the named source resource so kubectl can resolve its pod selector. Grant get only for the workload kinds operators actually use—for example, deployments in the apps API group, jobs in batch, or services in the core API group. The Role above intentionally covers direct pod targets and label selectors, not every workload shortcut.
Log access can expose credentials, personal data, request bodies, and internal topology. Treat pods/log as sensitive read access even though it cannot modify the pod.
Fix common kubectl logs errors
Exact error text varies by Kubernetes and container-runtime version, but these checks address the common causes.
Pod not found
Confirm the context, namespace, and current pod name:
kubectl config current-context
kubectl get pods --namespace=production
The copied name may belong to another cluster or to a replica that a rollout already replaced.
Container not found or a default container was selected
List regular and init container names, then retry with --container. A container name comes from the pod specification, not from the image name.
kubectl get pod POD -n NAMESPACE \
-o jsonpath='{.spec.containers[*].name}{"\n"}{.spec.initContainers[*].name}{"\n"}'
Waiting for the pod to start
Use kubectl describe pod and inspect events. Scheduling, image pulls, or volume mounts may be blocked before the application starts. --pod-running-timeout=60s can wait for a pod to become running, but it does not repair the underlying condition.
No output
Confirm the process writes to standard output or standard error. Output written only to an internal application file is not automatically available through kubectl logs. Also check the selected container, --since, --since-time, --tail, and label selector.
Previous terminated container not found
Check .status.containerStatuses in kubectl describe pod. A restart count of zero means no previous instance exists. A newly created replacement pod also has no access to the old pod’s local logs.
Forbidden or unauthorized
Run the two kubectl auth can-i checks above. Unauthorized usually means the current credential is missing, expired, or rejected. Forbidden means the authenticated identity lacks permission. Repair authentication or request the narrow RBAC rule instead of bypassing TLS or using an administrator credential.
Follow stopped unexpectedly
The selected container may have terminated, the pod may have been replaced, or the connection may have closed. Check pod state and restart count, inspect --previous, and discover the current replica. kubectl logs -f follows the selected container stream; it is not a durable subscription across arbitrary replacement pods.
kubectl logs does not read every node log
Container application logs and node system logs are different sources. kubectl logs reaches container logs through the Kubernetes API and kubelet. It does not make kubectl logs node/worker-1 a general reader for kubelet, container-runtime, kernel, or operating-system logs.
On Linux nodes using systemd, Kubernetes documents kubelet and container-runtime output in journald, commonly inspected with an authorized node session and a command such as:
journalctl --unit=kubelet
If direct node access is unavailable, Kubernetes also documents kubectl debug node/NODE:
kubectl debug node/worker-1 -it --image=ubuntu:24.04
Run this only under an approved node-debugging procedure. It is not a read-only form of kubectl logs: it creates a debugging pod on the node, joins the host IPC, network, and PID namespaces, and mounts the node filesystem at /host. The pod is not privileged by default, so some process access and chroot /host can fail. The --profile=sysadmin option grants stronger privileges and needs a separate security decision. Delete the generated debugging pod when the session ends.
Managed clusters may provide a cloud-specific node-log path instead of node shell access. Control-plane components that run as visible pods can be read through their pod names when the cluster exposes them and RBAC allows it. Do not confuse those pod logs with the host’s kubelet journal.
Avoid --insecure-skip-tls-verify-backend as a routine fix. The kubectl reference warns that disabling kubelet identity verification can allow invalid log content to be returned. Repair kubelet serving certificates and trust configuration instead.
Local rotation limits kubectl log history
The container runtime redirects container stdout and stderr into the Container Runtime Interface logging path. The kubelet rotates those files according to node configuration. Kubernetes documents an important limitation: kubectl logs exposes only the latest log file for the selected container instance.
That means a high-volume container can lose older lines from the kubectl view even while the pod is still running. --tail=-1 cannot recover data that has already rotated out of the latest file. Pod eviction, deletion, and node failure create stronger boundaries.
Kubernetes does not provide native cluster-level log storage. Its documented architecture uses a separate backend, commonly fed by a node-level agent running as a DaemonSet. Keep kubectl logs for immediate checks; use centralized retention when evidence must outlive the pod or be searched across namespaces and clusters.
Keep credentials and sensitive output out of terminals and tickets
Do not put bearer tokens, client keys, or inline kubeconfig contents in a kubectl logs command. Use the approved kubeconfig and authentication plugin. Command-line arguments and shell history can be collected by endpoint tooling or exposed to other local processes.
Log output can be equally sensitive. Before redirecting output to a file, piping it to another service, pasting it into a ticket, or sending it to an AI tool:
- narrow the time, pod, and container;
- review for tokens, cookies, personal data, and customer payloads;
- redact values without destroying the event context needed for diagnosis;
- store exported files with restricted permissions and a deletion owner;
- prefer stable event identifiers and controlled links over copying large raw payloads.
Never pipe kubectl logs directly into an arbitrary HTTP endpoint. A production collector needs authentication, buffering, retry limits, parsing, metadata enrichment, and auditable ownership.
Use centralized logging when the incident outlives one pod
kubectl logs is ideal for a direct current check. Centralized logging becomes necessary when logs must survive pod replacement or node loss, several replicas must be searched as one incident, Kubernetes metadata must remain queryable, or responders need shared retained evidence.
Fluxtail is a paid, logs-focused service with Starter and Pro self-service plans. A node-level collector can forward Kubernetes container logs to a documented receiver and named stream. The collector must supply and map pod, namespace, container, node, service, label, message, timestamp, and severity data correctly; Fluxtail does not infer every field from arbitrary text.
The Kubernetes logging workflow explains the collector-to-stream architecture. In Fluxtail, Live Tail follows retained events, and search and filters cover stream, time, message, service, severity, labels, and documented Kubernetes dimensions when those fields were received.
Built-in AI chat is separate from Fluxtail’s hosted MCP server. Hosted MCP uses browser OAuth with PKCE and consent bound to one account. Its read tools can query logs and diagnose missing data; operator mutations are proposed first and require a short-lived confirmation token. Raw retained events remain available to verify summaries and agent findings.
Fluxtail accepts logs, including OTLP logs, but does not claim native tracing or APM. Keep using kubectl logs to verify one pod at the source, and use centralized streams when the investigation crosses pod, namespace, node, or time boundaries.