An introductory course on Kubernetes Pods, their design, deployment, and administration.
Table of Contents
- Kubernetes Ecosystem Overview
- Module 1 — Defining Kubernetes Pods
- Module 2 — Deploying and Administering Pods
- Pod Lifecycle
- Init Containers
- Probes — Liveness, Readiness, Startup
- Resource Requests and Limits
- Reference Tables
- Reference YAML Snippets
- Essential kubectl Commands
1. Kubernetes Ecosystem Overview
A Pod is the smallest deployable unit in Kubernetes. It represents an instance of a running process in a cluster and can contain one or more tightly coupled containers that share network, storage, and lifecycle.
Key Components Surrounding Pods
| Component | Role |
|---|---|
| Cluster | Execution environment where Pods are deployed |
| Deployment | Defines the desired state for Pods (replica count, image, etc.) |
| ReplicaSet | Created by the Deployment — guarantees the correct number of Pods is always running |
| Service | Exposes Pods on the network, handles load balancing and service discovery |
| ConfigMap | Stores configuration data (env vars, CLI args) separately from application code |
| PersistentVolume | Provides reliable access to stable data resources (e.g., databases) for stateful Pods |
flowchart TD
User([User / kubectl]) --> Deployment
Deployment --> RS[ReplicaSet]
RS --> Pod1[Pod 1]
RS --> Pod2[Pod 2]
RS --> Pod3[Pod 3]
Pod1 --> Container1[Container app]
Pod2 --> Container2[Container app]
Pod3 --> Container3[Container app]
SVC[Service\nLoad Balancer] --> Pod1
SVC --> Pod2
SVC --> Pod3
CM[ConfigMap] -.->|env vars| Pod1
PV[PersistentVolume] -.->|storage| Pod1
style Pod1 fill:#326ce5,color:#fff
style Pod2 fill:#326ce5,color:#fff
style Pod3 fill:#326ce5,color:#fff
style SVC fill:#f0ad4e,color:#000
style RS fill:#5bc0de,color:#000
style Deployment fill:#5cb85c,color:#fff
2. Module 1 — Defining Kubernetes Pods
Pod Anatomy
A Pod encapsulates one or more containers, shared volumes, and a common network configuration. All containers in the same Pod share the same IP address and network namespace (localhost between them).
graph TB
subgraph POD["Pod (Kubernetes atomic unit)"]
direction TB
subgraph NET["Shared network namespace"]
IP["Unique Pod IP\n(e.g.: 10.244.0.5)"]
end
subgraph C1["Main container\n(e.g.: Flask app)"]
P1["Port 5000"]
end
subgraph C2["Sidecar container\n(e.g.: log shipper)"]
P2["Port 8080"]
end
subgraph VOL["Shared volumes"]
V1["emptyDir\n/var/log"]
V2["Projected Volume\n/var/run/secrets"]
end
NET --> C1
NET --> C2
C1 --> VOL
C2 --> VOL
end
style POD fill:#e8f4f8,stroke:#326ce5,stroke-width:2px
style NET fill:#dff0d8,stroke:#3c763d
style C1 fill:#326ce5,color:#fff
style C2 fill:#5bc0de,color:#000
style VOL fill:#fcf8e3,stroke:#8a6d3b
Designing a Single-Container Pod
The simplest and most common Pod type. The value lies in the ephemeral nature of the Pod: if a Pod fails, the Deployment automatically replaces it, often imperceptibly to users.
Single-container Pod YAML manifest structure:
apiVersion: v1
kind: Pod
metadata:
name: simple-app
labels:
app: simple-app
spec:
containers:
- name: simple-app
image: myrepo/simple-app:latest
ports:
- containerPort: 5000
Pre-deployment validation (dry-run):
# Client-side dry-run
kubectl apply -f pod.yaml --dry-run=client
# Server-side dry-run (checks compatibility with admission controllers)
kubectl apply -f pod.yaml --dry-run=server
kubectl applyvskubectl create
kubectl apply: creates or updates the targeted resourcekubectl create: creates a new resource — fails if a previous version exists
Designing a Multi-Container Pod
A multi-container Pod groups two or more containers that collaborate closely. The most common pattern is the sidecar pattern: a main container and an auxiliary container (e.g., log collection).
Example: Flask app + logging sidecar
apiVersion: v1
kind: Pod
metadata:
name: multi-container-app
labels:
app: multi-container-app
spec:
containers:
- name: simple-app
image: myrepo/simple-app:latest
ports:
- containerPort: 5000
- name: log-sidecar
image: busybox
command: ["/bin/sh", "-c"]
args:
- while true; do
echo "$(date) - Log event from sidecar";
sleep 5;
done
Common multi-container patterns:
| Pattern | Description |
|---|---|
| Sidecar | Auxiliary container extending main container capabilities (logs, monitoring) |
| Ambassador | Proxies the main container’s network connections to the outside |
| Adapter | Transforms main container output to normalize it |
3. Module 2 — Deploying and Administering Pods
Launching Pods with kubectl
# Deploy a Pod from a manifest
kubectl apply -f pod.yaml
# List active Pods
kubectl get pods
# List Pods with more details
kubectl get pods -o wide
# Describe a Pod (status, conditions, events)
kubectl describe pod simple-app
# Port-forwarding to access container locally
kubectl port-forward pod/simple-app 5000:5000
# Read logs from a specific container
kubectl logs multi-container-app -c simple-app
kubectl logs multi-container-app -c log-sidecar
# Delete a Pod
kubectl delete pod simple-app
Updating a Running Pod
To update a standalone Pod (created directly, without a Deployment):
# 1. Modify the application code
# 2. Rebuild and push the Docker image
docker build -t myrepo/simple-app:latest .
docker push myrepo/simple-app:latest
# 3. Delete the old Pod (kubectl apply doesn't work for standalone Pods)
kubectl delete pod simple-app
# 4. Recreate the Pod with the new image
kubectl apply -f pod.yaml
Important: For Pods managed by a Deployment or ReplicaSet,
kubectl applyhandles progressive non-destructive replacement (rolling update), avoiding service interruptions. This is why Deployments are preferred over standalone Pods in production.
Scaling Pods with Deployments
A Deployment defines the desired number of replicas. If a Pod fails, the ReplicaSet automatically creates a new one as replacement.
Deployment manifest with 3 replicas:
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment1
spec:
replicas: 3
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: my-container
image: nginx:1.27.3
ports:
- containerPort: 80
Scaling commands:
# Deploy the Deployment
kubectl apply -f deployment1.yaml
# List Deployments
kubectl get deployments
# Scale via command line (without modifying YAML)
kubectl scale deployment deployment1 --replicas=5
# Scale to 0 (stops the Deployment without deleting it)
kubectl scale deployment deployment1 --replicas=0
Scheduling and Security Context
In Kubernetes, scheduling refers to placing Pods on cluster nodes. Since nodes have different hardware and software profiles, scheduling allows associating workloads with the most appropriate nodes.
Snippet with Security Context and resource constraints:
spec:
securityContext:
fsGroup: 2000 # GID for mounted volumes (applies to all containers)
containers:
- name: secure-container
image: nginx:latest
securityContext:
runAsUser: 1000 # UID under which the container runs
runAsGroup: 3000 # GID under which the container runs
allowPrivilegeEscalation: false # Forbids privilege escalation
readOnlyRootFilesystem: true # Read-only root filesystem
capabilities:
drop:
- ALL # Drop all Linux capabilities
add:
- NET_BIND_SERVICE # Only allow binding to network ports
resources:
requests: # Minimum required resources
memory: "64Mi"
cpu: "250m"
limits: # Resource ceiling
memory: "128Mi"
cpu: "500m"
nodeSelector:
disktype: ssd # Deploy only on nodes with label disktype=ssd
4. Pod Lifecycle
stateDiagram-v2
[*] --> Pending : kubectl apply
Pending --> Running : Containers started successfully
Pending --> Failed : Cannot pull image / init error
Running --> Succeeded : All containers exited with code 0
Running --> Failed : At least one container exited with non-0 code
Running --> Unknown : Lost communication with Node
Succeeded --> [*]
Failed --> Pending : restartPolicy = Always or OnFailure
note right of Pending
- Scheduling in progress
- Image pull in progress
- Init containers running
end note
note right of Running
- At least one container active
- Liveness probes active
end note
note right of Succeeded
- All containers terminated
- Exit code = 0
- Typical for Jobs
end note
Pod Phases
| Phase | Description |
|---|---|
| Pending | Pod accepted by cluster but one or more containers not yet started |
| Running | Pod is bound to a node and at least one container is running |
| Succeeded | All containers terminated successfully (exit code 0) — typical for Jobs |
| Failed | All containers terminated and at least one failed (non-0 exit code) |
| Unknown | Pod state cannot be determined, usually due to node communication error |
5. Init Containers
Init containers are special containers that run before the main application containers. They must complete successfully before application containers can start.
Common use cases:
- Wait for a dependent service to be available
- Pre-configure the filesystem
- Clone a Git repository
- Perform database migrations
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
initContainers:
- name: init-wait-db
image: busybox
command: ['sh', '-c',
'until nc -z postgres-service 5432; do
echo "Waiting for database...";
sleep 2;
done;
echo "Database available!"']
- name: init-migrations
image: myapp:migrations
command: ['python', 'manage.py', 'migrate']
env:
- name: DB_HOST
value: "postgres-service"
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8000
Differences from main containers:
| Characteristic | Init Container | App Container |
|---|---|---|
| Execution | Sequential, once | Parallel, continuous |
| Restart | If fails, Pod restarts (per restartPolicy) | Per restartPolicy |
| Probes | No liveness/readiness probe | Probes supported |
| Volume sharing | Yes (with app containers) | Yes |
6. Probes — Liveness, Readiness, Startup
Probes are diagnostics executed periodically by the kubelet to monitor container health.
flowchart LR
subgraph PROBES["Kubernetes Probes"]
SP["Startup Probe\nAt startup\nProtects slow apps"]
LP["Liveness Probe\nContinuous\nRestarts on failure"]
RP["Readiness Probe\nContinuous\nRemoves from Service on failure"]
end
C[Container] --> SP
SP -->|Success| LP
SP -->|Success| RP
LP -->|Failure| KILL[Container killed\nand restarted]
RP -->|Failure| REMOVE[Removed from\nService Endpoint]
style SP fill:#f0ad4e,color:#000
style LP fill:#d9534f,color:#fff
style RP fill:#5cb85c,color:#fff
Probe Types
| Probe | Trigger | Action on Failure |
|---|---|---|
| Liveness Probe | Container stuck / deadlock | Container restarted |
| Readiness Probe | Container not yet ready to receive traffic | Container removed from Service endpoints |
| Startup Probe | Slow-starting application | Disables liveness/readiness until success |
Probe Mechanisms
# 1. HTTP GET
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 15 # Wait before first probe
periodSeconds: 10 # Probe frequency
failureThreshold: 3 # Failures before action
successThreshold: 1 # Successes to consider OK
timeoutSeconds: 5 # Timeout per probe
# 2. TCP Socket
readinessProbe:
tcpSocket:
port: 5432
initialDelaySeconds: 5
periodSeconds: 10
# 3. Exec (command in container)
livenessProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
# 4. gRPC (since Kubernetes 1.24)
livenessProbe:
grpc:
port: 2379
initialDelaySeconds: 10
Complete example with all three probes:
apiVersion: v1
kind: Pod
metadata:
name: myapp-with-probes
spec:
containers:
- name: myapp
image: myapp:latest
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /healthz
port: 8080
failureThreshold: 30 # Allows up to 5 minutes (30 × 10s) to start
periodSeconds: 10
livenessProbe:
httpGet:
path: /healthz
port: 8080
initialDelaySeconds: 0
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
7. Resource Requests and Limits
Resource requests and limits allow the Kubernetes scheduler to place Pods on appropriate nodes and prevent a container from consuming more than its fair share of resources.
resources:
requests: # Guaranteed resources — used for scheduling
memory: "64Mi"
cpu: "250m" # 250 millicores = 0.25 CPU
limits: # Ceiling — container cannot exceed these values
memory: "128Mi"
cpu: "500m"
QoS Classes (Quality of Service)
Kubernetes automatically assigns a QoS class to each Pod based on its resource requests/limits:
| QoS Class | Condition | Behavior During Shortage |
|---|---|---|
| Guaranteed | Requests = Limits for all containers | Last to be evicted (OOM Kill) |
| Burstable | Requests < Limits or partially undefined | Evicted after BestEffort |
| BestEffort | No requests or limits defined | First to be evicted |
8. Reference Tables
Pod Phases
| Phase | Short Description |
|---|---|
Pending | Scheduled but not yet started |
Running | At least one container active |
Succeeded | All containers exited with code 0 |
Failed | At least one container exited with error |
Unknown | State undeterminable |
Restart Policies
| Policy | Behavior |
|---|---|
Always (default) | Restarts container on any stop (success or failure) |
OnFailure | Restarts only if container exited with non-0 code |
Never | Never restarts the container |
QoS Classes
| Class | Requests | Limits | Eviction Priority |
|---|---|---|---|
Guaranteed | Defined | Equal to requests | Lowest (evicted last) |
Burstable | Defined | Greater than requests | Intermediate |
BestEffort | Not defined | Not defined | Highest (evicted first) |
kubectl apply vs kubectl create
| Command | If Resource Exists | If Resource Doesn’t Exist |
|---|---|---|
kubectl apply | Updates | Creates |
kubectl create | Error | Creates |
kubectl replace | Completely replaces | Error |
9. Reference YAML Snippets
Minimal Single-Container Pod
apiVersion: v1
kind: Pod
metadata:
name: simple-app
labels:
app: simple-app
spec:
containers:
- name: simple-app
image: myrepo/simple-app:latest
ports:
- containerPort: 5000
Multi-Container Pod (Sidecar Pattern)
apiVersion: v1
kind: Pod
metadata:
name: multi-container-app
spec:
containers:
- name: app
image: myrepo/simple-app:latest
ports:
- containerPort: 5000
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
- name: log-sidecar
image: busybox
command: ["/bin/sh", "-c"]
args:
- tail -f /var/log/app/app.log
volumeMounts:
- name: shared-logs
mountPath: /var/log/app
volumes:
- name: shared-logs
emptyDir: {}
Deployment with 3 Replicas
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment1
spec:
replicas: 3
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: my-container
image: nginx:1.27.3
ports:
- containerPort: 80
10. Essential kubectl Commands
Pods
# Create / update a Pod
kubectl apply -f pod.yaml
# List Pods
kubectl get pods
kubectl get pods -o wide # With extended info
kubectl get pods -n <namespace> # In a specific namespace
# Inspect a Pod
kubectl describe pod <name>
kubectl logs <pod-name> # Container logs
kubectl logs <pod-name> -c <container> # Specific container
kubectl logs <pod-name> -f # Follow logs
# Access a Pod
kubectl exec -it <pod-name> -- bash
kubectl port-forward pod/<name> 8080:80
# Delete a Pod
kubectl delete pod <name>
kubectl delete -f pod.yaml
Deployments
# Create / update a Deployment
kubectl apply -f deployment.yaml
# List Deployments
kubectl get deployments
# Scale
kubectl scale deployment <name> --replicas=5
# Rolling update
kubectl set image deployment/<name> <container>=<new-image>
kubectl rollout status deployment/<name>
kubectl rollout undo deployment/<name>
Cluster Information
# Cluster info
kubectl cluster-info
# List nodes
kubectl get nodes
# Check kubectl version
kubectl version --client
Course Summary:
This course covers the essentials of Kubernetes Pods:
- Designing single-container and multi-container Pods via YAML manifests
- Deploying, updating, and deleting Pods with
kubectl- Using Deployments for automatic scaling and high availability
- Security Contexts for applying the principle of least privilege
- Scheduling to optimize workload placement on nodes
- Advanced concepts: init containers, probes (liveness/readiness/startup), resource requests/limits, and QoS classes
Search Terms
pods · kubernetes · containers · pod · kubectl · classes · deployments · designing · multi-container · phases · probe · qos · reference · single-container