Kubernetes in 30 Minutes: Pods, Deployments and Services
This article provides a concise introduction to the fundamental building blocks of Kubernetes: Pods, Deployments, and Services. Understanding these core…
This article provides a concise introduction to the fundamental building blocks of Kubernetes: Pods, Deployments, and Services. Understanding these core abstractions is crucial for deploying and managing containerized applications effectively within a Kubernetes cluster. We will explore their roles, interrelationships, and practical application through command-line examples and YAML definitions.
Pods: The Atomic Unit of Deployment
A Pod is the smallest deployable unit in Kubernetes. It represents a single instance of a running process in your cluster. Pods are designed to encapsulate one or more closely related containers that share resources like network interfaces, storage volumes, and IPC namespaces. While a Pod can contain multiple containers, it's generally best practice to run a single primary container per Pod, with helper containers (sidecars) for tasks like logging, metrics collection, or configuration synchronization.
Key characteristics of Pods:
- Shared Network Namespace: All containers within a Pod share the same IP address and port space. They can communicate with each other using
localhost. - Shared Storage: Pods can define shared storage volumes that all containers within the Pod can access, enabling data sharing or persistent storage.
- Ephemeral: Pods are inherently ephemeral. If a Pod dies (e.g., due to a node failure or a container crash), Kubernetes does not automatically restart it. Higher-level abstractions manage their lifecycle.
- Resource Limits: You can define CPU and memory requests and limits for containers within a Pod, helping the Kubernetes scheduler place them efficiently and prevent resource starvation.
Example Pod Definition (for illustration, rarely deployed directly)
While you rarely create Pods directly, understanding their structure is vital.
apiVersion: v1
kind: Pod
metadata:
name: my-nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx:1.27.0 # Specify a precise version
ports:
- containerPort: 80
name: http-port
resources:
requests:
memory: "64Mi"
cpu: "250m" # 250 milliCPU = 0.25 CPU core
limits:
memory: "128Mi"
cpu: "500m"
- name: busybox-sidecar
image: busybox:1.36.1
command: ["sh", "-c", "while true; do sleep 30; done"] # Keep sidecar running
In this example, two containers, nginx-container and busybox-sidecar, share the same network namespace.
The Nginx container exposes port 80. Resource requests and limits are defined for the Nginx container.
Deployments: Managing Replicas and Updates
Deployments are a higher-level abstraction that provide declarative updates for Pods and ReplicaSets. They manage the desired state of your application, ensuring that a specified number of Pod replicas are always running. Deployments handle rolling updates, rollbacks, and scaling.
Key functionalities of Deployments:
- Replica Management: A Deployment ensures that a specified number of Pod replicas are running at all times, even if Pods fail. It does this by managing ReplicaSets.
- Declarative Updates: You define the desired state of your application (e.g., new image version, new configuration), and the Deployment controller intelligently updates your Pods.
- Rolling Updates: Deployments support zero-downtime rolling updates by gradually replacing old Pods with new ones, ensuring continuous application availability.
- Rollbacks: If a new deployment introduces issues, you can easily roll back to a previous stable version.
- Scaling: You can easily scale your application up or down by changing the
replicasfield in the Deployment specification.
Deployment Specification
The Deployment object defines the desired state of your application.
The selector field is crucial for the Deployment to know which Pods it manages.
The template field contains the Pod definition that the Deployment will create.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-deployment
labels:
app: web
spec:
replicas: 3 # Desired number of Pod replicas
selector:
matchLabels:
app: web # This selector must match the Pod template's labels
template:
metadata:
labels:
app: web # Labels applied to the Pods created by this Deployment
spec:
containers:
- name: web-container
image: nginx:1.27.0 # Specify a precise image version
ports:
- containerPort: 80
env:
- name: MESSAGE
value: "Hello from Kubernetes!"
affinity: # Example of Pod affinity rule
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: "kubernetes.io/hostname" # Try to spread Pods across nodes
strategy: # Rolling update strategy (default)
type: RollingUpdate
rollingUpdate:
maxUnavailable: 25% # Max number of Pods unavailable during update
maxSurge: 25% # Max number of Pods that can be created above desired count
In this YAML, we define a Deployment named web-deployment that will ensure 3 replicas of our Nginx application are running.
The Pods generated by this Deployment will have the label app: web, which matches the Deployment's selector.
We've also included a simple MESSAGE environment variable and an anti-affinity rule to encourage spreading Pods across different nodes.
Common Deployment Operations
- Apply the Deployment:
kubectl apply -f web-deployment.yaml - Check Deployment status:
kubectl get deploy web-deployment - View Pods managed by Deployment:
kubectl get pods -l app=web - Scale up/down:
kubectl scale deployment web-deployment --replicas=5 - Perform a rolling update: Update the image in
web-deployment.yaml(e.g., fromnginx:1.27.0tonginx:1.28.0) and runkubectl apply -f web-deployment.yamlagain. - Check deployment history:
kubectl rollout history deployment/web-deployment - Rollback to previous revision:
kubectl rollout undo deployment/web-deployment
Services: Stable Network Endpoints
Pods are ephemeral and can be created or destroyed at any time, leading to dynamic IP addresses. This makes direct communication with Pods challenging. A Kubernetes Service provides a stable network endpoint (a static IP address and DNS name) for a set of Pods. It acts as an abstraction layer, routing traffic to the healthy Pods that match its selector.
Key features of Services:
- Stable IP and DNS: Services provide a fixed virtual IP address and a DNS name within the cluster, making it easy for other applications to discover and communicate with your Pods.
- Load Balancing: Services distribute incoming network traffic across all healthy Pods that match its selector.
- Decoupling: Services decouple your application's consumer from its backend Pods, allowing Pods to be scaled, replaced, or upgraded without impacting the consumer.
- Service Discovery: Kubernetes automatically updates DNS entries and IP tables to reflect changes in Pods backing a Service.
Service Types
Kubernetes offers several Service types, each serving a different purpose:
- ClusterIP (Default): Exposes the Service on an internal IP in the cluster. It's only reachable from within the cluster. This is suitable for internal microservices communication.
- NodePort: Exposes the Service on a static port (the NodePort) on each Node's IP address. This makes the Service accessible from outside the cluster via
<NodeIP>:<NodePort>. Kubernetes usually picks a port from a high range (e.g., 30000-32767). - LoadBalancer: Exposes the Service externally using a cloud provider's load balancer. This type provisions an external IP address that acts as the entry point to your application. This is primarily used in cloud environments (AWS, GCE, Azure, etc.).
- ExternalName: Maps the Service to the contents of the
externalNamefield (e.g.,my.database.example.com) by returning aCNAMErecord. No proxying or internal IP is allocated.
Service Specification
The selector field in a Service is critical. It determines which Pods the Service will route traffic to, based on their labels.
apiVersion: v1
kind: Service
metadata:
name: web-service
labels:
app: web
spec:
selector:
app: web # Matches Pods with label app: web
ports:
- protocol: TCP
port: 80 # Port the Service listens on
targetPort: 80 # Port the Pod container listens on (containerPort)
name: http
type: ClusterIP # Or NodePort, LoadBalancer
sessionAffinity: None # Or ClientIP for sticky sessions
This web-service will forward TCP traffic from port 80 to port 80 on any Pods that have the label app: web.
Since its type is ClusterIP, it will only be reachable within the cluster.
Combined Deployment and Service Example (from stub)
This YAML combines a Deployment and a Service to create a web application.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: web
image: nginx:1.27.0 # Using a specific Nginx version
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: web
spec:
selector:
app: web
ports:
- port: 80
targetPort: 80
protocol: TCP
name: http
type: ClusterIP # Default, but explicitly stated
To deploy this:
kubectl apply -f web.yaml
Verify the deployment and service:
kubectl get deployments,pods,services -l app=web
You should see the web Deployment, 3 web Pods, and the web Service.
To interact with the service from within the cluster (e.g., from another Pod), you can use http://web:80.
Interaction and Lifecycle
The relationship between these three core components is hierarchical:
- You define a Deployment, which specifies the desired state for your application's Pods (e.g., image, replica count, resource limits).
- The Deployment creates and manages Pods (via ReplicaSets), ensuring the specified number of healthy replicas are running.
- A Service provides a stable network entry point and load balancing across the Pods managed by the Deployment, based on their labels.
When a Pod needs to be replaced (e.g., during a rolling update, or if it crashes), the Deployment creates a new Pod. The Service automatically updates its internal endpoint list to include the new Pod and remove the old one, ensuring seamless connectivity.
Common Pitfalls and Troubleshooting
- Label Mismatch: The most common error is a mismatch between a Deployment's
selector.matchLabels(or the Pod template'smetadata.labels) and a Service'sspec.selector. If these don't match, the Service won't find any Pods to route traffic to. Usekubectl get endpoints <service-name>to check if endpoints are present. - Incorrect
targetPort: Ensure thetargetPortin your Service definition matches thecontainerPortexposed by your application inside the Pod. - Image Pull Errors: Pods can remain in
ImagePullBackOfforErrImagePullstate if the image name is wrong, the tag doesn't exist, or credentials are required for a private registry. Checkkubectl describe pod <pod-name>andkubectl logs <pod-name>. - Readiness/Liveness Probes: Without proper liveness and readiness probes, Kubernetes might send traffic to an unready Pod or not restart a stuck one. Add these to your Pod specification in the Deployment.
- Resource Constraints: Pods can fail to schedule (
Pendingstatus) if nodes don't have enough resources (CPU, memory) to satisfy their requests. Checkkubectl describe pod <pod-name>for scheduling events. - Service Visibility: A
ClusterIPService is not directly accessible from outside the cluster. If external access is needed, useNodePortorLoadBalancer, or an Ingress controller.