Kubernetes becomes much easier to understand once Pods, Deployments, ReplicaSets, and Services are viewed as different layers rather than interchangeable objects. Pods run containers. ReplicaSets maintain a desired number of matching Pods. Deployments manage ReplicaSets and application rollouts. Services give changing sets of Pods a stable network identity.
This object relationship is foundational for the current KCNA certification and the wider Linux Foundation certifications path. The existing Kubernetes fundamentals is useful background; this article focuses specifically on how the workload and service objects fit together at runtime.
Pods are the unit that actually runs containers
A Pod is the smallest deployable compute object in Kubernetes. A Pod can contain one or more containers that share a network namespace and can share mounted storage. Containers inside the same Pod can communicate over localhost, and the Pod receives its own cluster network identity.
Pods are intentionally disposable. A failed Pod is usually replaced rather than repaired in place. Its replacement can receive a different name and IP address. That design is why applications should not depend on the identity of one particular Pod unless a higher-level workload model provides stable identity.
You can create a Pod directly, but production applications are normally managed through workload controllers. A controller continuously compares desired state with actual state and creates or removes Pods to close the gap. That reconciliation behavior is one of the most important ideas in Kubernetes.
ReplicaSets keep the desired number of Pods running
A ReplicaSet declares how many replicas of a Pod template should exist and uses a label selector to identify the Pods it manages. If a matching Pod disappears, the ReplicaSet creates another. If too many matching Pods exist, it can remove excess replicas.
In normal application delivery, administrators rarely manage ReplicaSets directly. A Deployment creates and manages ReplicaSets on behalf of the application. Understanding ReplicaSets is still essential because rollout behavior, revision history, and troubleshooting frequently surface them.
Selectors must be designed carefully. A controller identifies its Pods through labels, not through a hidden parent pointer that magically prevents overlap. If multiple controllers use overlapping selectors, they can conflict. The labels in a workload’s Pod template therefore form part of the control contract.
Deployments manage stateless application rollouts
A Deployment is the common controller for stateless application workloads. Its specification contains a Pod template, a selector, a desired replica count, and rollout behavior. The Deployment controller creates a ReplicaSet, which then creates the Pods.
When the Pod template changes—for example, because the image digest or environment configuration changes—the Deployment normally creates a new ReplicaSet. It scales the new ReplicaSet up and the old one down according to the rollout strategy. Old ReplicaSets can be retained at zero replicas so the Deployment has revision history for rollback.
This layering explains a common troubleshooting clue: during a rollout, one Deployment can temporarily own multiple ReplicaSets even though only the newest should eventually have running Pods. Looking only at kubectl get pods can hide the controller-level reason those Pods exist.
Services solve the problem of changing Pod addresses
Pods are replaceable, and their IP addresses can change. A client should not need to rediscover backend Pod addresses every time a Deployment rolls out. A Kubernetes Service provides a stable abstraction in front of a logical set of endpoints, typically selected from Pods by labels.
The Service API defines how clients reach the backend group. The default ClusterIP type provides a stable cluster-internal virtual address. NodePort exposes a port on cluster nodes, while LoadBalancer can integrate with a supported infrastructure provider to provision external load balancing. Headless Services deliberately omit a virtual cluster IP for discovery patterns that need direct endpoint visibility.
Kubernetes tracks current Service backends through EndpointSlice objects. As Pods appear, disappear, or change readiness, the endpoint data can change while the Service identity remains stable.
Labels connect Services to workloads
A Service does not need to know that a Deployment exists. It usually selects Pods using labels. The Deployment’s Pod template applies those labels, and the Service selector matches them. This loose coupling is powerful because any Pod with the right labels can become an endpoint, regardless of which controller created it.
It is also a frequent source of outages. A typo in a Service selector can produce a Service with no usable backends even while every Pod is healthy. A rollout that changes Pod labels without updating the Service selector can create the same symptom. Troubleshooting should therefore include both workload status and endpoint selection.
Use kubectl get svc, kubectl get endpointslices, and label-aware Pod queries to verify that the network abstraction actually points to the intended workloads.
Readiness is different from simply running
A Pod can be in the Running phase while its application is not ready to receive traffic. Readiness probes let Kubernetes distinguish a live process from a backend that should participate in service traffic. A new Pod can start, initialize caches or connections, and become ready only when it can safely handle requests.
This distinction matters during rolling updates. Deployment availability depends on Pods becoming ready, and Services should route to appropriate endpoints rather than treating process existence as application health. A poorly designed readiness probe can either send traffic too early or keep healthy applications out of service.
Liveness and startup probes have different purposes. They can trigger container restarts or protect slow startup, but they should not be used as interchangeable versions of readiness. The controller and networking layers react to these signals differently.
Deployments are not the answer for every workload
Deployments assume that replicas are broadly interchangeable. That fits many web APIs, stateless workers, and front-end applications. Workloads that need stable network identity, ordered rollout behavior, or persistent identity across restarts may fit StatefulSets better.
Persistent storage is also a separate Kubernetes concern. PersistentVolumeClaims explain how workloads request durable storage. A Deployment can mount a claim, but storage semantics can limit whether multiple replicas can safely use the same volume.
Jobs and CronJobs are better for run-to-completion work, while DaemonSets are designed to place Pods across selected nodes. The Kubernetes workload API exists because different application behaviors need different controllers.
Helm packages objects but does not replace their semantics
Helm can template and install Deployments, Services, ConfigMaps, and many other Kubernetes resources. Helm charts show why packaging is useful, but Helm does not change the relationships among the underlying Kubernetes objects.
When a chart deployment fails, troubleshoot the generated resources at their native layers. Confirm that the Deployment has a healthy ReplicaSet, the ReplicaSet has the intended Pods, the Pods are ready, and the Service selects those Pods. A packaging tool can create the objects correctly or incorrectly; Kubernetes controllers still determine runtime behavior.
This mental model is more durable than memorizing commands because it explains why each object exists and which controller is responsible when desired state is not achieved.
Trace failures from the highest layer down
For a typical stateless application, start with the Deployment: is the desired rollout progressing and are the expected replicas available? Next inspect its ReplicaSets: is the new revision scaling as intended, and is an old revision unexpectedly active? Then inspect Pods for scheduling, image, readiness, or runtime errors.
If clients cannot connect while Pods are healthy, move to the Service and EndpointSlices. Check selectors, ports, target ports, and backend readiness. This layered troubleshooting path prevents random command execution and connects symptoms to the controller responsible for that part of the system.
The core relationship is worth remembering: Deployment manages ReplicaSets, ReplicaSets manage matching Pods, and Services provide a stable way to reach selected Pods. Once that model is clear, much of Kubernetes workload behavior becomes predictable.
Scaling reinforces the separation of responsibilities. Increasing a Deployment’s desired replicas causes its active ReplicaSet to create more Pods; the Service does not need to be reconfigured because its selector can discover the new matching backends. A HorizontalPodAutoscaler can adjust replica count from observed metrics, but the Deployment still remains the workload controller and the Service still remains the networking abstraction. This modularity is one reason Kubernetes can change capacity without requiring clients to understand individual Pod identity.
Resource ownership is also visible in metadata. Kubernetes uses owner references so garbage collection can clean up dependent resources such as ReplicaSets created by a Deployment, while selectors determine which Pods controllers manage. These mechanisms solve different problems. An owner reference expresses lifecycle ownership; a selector expresses membership. Mixing them up can make troubleshooting confusing because a Service can select a Pod it does not own, while a Deployment can own a ReplicaSet whose current Pods are not reachable through any Service.
A final KCNA-level distinction is desired state versus current state. The Deployment specification says what should exist; status fields report what the controllers have actually achieved. ReplicaSet desired/current/ready counts and Deployment available/up-to-date counts can diverge during rollouts or failures. Reading those fields as reconciliation progress is more useful than treating Kubernetes objects as static configuration files. The control plane is constantly trying to close the difference between specification and observed reality.