Understanding Pods, Deployments, and Services in Kubernetes
Kubernetes can feel like a complex ecosystem, but once you understand its building blocks, everything starts to make sense. In this article, we’ll explore the three most fundamental components in Kubernetes: Pods, Deployments, and Services. By the end, you’ll have a solid understanding of how your applications are deployed, managed, and exposed in a Kubernetes cluster. What is a Pod? A Pod is the smallest and most basic deployable unit in Kubernetes. A Pod represents a single instance of a running process in your cluster. Key Characteristics: A Pod can contain one or more containers (usually one). Containers in a Pod share: The same network namespace (same IP address and port space). The same storage volumes, if defined. Think of a Pod as a wrapper around one or more tightly coupled containers that must run together. Why Pods? Pods are useful for: Running a containerized app. Grouping helper containers (like logging agents) with the main container. Examples - Simple Pod: apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx-container image: nginx:latest ports: - containerPort: 80 Pod with Volumes, Multiple Containers including init containers and environment variables: apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app.kubernetes.io/name: MyApp spec: containers: - name: myapp-container image: busybox:1.28 command: ['sh', '-c', 'echo The app is running! && sleep 3600'] env: - name: ENVIRONMENT value: "production" - name: CONFIG_FILE value: "/etc/config/app.conf" volumeMounts: - name: config-vol mountPath: /etc/config initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"] volumes: - name: config-vol configMap: name: log-config items: - key: log_level path: log_level.conf Manifest breakup for better understanding Here are breakdowns for the components used in the above manifest: Environment Variables env: - name: DEMO_GREETING value: "Hello from the environment" - name: DEMO_FAREWELL value: "Such a sweet sorrow" Volumes Volumes are defined in the volumes section of the manifest. They can be used/mounted by one or more containers in the Pod. volumeMounts: - name: config-vol mountPath: /etc/config volumes: - name: config-vol configMap: name: log-config items: - key: log_level path: log_level.conf Init Containers Init containers are used to perform setup tasks before the main containers in the Pod start. initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"] What is a Deployment? While a Pod is great, it’s not self-healing. If a Pod crashes, it won’t come back automatically. That’s where a Deployment comes in. A Deployment is a higher-level abstraction that manages Pods and ReplicaSets for you. Key Benefits: Ensures desired state is maintained (e.g., always 3 replicas running). Supports rolling updates and rollbacks. Automatically replaces failed Pods. Examples: Simple Deployment: apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.25 ports: - containerPort: 80 Note: Most of the fields in the Deployment manifest are the same as in a Pod manifest. The key difference is that in a Deployment, you specify the number of replicas you want to run. It is specified in the replicas field. Deployment with Volumes, Multiple Containers including init containers and environment variables: apiVersion: apps/v1 kind: Deployment metadata: name: demo-app labels: app: demo spec: replicas: 2 selector: matchLabels: app: demo template: metadata: labels: app: demo spec:

Kubernetes can feel like a complex ecosystem, but once you understand its building blocks, everything starts to make sense. In this article, we’ll explore the three most fundamental components in Kubernetes: Pods, Deployments, and Services.
By the end, you’ll have a solid understanding of how your applications are deployed, managed, and exposed in a Kubernetes cluster.
What is a Pod?
A Pod is the smallest and most basic deployable unit in Kubernetes. A Pod represents a single instance of a running process in your cluster.
Key Characteristics:
- A Pod can contain one or more containers (usually one).
- Containers in a Pod share:
- The same network namespace (same IP address and port space).
- The same storage volumes, if defined.
Think of a Pod as a wrapper around one or more tightly coupled containers that must run together.
Why Pods?
Pods are useful for:
- Running a containerized app.
- Grouping helper containers (like logging agents) with the main container.
Examples -
- Simple Pod:
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx-container
image: nginx:latest
ports:
- containerPort: 80
- Pod with Volumes, Multiple Containers including init containers and environment variables:
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app.kubernetes.io/name: MyApp
spec:
containers:
- name: myapp-container
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
env:
- name: ENVIRONMENT
value: "production"
- name: CONFIG_FILE
value: "/etc/config/app.conf"
volumeMounts:
- name: config-vol
mountPath: /etc/config
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"]
- name: init-mydb
image: busybox:1.28
command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
volumes:
- name: config-vol
configMap:
name: log-config
items:
- key: log_level
path: log_level.conf
Manifest breakup for better understanding
Here are breakdowns for the components used in the above manifest:
Environment Variables
env: - name: DEMO_GREETING value: "Hello from the environment" - name: DEMO_FAREWELL value: "Such a sweet sorrow"
Volumes
Volumes are defined in the
volumes
section of the manifest. They can be used/mounted by one or more containers in the Pod.volumeMounts: - name: config-vol mountPath: /etc/config volumes: - name: config-vol configMap: name: log-config items: - key: log_level path: log_level.conf
Init Containers
Init containers are used to perform setup tasks before the main containers in the Pod start.
initContainers: - name: init-myservice image: busybox:1.28 command: ['sh', '-c', "until nslookup myservice.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for myservice; sleep 2; done"] - name: init-mydb image: busybox:1.28 command: ['sh', '-c', "until nslookup mydb.$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local; do echo waiting for mydb; sleep 2; done"]
What is a Deployment?
While a Pod is great, it’s not self-healing. If a Pod crashes, it won’t come back automatically. That’s where a Deployment comes in.
A Deployment is a higher-level abstraction that manages Pods and ReplicaSets for you.
Key Benefits:
- Ensures desired state is maintained (e.g., always 3 replicas running).
- Supports rolling updates and rollbacks.
- Automatically replaces failed Pods.
Examples:
- Simple Deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
Note: Most of the fields in the Deployment manifest are the same as in a Pod manifest. The key difference is that in a Deployment, you specify the number of replicas you want to run. It is specified in the replicas
field.
- Deployment with Volumes, Multiple Containers including init containers and environment variables:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-app
labels:
app: demo
spec:
replicas: 2
selector:
matchLabels:
app: demo
template:
metadata:
labels:
app: demo
spec:
volumes:
- name: shared-data
emptyDir: {}
- name: config-volume
configMap:
name: demo-config
initContainers:
- name: init-myservice
image: busybox
command: ['sh', '-c', 'echo "Initializing..." > /mnt/data/init.log']
volumeMounts:
- name: shared-data
mountPath: /mnt/data
containers:
- name: demo-container
image: nginx:1.25
ports:
- containerPort: 80
env:
- name: ENVIRONMENT
value: "production"
- name: CONFIG_FILE
value: "/etc/config/app.conf"
volumeMounts:
- name: shared-data
mountPath: /usr/share/nginx/html/init
- name: config-volume
mountPath: /etc/config
readOnly: true
---
#configmap-manifest
apiVersion: v1
kind: ConfigMap
metadata:
name: demo-config
data:
app.conf: |
server {
listen 80;
location / {
return 200 "Hello from ConfigMap!";
}
}
Some more manifest breakups for better understanding
Shared Volumes
Same volumes can be shared by multiple containers in a Pod. This is useful for sharing data between containers in the same Pod.
volumes: - name: shared-data emptyDir: {} initContainers: - volumeMounts: - name: shared-data mountPath: /mnt/data containers: - volumeMounts: - name: shared-data mountPath: /usr/share/nginx/html/init
Configmap as volumes
ConfigMaps can be used in two primary ways:
- As environment variables
- As volumes (mounted files inside your container) In this example, we've mounted it as a volume - for configmap manifest, refer to the
#configmap-manifest
section in the above manifest.volumes: - name: config-volume configMap: name: demo-config containers: - volumeMounts: - name: config-volume mountPath: /etc/config readOnly: true
Once deployed, inside the container you’ll have:
/etc/config/app.conf
This config file is then used by the container to configure the application using environment variable.
containers: - env: - name: CONFIG_FILE value: "/etc/config/app.conf"
Note: Mounting ConfigMap as a volume makes the config read-only by default, which is a nice security feature.
What is a Service?
A Service in Kubernetes exposes your Pods to other applications inside (or outside) the cluster.
Types of Services:
- ClusterIP (default): Internal communication only.
- NodePort: Exposes the service on a port on each node.
- LoadBalancer: Exposes the service externally using a cloud provider's load balancer.
- ExternalName: Maps the service to an external DNS name.
Example (NodePort):
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
type: NodePort
selector:
app: nginx
ports:
- port: 80
targetPort: 80
nodePort: 30007
This will expose your nginx deployment on http://:30007.
Putting it All Together: A Practical Example
Here’s an example to deploy Nginx and expose it via a NodePort service.