What Is a Kubernetes Pod? How Pods Work in EKS

A pod is the smallest deployable unit in Kubernetes. It wraps one or more containers that share a network, a hostname, and optionally storage. In EKS, every workload you run is built from pods, whether you see them directly or not.

Simple explanation

Kubernetes does not schedule individual containers. It schedules pods. A pod is the unit Kubernetes places on a node, monitors for health, and restarts if it crashes. When you ask for three replicas of your app, you get three pods, each containing one container.

Analogy

Think of a pod like a work shift at a factory. The shift includes one or more workers (containers), assigns them to a specific workstation (node), and gives them a shared locker room (network namespace) so they can coordinate. When the shift ends, the locker room disappears. The workers do not stick around once the shift is over.

Most pods contain a single container. Multi-container pods are a specific pattern (sidecars, init containers) and not the default. If you are new to Kubernetes, assume single-container pods until you have a clear reason to add more.

What a pod actually is

A pod groups one or more containers and provides them with shared infrastructure:

  • Shared IP address. All containers in a pod share a single IP address. They can reach each other on localhost without going through the cluster network.
  • Shared network namespace. Containers in the same pod see the same network interfaces and can bind to different ports on localhost.
  • Shared volumes. Containers can mount the same volume, allowing them to exchange files without making network calls.
  • Single node. All containers in a pod always run on the same node. A pod cannot span multiple nodes.

From the perspective of the rest of the cluster, a pod is one entity with one IP. From inside the pod, containers are tightly coupled: they live and die together.

Note

Most pods you write will have a single container. Multi-container pods exist for specific patterns (sidecars, init containers, ambassadors), not as a general design. If two services do not need to share a network or volume, they belong in separate pods.

How it works

When you deploy an application to Amazon EKS, here is what happens at the pod level:

  1. You define a workload. You write a Deployment manifest that includes a pod template: the image, ports, resource limits, and health checks.
  2. A controller creates pods. The Deployment controller reads your desired state and creates pods to match it. You rarely write bare pod specs in production.
  3. The scheduler assigns a node. Kubernetes looks at the pod’s resource requests and finds a node with enough available capacity.
  4. Kubelet starts containers. The kubelet agent on the target node pulls the container image from ECR (or another registry) and starts the containers.
  5. The pod gets a network address. EKS uses the VPC CNI plugin to assign the pod a real IP from your VPC subnet, making it directly routable inside your VPC.
  6. A Service routes traffic. A Kubernetes Service uses a label selector to find pods with matching labels and sends traffic to them.

The relationship between these concepts, in plain terms:

  • A pod is one running instance of your app.
  • A node is the EC2 instance (or Fargate profile) where the pod runs.
  • A Deployment manages a set of identical pods and handles updates and failures.
  • A Service provides a stable IP and DNS name that always points to healthy pods.

Kubernetes pod vs container vs Deployment

These three terms are the ones beginners mix up the most.

ConceptWhat it isWho creates it
ContainerA packaged process: your app code bundled with its runtime dependencies into a portable imageBuilt with Docker or a CI pipeline; not a Kubernetes object
PodThe smallest deployable unit in Kubernetes; wraps one or more containers with a shared IP, network namespace, and optional volumesUsually created by a controller (Deployment, StatefulSet); can be created directly for testing
DeploymentA controller that manages a set of identical pod replicas, handles rolling updates, and recreates pods when they failCreated by you via kubectl or GitOps; it then creates and owns the pods

Containers run inside pods, and pods are managed by Deployments (or other controllers). You interact with Deployments. Kubernetes manages the pods. For the EKS vs ECS tradeoff when choosing a container platform, see EKS vs ECS.

When to use this

In practice, you rarely create bare pods directly. You use higher-level resources that manage pods for you.

Common pod patterns in production EKS workloads:

  • App replicas via Deployment. Your API or web service runs as multiple pods managed by a Deployment. Each pod handles a share of traffic. If one crashes, the Deployment creates a replacement automatically.
  • Sidecars. A main app container runs alongside a helper container in the same pod. For example, a Fluent Bit container that ships logs to CloudWatch. See logging in Kubernetes for how this works.
  • Node-level agents via DaemonSet. Monitoring and logging agents need to run on every node. A DaemonSet creates one pod per node automatically. See monitoring EKS clusters for common agent patterns.
  • Batch tasks via Job or CronJob. A data processing script runs to completion in a pod, exits with Succeeded, and the pod is done.
  • Debugging. A bare pod lets you run a shell inside the cluster to test network connectivity or inspect a volume.
Warning

Never use a bare pod for a long-lived production workload. If the node it runs on is terminated, the pod is gone permanently and will not be rescheduled. Use a Deployment for anything that needs to keep running reliably.

Pod lifecycle and common states

Every pod moves through a series of phases. Knowing these helps you diagnose problems when pods are not behaving as expected.

PhaseMeaningCommon causes if stuck here
PendingPod accepted by the cluster but containers have not started yetInsufficient node capacity, image pull waiting, volume not available, node selector mismatch
RunningAt least one container is running or startingNormal state for active workloads; check container-level state if something looks wrong
SucceededAll containers exited with code 0Normal for completed Jobs or CronJobs
FailedAt least one container exited with a non-zero codeApplication error, OOMKill, crash
UnknownPod state cannot be determinedNode communication lost; the pod may still be running on that node

Within a running pod, individual containers have their own states: Waiting, Running, or Terminated. The pod phase is the overall summary. The container state tells you the detail. A pod can show Running while a container inside it is still Waiting for an image pull to complete.

Use these commands to inspect pod and container state:

# List all pods in the current namespace
kubectl get pods

# Describe a pod — shows events, container states, exit codes, and conditions
kubectl describe pod <pod-name>

# View logs from a container
kubectl logs <pod-name>

# View logs from a specific container in a multi-container pod
kubectl logs <pod-name> -c <container-name>

# Stream logs in real time
kubectl logs <pod-name> -f
Note

If you see a pod stuck in CrashLoopBackOff, the phase will show Running but the container keeps crashing and restarting. Use kubectl logs <pod-name> —previous to read logs from the crashed container. See debugging EKS CrashLoopBackOff errors for a full walkthrough.

Pod YAML example

Here is a complete single-container pod specification:

apiVersion: v1
kind: Pod
metadata:
  name: web-server
  labels:
    app: web
    environment: production
spec:
  containers:
  - name: nginx
    image: nginx:1.27
    ports:
    - containerPort: 80
    resources:
      requests:
        cpu: 100m
        memory: 128Mi
      limits:
        cpu: 500m
        memory: 256Mi
    readinessProbe:
      httpGet:
        path: /health
        port: 80
      initialDelaySeconds: 5
      periodSeconds: 10

Key fields explained:

  • metadata.labels — key-value pairs attached to the pod. Services use label selectors to find pods, so these labels control which pods receive traffic. They are not just documentation.
  • image — the container image to run. Always pin to a specific version tag (nginx:1.27) rather than latest. The latest tag changes silently and can cause unpredictable behaviour when pods restart.
  • resources.requests — the minimum CPU and memory the pod needs. The scheduler uses these to decide which node to place the pod on. CPU is measured in millicores (100m = 0.1 cores). Memory is in mebibytes (128Mi).
  • resources.limits — the maximum CPU and memory the pod can use. A container that exceeds its memory limit is killed with an OOMKilled error.
  • readinessProbe — Kubernetes checks this before sending traffic to the pod. A pod that fails its readiness check is removed from Service endpoints. Without this, your app receives traffic before it is ready.

You can apply this manifest using kubectl:

kubectl apply -f pod.yaml
kubectl get pod web-server

Multi-container pods and sidecars

Multi-container pods are not the default. Use them when two containers genuinely need to share a network or a volume, not simply because they are related services.

The most common pattern is the sidecar: a helper container running alongside the main app. In this example, a Fluent Bit container reads log files written by the web app and ships them to CloudWatch:

apiVersion: v1
kind: Pod
metadata:
  name: app-with-logging
spec:
  containers:
  - name: web-app
    image: my-company/web-app:2.1.0
    ports:
    - containerPort: 8080
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/app
  - name: log-shipper
    image: fluent/fluent-bit:3.0
    volumeMounts:
    - name: log-volume
      mountPath: /var/log/app
      readOnly: true
  volumes:
  - name: log-volume
    emptyDir: {}

The web app writes to /var/log/app. Fluent Bit reads from the same directory via a shared emptyDir volume. The two containers coordinate through the filesystem without any network calls. Because they share an IP, they can also communicate directly over localhost on any port.

Think of it this way

A sidecar is like a support vehicle that travels alongside the main truck. It does not carry the main cargo, but it provides something the truck cannot do on its own — fuelling, GPS logging, temperature monitoring. Remove the sidecar and the truck still drives. Add it back and the truck gets capabilities it could not build for itself.

Other multi-container patterns include init containers (run to completion before the main container starts, used for setup tasks like schema checks) and ambassador containers (proxy network connections on behalf of the main container).

Common mistakes

  1. Using the latest image tag. The latest tag changes over time. A pod that restarts after a node replacement may pull a different image than the one that was running before. Always pin to a specific version tag or image digest in production.
  2. Not setting resource requests and limits. Without CPU and memory requests, the scheduler places pods without knowing whether the node can handle the load. Nodes become overloaded, pods get OOMKilled, and the cluster becomes unstable. Set both on every container.
  3. Missing readiness probes. Without a readiness probe, Kubernetes sends traffic to a pod the moment the container starts, even if your app takes ten seconds to initialise. This causes failed requests during every deployment and restart.
  4. Hard-coding pod IP addresses. Pod IPs are ephemeral. Every time a pod is created or replaced, it gets a new IP. Never reference a pod by IP in application configuration. Use a Kubernetes Service for a stable endpoint.
  5. Creating bare pods for long-lived workloads. Bare pods have no self-healing. If the node terminates, the pod is gone and nothing recreates it. Use a Deployment for any workload that needs to stay running.
  6. Confusing restart with recreation. When a container inside a pod crashes, kubelet restarts it on the same pod, same node, same IP. When the pod itself is deleted and recreated (for example, after a node failure), it is a new pod with a new IP and a clean filesystem.
  7. Assuming a pod can span multiple nodes. A pod always runs on exactly one node. For redundancy across nodes, create multiple pod replicas. Each replica is a separate pod that Kubernetes may place on a different node.

Pod vs node, Service, and Deployment

These four concepts are easy to mix up when you are starting out:

ConceptWhat it isCommon confusion
PodOne running instance of your app: one or more containers sharing a network and optionally storagePeople sometimes think scaling a Deployment scales the pod itself, or that a pod is a node
NodeThe EC2 instance or Fargate profile where pods runNodes are the physical or virtual machine. Pods run on nodes, not as nodes
ServiceA stable virtual IP and DNS name that routes traffic to matching podsA Service is not a pod. It is a network abstraction. Deleting a pod does not delete its Service
DeploymentA controller that manages a set of pod replicas, handles updates and self-healingA Deployment is not a pod. It owns pods. Deleting a Deployment deletes all its pods

Frequently asked questions

Can a pod run on multiple nodes?

No. A pod always runs on a single node. If you need redundancy, create multiple pod replicas using a Deployment. Kubernetes may schedule each replica on a different node, but each individual pod stays on exactly one node.

What is the difference between a pod and a container?

A container is a packaged process: your application code bundled with its runtime dependencies into a portable image. A pod is a Kubernetes construct that wraps one or more containers, gives them a shared IP address and network namespace, and lets them communicate over localhost. You do not schedule containers directly in Kubernetes; you schedule pods.

What happens when a pod dies?

It depends on how it was created. If the pod was created by a Deployment or StatefulSet, the controller detects the missing pod and creates a replacement on a healthy node. If it was a bare pod created directly, it is gone permanently. Either way, the replacement pod gets a new IP address.

Why does a pod IP change?

Pod IPs are ephemeral. Every time a pod is created or replaced, Kubernetes assigns it a new IP from the node CIDR block. Use a Kubernetes Service instead of a pod IP. The Service maintains a stable virtual IP and routes traffic to whichever pods match its selector.

When should I use a Deployment instead of a pod?

Almost always. Bare pods have no self-healing, no replica management, and no rolling update capability. Use a Deployment for stateless apps, a StatefulSet for stateful workloads, a DaemonSet for node-level agents, and a Job or CronJob for batch tasks. Bare pods are mostly useful for quick debugging inside the cluster.

Last verified: 4 April 2026 Cloud services change frequently. Verify details against official documentation before making infrastructure decisions.