All posts

Kubernetes illustrated: how Pods, Deployments, and Services fit together

· 14 min read

Follow a book-list API through Kubernetes. Eight diagrams and a placement sketch connect clusters and Nodes, Pod creation and replacement, Service traffic, health probes, configuration, storage, scaling, and rolling updates.

1. What is Kubernetes? Keeping three copies of an API running

A container image packages an application and the files it needs. A container is a running environment created from that image. A container runtime can start it on one machine. Across multiple machines, you also need placement, replacement after failure, stable destinations, and updates. Kubernetes, abbreviated K8s, manages those concerns.

Consider a fictional API that lists books. You declare a desired state: run three Pods of books-api v1. Controllers observe the current state and close the gap, for example by creating missing Pods. This repeated adjustment is called reconciliation.

Figure 1: one pass through reconciliation. Observation and adjustment repeat.

Declare: three Pods needed → Observe: only two exist → Adjust: create the missing Pod → Observe again: are there three?

Creation takes time. Insufficient capacity or permissions can prevent the system from reaching its target. Writing three does not instantly produce three healthy instances; Kubernetes keeps working toward that goal. The following example uses a conventional Deployment and a ClusterIP Service with a selector.

2. Cluster, Node, Pod, and container: what runs where?

A cluster consists of a control plane that manages it and Nodes that run applications. A Node is a virtual or physical machine. A Pod is placed on one Node and contains one or more containers sharing a network environment and, where configured, volumes. Closely coupled helpers, such as an API and its proxy, can share a Pod.

Placement sketch: this two-Node arrangement is illustrative, not a guarantee of automatic even placement
Cluster
├─ Control plane (manages the cluster)
└─ Worker Nodes (run applications)
   ├─ Node A
   │  ├─ Pod A [API container]
   │  └─ Pod B [API container]
   └─ Node B
      └─ Pod C [API container]

To run three API instances, normally replicate the API Pod three times rather than putting three API containers inside one Pod. A Pod is the unit of placement and replication. Containers in the same Pod cannot be spread across Nodes. To distribute replicas for Node failure resilience, design placement constraints such as topology spread constraints.

Control plane componentRoleWork in this example
API serverExposes the Kubernetes APIAccepts declarations from tools such as kubectl
etcdStores cluster state, including API objectsStores Deployment settings; it is separate from the application's book database
schedulerChooses Nodes for unassigned PodsFinds Nodes meeting resource requests and placement constraints
controller managerRuns reconciliation loopsControllers such as the ReplicaSet controller move actual state toward the target

On each Node, the kubelet manages Pod execution and starts containers through a runtime such as containerd. Separating the API entry point, placement decision, and local execution makes the architecture easier to follow.

3. Deployment, ReplicaSet, and Pod: who maintains the count?

Creating a bare Pod does not attach a controller to replace it after deletion. For a stateless API, use a Deployment to declare a Pod template, replica count, and update strategy. The Deployment manages ReplicaSets, and each ReplicaSet maintains the count of its Pods.

Figure 2: arrows show management relationships. Deployments and ReplicaSets do not relay application requests.

Deployment: template and updates → ReplicaSet: maintain this template's count → Pods A, B, C: run containers

Figure 3: replacement after deleting one Pod, assuming a suitable Node and a retrievable image.
  1. API Pods: Pod B is deleted, leaving fewer than the required three
  2. Control plane: The ReplicaSet controller creates replacement Pod D
  3. Control plane: The scheduler chooses a Node for Pod D
  4. Kubelet on a Node: Through the runtime, fetch the image and start the container
  5. API Pods: Pod D finishes initialization and becomes Ready

Pod D is a different object from deleted Pod B and need not have the same IP. By contrast, if a container exits unexpectedly, the kubelet may restart it inside the same Pod according to restartPolicy. Distinguish container restart from Pod replacement. Detection and replacement take time; in-flight requests and in-memory application data are not automatically restored.

4. Service, labels, and Ingress: where does a request go?

If callers hard-code a Pod IP, replacement changes their destination. A Service provides a stable destination for a changing set of Pods. This example's ClusterIP Service receives a virtual IP within the cluster. With cluster DNS, an application in the same Namespace can use the name books-api.

A label is a tag on an object. Give the Pods app=books-api and use app=books-api in the Service selector. For a conventional selector-based Service, Pod addresses and readiness are reflected in EndpointSlices, and the networking implementation updates forwarding destinations. The Service does not choose Pods by their Deployment's name.

Figure 4: a logical external HTTP path. A Service abstracts destinations; it need not be a separate proxy Pod.

User's HTTP request → Ingress-configured LB or proxy → Choose Service books-api as the backend → One eligible Ready Pod: A, C, or D → API container in that Pod

An Ingress declares HTTP(S) routing rules from hosts and paths to Services. An Ingress controller and an actual load balancer or proxy must implement them. The diagram shows logical relationships: some implementations forward directly from a proxy to Pods without traversing the Service virtual IP. Check the actual path in your implementation. Gateway API is another option for configuring an entry point.

MechanismMain useWhat it needs
ClusterIP ServiceStable access inside the clusterCluster networking and a Service forwarding implementation
LoadBalancer ServiceExternal exposure through a load balancerA supporting load balancer implementation, often provided by a cloud
IngressChoose a Service by HTTP(S) host and pathA controller implementing the rules and infrastructure handling the traffic

5. Running versus Ready: can a newly started Pod accept traffic?

Running does not guarantee that an application can serve requests. Its container may be running while configuration or caches are still loading. Probes distinguish startup completion, readiness to accept requests, and conditions requiring a restart.

ProbeQuestionMain effect of failure
startupProbeHas startup completed?Restarts the container after the configured failure criteria; the other two probes wait for startup success
readinessProbeCan this container accept requests?Makes the Pod NotReady and excludes it from normal Service forwarding; this failure alone does not restart it
livenessProbeDoes this container need a restart?Restarts the container after the configured failure criteria
Figure 5: startup to serving traffic. All container readiness and required conditions must be met, then propagated to routing.
  1. API container: The process starts but is still initializing
  2. Kubelet probes: startupProbe succeeds; readiness and other probes can begin
  3. Kubelet probes: readinessProbe succeeds and Pod readiness conditions are met
  4. Service destinations: The Ready Pod is reflected in the traffic path
  5. Kubelet probes: Later readiness failure excludes it; that failure alone does not restart it

A liveness check that queries a shared database can restart every container during a temporary database slowdown. Startup connection bursts can then worsen the incident. Separate local faults that a restart can repair from dependency failures. If readiness includes a shared dependency, evaluate the effect of excluding every Pod together. Probe execution and routing updates have delays; the transition is not instantaneous.

6. Reading YAML: connect the Pod template to a Service selector

The following YAML expresses those relationships. It is a conceptual example assuming an existing books Namespace. The image URL is a placeholder, and the configuration has not been executed. To try it, supply an accessible image implementing the book API and /readyz on port 8080. Resource values are hypothetical, not recommendations.

apps/v1 Deployment and v1 Service example: startup, liveness, and surrounding production settings are omitted
apiVersion: apps/v1
kind: Deployment
metadata:
  name: books-api
  namespace: books
spec:
  replicas: 3
  selector:
    matchLabels:
      app: books-api
  template:
    metadata:
      labels:
        app: books-api
    spec:
      containers:
        - name: api
          image: registry.example.invalid/books-api:v1
          ports:
            - name: http
              containerPort: 8080
          readinessProbe:
            httpGet:
              path: /readyz
              port: http
          resources:
            requests:
              cpu: "100m"
              memory: "128Mi"
            limits:
              cpu: "500m"
              memory: "256Mi"
---
apiVersion: v1
kind: Service
metadata:
  name: books-api
  namespace: books
spec:
  type: ClusterIP
  selector:
    app: books-api
  ports:
    - port: 80
      targetPort: http

7. Namespace, ConfigMap, and Secret: scope and configuration

A Namespace scopes names and resources within a cluster. The books Service and a Service with the same name in another Namespace are distinct. Some resources, including Nodes and PersistentVolumes, are not namespaced. Namespaces alone do not isolate all traffic or permissions: use controls such as RBAC and NetworkPolicy supported by the networking implementation.

ConceptBook API exampleWhat to remember
NamespaceGroup the API and Service in booksDoes not by itself determine Node placement or network isolation
ConfigMapLog levels and non-confidential settingsKeep secrets out; separate environment configuration from the image
SecretDatabase passwords and API keysBase64 is not encryption; configure encryption at rest and least privilege separately

Updating a ConfigMap or Secret does not change environment variables in already running containers; those containers must restart to receive new values. Ordinary volume mounts receive updates eventually, but subPath mounts do not receive automatic updates, and the application must reread changed files. Treat permission to mount a Secret into a Pod as access to its confidential value.

8. Volumes, PVCs, and PVs: data that must outlive a Pod

Do not treat a container's writable layer or a Pod's temporary volume as durable storage. For example, emptyDir survives a container restart within the same Pod, but is lost when that Pod is deleted. PersistentVolumeClaims (PVCs) and PersistentVolumes (PVs) let storage have a lifetime separate from the Pod.

Figure 6: persistent storage references and bindings, not a sequence of network requests.

Pod: mount the storage → PVC: request size and access modes → PV: storage resource bound to the claim → Backing disk or shared file storage

A StorageClass describes a storage category and provisioning method for dynamic storage creation. A PVC does not guarantee simultaneous access from multiple Nodes: access modes, zones, and implementation matter. Whether backing storage survives PVC deletion depends on settings such as reclaimPolicy. Persistence is separate from backup; deletion and corruption still need a recovery design. If this API stores books in an external database, its API Pods do not each need a PVC.

9. Requests, limits, and HPA: adding Pods versus adding Nodes

Requests are inputs to placement; limits constrain execution. In Linux containers, CPU limits can cause throttling, while memory pressure can cause OOM termination. These are different behaviors. In the example, 100m is one tenth of a CPU core and 128Mi is 128 mebibytes. A request does not mean that amount is physically set aside exclusively for the application.

Figure 7: a hypothetical HPA change from three to five Pods. With spare Node capacity, no Node addition is needed.

HPA evaluates metrics → Change Deployment target from 3 to 5 → ReplicaSet creates extra Pods → No placement capacity: Pending; add Nodes separately → Start, become Ready, update routing, then serve

The Horizontal Pod Autoscaler (HPA) adjusts a target's desired Pod count using metrics such as CPU. For CPU utilization targets, CPU requests provide the denominator. A suitable metrics supply is also required. When adopting HPA, transfer replica-count management to it instead of continually applying a fixed replicas value from the earlier YAML. Reapplying replicas: 3 can reset the target that HPA increased. Adding Nodes is a separate mechanism; HPA alone does not create machines. Collection, placement, image retrieval, and initialization delay usable capacity. Consider scheduled scaling or spare capacity for predictable spikes.

More Pods can also mean more database connections or external API calls. In a hypothetical example, a connection pool capped at ten per Pod allows up to 30 connections with three Pods and 50 with five. Kubernetes does not necessarily adjust for an external database's limit. Choose Pod counts and concurrency from the application's overall budget.

10. Rolling updates: prepare new Pods before terminating old ones

Changing a Deployment's Pod template from v1 to v2 uses a new ReplicaSet during a rolling update, adjusting old and new counts in steps. The diagram assumes three desired replicas, maxSurge of one, and maxUnavailable of zero. Old Pods are not scaled down until new Pods are available, so spare capacity is needed temporarily.

Figure 8: one update step maintaining three available replicas. Including terminating Pods, more than four Pods can exist at once.
  1. Deployment: Prepare a ReplicaSet for the new template
  2. New v2 Pod: Start one extra v2 Pod and wait until it is available
  3. Deployment: Reduce the old ReplicaSet by one while watching availability
  4. Old v1 Pod: Routing removal proceeds while in-flight work finishes within the grace period
  5. Deployment: Repeat reconciliation until the target three replicas run v2

Rolling updates alone do not guarantee uninterrupted service. Correct readiness, sufficient capacity in remaining Pods, and graceful shutdown are required. Account for routing propagation and in-flight requests, and make sure the application receives termination signals and finishes cleanup within its grace period. A fixed sleep is not proof of safety: measure forwarding removal and shutdown times. Database schema changes must support both application versions during the transition.

Connect the terms: which stage should you inspect?

Observed stateInspect firstWhat this distinguishes
Pod is PendingPod events, requests, placement rules, Node capacityCreation may not yet have progressed to placement or startup
Running but not ReadyProbe results, initialization logs, container statusA started process versus one ready to receive requests
Ready but unreachable through the ServiceSelectors and labels, EndpointSlices, port/targetPort, network controlsTarget selection, port mapping, and traffic-path failures
Repeated container restartsExit reason, previous logs, OOM events, failed probesApplication faults, resource constraints, and restart decisions
Errors only during deploymentsForwarding to old Pods, shutdown logs, remaining capacity, DB connectionsCompare routing changes, shutdown, and capacity at the same time

Check your understanding: the Deployment declares three Pods, the Service supplies a stable name despite replacement, and readinessProbe checks whether initialization permits traffic. If you can explain those roles using Figures 2, 4, and 5, you have connected the core concepts. The related Tips below go deeper into probe design, resource constraints, scaling delays, secret configuration, and shutdown.

References: official Kubernetes documentation

These official concept pages were checked on October 26, 2026. The diagrams are original explanatory models for the book-list API, not observations from a running environment. Check feature availability and actual networking and storage behavior against your Kubernetes version and implementation.

Tips this post digs into