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 Variablesenv: - name: DEMO_GREETING value: "Hello from the environment" - name: DEMO_FAREWELL value: "Such a sweet sorrow"
VolumesVolumes 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 ContainersInit 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
NOTEMost 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 VolumesSame 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 volumesConfigMaps 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"
NOTEMounting 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://
Putting it All Together: A Practical Example
Here’s an example to deploy Nginx and expose it via a NodePort service.
🧩 Create the Deployment
kubectl create deploy nginx --image=nginx
🧪 Check the Pods
kubectl get pods
🌐 Create the Service
kubectl expose deploy nginx --name=nginx-service --port=30007 --target-port=80 --type=NodePort
🌍 Access the App
minikube service nginx-service
Or manually:
minikube ip
Visit http://
TIP
- You can use
kubectl apply -f --dry-run=client -o <file>
to validate manifests before applying.- You can use
kubectl <remaining-command> --dry-run=client -o yaml
to generate a manifest.
Final Thoughts
Pods, Deployments, and Services form the core trio of any Kubernetes application.
Pods are your running containers.
Deployments manage your Pods at scale and keep them healthy.
Services make sure your application is reachable—internally or externally.
Understanding these three concepts is crucial for progressing in your Kubernetes journey. Once you’ve mastered them, you’ll be ready to move on to more advanced topics like ConfigMaps, Secrets, Ingress, Volumes, and beyond.
Next up: In the upcoming article, we’ll explore Ingress controllers, how to handle configurations with ConfigMaps, and persistent storage in Kubernetes.
Until then, keep learning and stay secure! 🚀