How does centralized logging typically work in Kubernetes, given pods are ephemeral?

6 minintermediateloggingdaemonsetobservability

Quick Answer

Container stdout/stderr is written to a file on the node by the container runtime. A log-collection agent, almost always deployed as a DaemonSet so it runs on every node, tails these log files and forwards them to a centralized, durable logging backend (Elasticsearch, Loki, a cloud logging service). This decouples log durability from any individual Pod's lifetime — a Pod's local log files disappear when it's deleted, but the already-shipped copies in the centralized backend persist and remain searchable.

Detailed Answer

Why Pod ephemerality makes centralized logging necessary

kubectl logs reads directly from a log file the container runtime maintains on the node the Pod is (or was recently) running on. The moment a Pod is deleted, rescheduled, scaled down, or replaced during a rollout, those local log files eventually get cleaned up too, and kubectl logs for that specific Pod name no longer works at all. For anything beyond quick, live debugging of a still-running Pod, relying on kubectl logs alone isn't enough — you need logs collected and stored somewhere durable, independent of any individual Pod's lifetime.

The standard architecture: a log-shipping DaemonSet

Node                                    Node
┌──────────────────────┐          ┌──────────────────────┐
│ Pod A -> stdout/stderr │          │ Pod C -> stdout/stderr │
│    -> log file on node  │          │    -> log file on node  │
│ Pod B -> stdout/stderr │          │                        │
│    -> log file on node  │          │  Fluent Bit (DaemonSet) │
│                        │          │    tails log files       │
│ Fluent Bit (DaemonSet) │          │    ships them out          │
│    tails log files       │          └──────────────────────┘
│    ships them out          │                     │
└──────────────────────┘                     │
             │                                       │
             └───────────────┬───────────────────────┘
                             ▼
                  Centralized logging backend
              (Elasticsearch, Loki, CloudWatch, etc.)

A log-shipping agent (Fluentd, Fluent Bit, Vector, or a cloud provider's own agent) runs as a DaemonSet — see the workload controllers topic, this is exactly the canonical DaemonSet use case — so exactly one copy runs on every node, continuously tailing every container's log files on that node and forwarding them to a centralized backend, often enriching each log line with useful Kubernetes metadata (Pod name, namespace, labels) along the way.

Common centralized logging backends

  • Elasticsearch (or OpenSearch) + Kibana — the classic "ELK/EFK stack" (Elasticsearch, Fluentd, Kibana), offering rich full-text search and dashboarding.
  • Grafana Loki — a more lightweight, cost-efficient alternative that indexes only metadata/labels, not full log text, often paired with Grafana for visualization. Appealing when Elasticsearch's resource cost and operational complexity are undesirable.
  • Cloud-native logging services — AWS CloudWatch Logs, GCP Cloud Logging, Azure Monitor Logs. Convenient when already running on that cloud provider, with less operational overhead than self-hosting a logging stack.

An alternative pattern: sidecar-based log shipping

Instead of a node-level DaemonSet, some setups use a sidecar container per Pod (see the sidecar pattern question) specifically to ship that one Pod's logs. Useful when an application writes logs to a file rather than stdout/stderr, requiring a sidecar with a shared volume to tail that specific file, but generally higher overhead — one shipping agent per Pod rather than one per node — than the DaemonSet approach, and used more selectively for that reason.

Best practice: log to stdout/stderr, not files

Applications running in containers should generally write logs to stdout/stderr rather than to files within the container. This is what the container runtime and standard log-shipping DaemonSets are built to capture automatically, without needing any sidecar or special per-application configuration. Writing to internal files instead requires extra plumbing, a sidecar or a shared volume, to get those logs collected at all — one of the "twelve-factor app" principles that maps directly onto how Kubernetes logging infrastructure expects applications to behave.