The Nautilus DevOps team is delving into Kubernetes for app management. One team member needs to create a deployment following these details:
Create a deployment named nginx to deploy the application nginx using the image nginx:latest (ensure to specify the tag)
Note: The kubectl utility on the jump-host has been configured to work with the Kubernetes cluster.
Deploy Applications with Kubernetes Deployments: A Complete Guide
Introduction
Kubernetes has become the de facto standard for container orchestration, and Deployments are one of its most powerful and essential resources. In this comprehensive guide, we'll explore how to deploy applications using Kubernetes Deployments, covering everything from basic concepts to advanced strategies used in production environments.
Whether you're preparing for the CKA certification, managing applications in production, or just starting your Kubernetes journey, this guide will provide you with the knowledge and hands-on experience needed to master Kubernetes Deployments.
What are Kubernetes Deployments?
A Deployment is a Kubernetes resource that provides declarative updates for Pods and ReplicaSets. Think of it as a higher-level concept that manages the lifecycle of your application instances, ensuring that the desired state of your application matches the actual state in the cluster.
Key Features of Deployments:
- ✅ Declarative Updates: Define the desired state, and Kubernetes handles the rest
- ✅ Rolling Updates: Zero-downtime updates with controlled rollout strategies
- ✅ Rollbacks: Easy revert to previous versions if something goes wrong
- ✅ Scaling: Simple horizontal scaling with a single command
- ✅ Self-Healing: Automatically replaces failed or unhealthy pods
- ✅ History & Auditing: Track deployment revisions and changes
Understanding the Architecture
Deployment Components
┌─────────────────────────────────────────┐
│ Deployment (nginx) │
│ - Desired Replicas: 3 │
│ - Update Strategy: RollingUpdate │
│ - Selector: app=nginx │
└──────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────┐
│ ReplicaSet (nginx-7c5d8bf9f7) │
│ - Current Replicas: 3 │
│ - Ready Replicas: 3 │
│ - Owner: Deployment │
└──────────────┬──────────────────────────┘
│
┌─────────┼─────────┐
│ │ │
▼ ▼ ▼
┌────────┐┌────────┐┌────────┐
│ Pod 1 ││ Pod 2 ││ Pod 3 │
│ ││ ││ │
│ nginx ││ nginx ││ nginx │
└────────┘└────────┘└────────┘
Relationship Between Resources
- Deployment → Manages ReplicaSets
- ReplicaSet → Manages Pods
- Pods → Run the actual container(s)
Creating Your First Deployment
Method 1: Imperative Command
The quickest way to create a deployment:
kubectl create deployment nginx --image=nginx:latest
Method 2: Declarative YAML (Recommended)
Generate the YAML first:
kubectl create deployment nginx \
--image=nginx:latest \
--dry-run=client -o yaml > nginx-deployment.yaml
Then apply it:
kubectl apply -f nginx-deployment.yaml
Method 3: Complete YAML Manifest
Here's a complete deployment manifest with all configurations:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: production
labels:
app: nginx
environment: production
version: "1.0"
spec:
replicas: 3
selector:
matchLabels:
app: nginx
environment: production
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
revisionHistoryLimit: 10
paused: false
progressDeadlineSeconds: 600
template:
metadata:
labels:
app: nginx
environment: production
version: "1.0"
spec:
containers:
- name: nginx
image: nginx:1.21.6
ports:
- containerPort: 80
name: http
protocol: TCP
env:
- name: ENVIRONMENT
value: "production"
- name: NGINX_VERSION
value: "1.21.6"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 10
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
startupProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
imagePullSecrets:
- name: registry-credentials
restartPolicy: Always
terminationGracePeriodSeconds: 30
Understanding Each Section
1. API Version and Kind
apiVersion: apps/v1
kind: Deployment
-
apps/v1is the stable API version for Deployments -
Kinddefines the resource type
2. Metadata
metadata:
name: nginx
namespace: production
labels:
app: nginx
-
name: Unique identifier for the deployment -
namespace: Logical grouping (defaults to "default") -
labels: Key-value pairs for organization and selection
3. Spec Section
spec:
replicas: 3
selector:
matchLabels:
app: nginx
-
replicas: Number of desired pod instances -
selector: How the deployment finds its pods
4. Pod Template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21.6
- Defines the blueprint for pods
- Contains container specifications
5. Update Strategy
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
- Recreate: Delete all pods, then recreate
- RollingUpdate: Gradually replace pods
Common Operations
1. Viewing Deployments
# List all deployments
kubectl get deployments
# Get detailed info
kubectl describe deployment nginx
# Get deployment status
kubectl rollout status deployment nginx
# Show deployment YAML
kubectl get deployment nginx -o yaml
# Get deployment in JSON
kubectl get deployment nginx -o json
# Show deployment with additional information
kubectl get deployment nginx -o wide
2. Scaling
# Scale to 5 replicas
kubectl scale deployment nginx --replicas=5
# Scale using YAML
kubectl patch deployment nginx -p '{"spec":{"replicas":5}}'
# Scale based on load (using HPA - Horizontal Pod Autoscaler)
kubectl autoscale deployment nginx --min=3 --max=10 --cpu-percent=80
3. Updating Applications
# Update image
kubectl set image deployment/nginx nginx=nginx:1.22.0
# Update multiple images
kubectl set image deployment/nginx nginx=nginx:1.22.0 sidecar=sidecar:2.0
# Update environment variables
kubectl set env deployment/nginx ENVIRONMENT=staging
# Update resources
kubectl set resources deployment/nginx -c=nginx --limits=cpu=500m,memory=256Mi
# Update all containers at once
kubectl patch deployment nginx -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","image":"nginx:1.22.0"}]}}}}'
4. Rollbacks
# View rollout history
kubectl rollout history deployment nginx
# View specific revision
kubectl rollout history deployment nginx --revision=2
# Rollback to previous version
kubectl rollout undo deployment nginx
# Rollback to specific revision
kubectl rollout undo deployment nginx --to-revision=2
# Pause and resume rollout
kubectl rollout pause deployment nginx
kubectl rollout resume deployment nginx
5. Deleting
# Delete deployment
kubectl delete deployment nginx
# Delete using YAML
kubectl delete -f nginx-deployment.yaml
# Delete with force
kubectl delete deployment nginx --force --grace-period=0
Advanced Deployment Strategies
1. Rolling Update Strategy
The default strategy that provides zero-downtime updates:
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 25% # Maximum extra pods allowed during update
maxUnavailable: 25% # Maximum unavailable pods during update
How it works:
- Gradually replaces old pods with new ones
- Ensures application availability during updates
- Configurable speed with
maxSurgeandmaxUnavailable
2. Recreate Strategy
Simple strategy that replaces all pods at once:
strategy:
type: Recreate
When to use:
- Applications that don't support multiple versions simultaneously
- When downtime is acceptable
- Stateful applications with database migrations
3. Blue-Green Deployment
Not native to Kubernetes but can be implemented with Deployments:
# Blue (current) deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-blue
labels:
app: nginx
version: blue
# ... rest of config
---
# Green (new) deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-green
labels:
app: nginx
version: green
# ... rest of config
4. Canary Deployment
Gradually roll out to a subset of users:
# Main deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 9
# ... rest of config
---
# Canary deployment (10% of traffic)
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-canary
labels:
app: nginx
version: canary
spec:
replicas: 1
# ... rest of config
Health Checks and Probes
Types of Probes
- Liveness Probe: Checks if the container is still running
- Readiness Probe: Checks if the container is ready to serve traffic
- Startup Probe: Checks if the application has started (for slow-starting apps)
Probe Configuration Examples
# HTTP Get Probe
livenessProbe:
httpGet:
path: /health
port: 8080
httpHeaders:
- name: Custom-Header
value: Awesome
initialDelaySeconds: 15
periodSeconds: 20
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
# TCP Socket Probe
readinessProbe:
tcpSocket:
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
# Command Probe
startupProbe:
exec:
command:
- cat
- /tmp/healthy
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
Resource Management
CPU and Memory Limits
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "256Mi"
cpu: "500m"
Understanding:
-
requests: Minimum guaranteed resources -
limits: Maximum resources allowed -
cpu: Measured in millicores (1000m = 1 CPU core) -
memory: Measured in Mi (Mebibytes) or Gi
Quality of Service (QoS) Classes
- Guaranteed: When requests = limits for all resources
- Burstable: When requests < limits
- BestEffort: No requests or limits set
Monitoring and Debugging
1. Viewing Logs
# Logs from a specific pod
kubectl logs nginx-7c5d8bf9f7-nb2sz
# Logs from all pods in deployment
kubectl logs deployment/nginx
# Follow logs
kubectl logs -f deployment/nginx
# Previous container logs (if crashed)
kubectl logs nginx-7c5d8bf9f7-nb2sz --previous
2. Executing Commands
# Execute command in pod
kubectl exec -it nginx-7c5d8bf9f7-nb2sz -- /bin/bash
# Run a single command
kubectl exec nginx-7c5d8bf9f7-nb2sz -- ls -la /usr/share/nginx/html
# Copy files to/from pod
kubectl cp nginx-7c5d8bf9f7-nb2sz:/var/log/nginx/access.log access.log
3. Checking Events
# All events
kubectl get events
# Events for specific deployment
kubectl get events --field-selector involvedObject.name=nginx
# Sort events by time
kubectl get events --sort-by='.lastTimestamp'
4. Troubleshooting Pods
# Detailed pod description
kubectl describe pod nginx-7c5d8bf9f7-nb2sz
# Check pod status
kubectl get pod nginx-7c5d8bf9f7-nb2sz -o yaml
# Check pod logs
kubectl logs nginx-7c5d8bf9f7-nb2sz
# Check pod events
kubectl get events --field-selector involvedObject.name=nginx-7c5d8bf9f7-nb2sz
Best Practices
✅ DO's
-
Use Declarative Manifests
- Version control your YAML files
- Enable audit trail and rollback capability
-
Pin Image Versions
- Avoid
:latestin production - Use semantic versioning or commit hashes
- Avoid
-
Set Resource Limits
- Prevent resource exhaustion
- Ensure QoS class assignment
-
Add Health Checks
- Implement liveness and readiness probes
- Use startup probes for slow-starting apps
-
Use Multiple Replicas
- Ensure high availability
- Enable rolling updates
-
Implement Monitoring
- Set up logging and metrics
- Use monitoring tools like Prometheus
-
Use Namespaces
- Organize deployments logically
- Implement RBAC and resource quotas
-
Implement Security
- Use ServiceAccounts with minimal permissions
- Set security contexts
- Use image pull secrets for private registries
❌ DON'Ts
-
Don't use
:latestin production - Unpredictable updates - Don't ignore resource limits - Can crash the cluster
- Don't skip health checks - Missing self-healing
- Don't use single replicas - Single point of failure
- Don't delete pods directly - Let the deployment manage them
- Don't make direct updates to pods - Use the deployment
- Don't store secrets in manifests - Use Kubernetes secrets
- Don't run as root - Use security contexts
Production-Ready Example
Here's a complete production-ready deployment:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
namespace: production
labels:
app: web-app
environment: production
tier: frontend
version: v1.2.3
annotations:
kubernetes.io/change-cause: "Updated to v1.2.3 with security patches"
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
spec:
replicas: 5
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
selector:
matchLabels:
app: web-app
revisionHistoryLimit: 10
progressDeadlineSeconds: 600
template:
metadata:
labels:
app: web-app
environment: production
tier: frontend
version: v1.2.3
spec:
containers:
- name: web-app
image: registry.example.com/web-app:v1.2.3
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
name: http
protocol: TCP
env:
- name: ENVIRONMENT
value: "production"
- name: LOG_LEVEL
value: "info"
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secrets
key: url
- name: REDIS_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: redis_host
resources:
requests:
memory: "128Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "1000m"
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 15
periodSeconds: 5
timeoutSeconds: 3
successThreshold: 1
failureThreshold: 3
startupProbe:
httpGet:
path: /health/startup
port: 8080
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 30
volumeMounts:
- name: app-data
mountPath: /data
- name: app-config
mountPath: /etc/config
securityContext:
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
volumes:
- name: app-data
persistentVolumeClaim:
claimName: app-data-pvc
- name: app-config
configMap:
name: app-config
imagePullSecrets:
- name: registry-credentials
restartPolicy: Always
terminationGracePeriodSeconds: 60
securityContext:
fsGroup: 1000
runAsNonRoot: true
serviceAccountName: web-app-sa
nodeSelector:
node-type: application
tolerations:
- key: "critical"
operator: "Equal"
value: "true"
effect: "NoSchedule"
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web-app
topologyKey: kubernetes.io/hostname
Common Error Scenarios and Solutions
1. ImagePullBackOff
Error: Pod stuck in ImagePullBackOff
Solution:
# Check image name and tag
kubectl describe pod -l app=nginx | grep Image
# Fix by updating image
kubectl set image deployment/nginx nginx=nginx:1.21.6
2. CrashLoopBackOff
Error: Pod constantly crashing
Solution:
# Check logs
kubectl logs deployment/nginx --previous
# Check events
kubectl describe pod -l app=nginx | grep -A 10 Events
3. Deployment Stuck
Error: Deployment progress is stuck
Solution:
# Check rollout status
kubectl rollout status deployment nginx
# Check events
kubectl get events --field-selector involvedObject.name=nginx
# Restart deployment
kubectl rollout restart deployment nginx
4. Insufficient Resources
Error: Pods pending due to resource constraints
Solution:
# Check node resources
kubectl describe nodes
# Reduce resource requests
kubectl patch deployment nginx -p '{"spec":{"template":{"spec":{"containers":[{"name":"nginx","resources":{"requests":{"cpu":"100m","memory":"64Mi"}}}]}}}}'
Integration with Other Kubernetes Resources
1. Service
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx
ports:
- port: 80
targetPort: 80
type: ClusterIP
2. ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
data:
nginx.conf: |
server {
listen 80;
server_name example.com;
location / {
root /usr/share/nginx/html;
index index.html;
}
}
3. Secret
apiVersion: v1
kind: Secret
metadata:
name: nginx-secrets
type: Opaque
data:
username: dXNlcm5hbWU= # base64 encoded
password: cGFzc3dvcmQ= # base64 encoded
4. Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: nginx-ingress
spec:
rules:
- host: nginx.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: nginx-service
port:
number: 80
CI/CD Integration
Example GitLab CI Pipeline
stages:
- build
- deploy
variables:
IMAGE_TAG: $CI_COMMIT_SHORT_SHA
K8S_NAMESPACE: production
build:
stage: build
script:
- docker build -t $CI_REGISTRY_IMAGE:$IMAGE_TAG .
- docker push $CI_REGISTRY_IMAGE:$IMAGE_TAG
deploy:
stage: deploy
script:
- kubectl set image deployment/web-app web-app=$CI_REGISTRY_IMAGE:$IMAGE_TAG
- kubectl rollout status deployment/web-app
only:
- main
Monitoring with Prometheus/Grafana
ServiceMonitor for Prometheus
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: nginx-monitor
namespace: production
spec:
selector:
matchLabels:
app: nginx
endpoints:
- port: metrics
path: /metrics
interval: 30s
Conclusion
Kubernetes Deployments are the backbone of modern application deployment strategies. They provide the control, flexibility, and reliability needed for production-grade applications. In this guide, we've covered:
- ✅ Understanding Deployment architecture and components
- ✅ Creating and managing Deployments
- ✅ Implementing different update strategies
- ✅ Configuring health checks and resource management
- ✅ Best practices for production environments
- ✅ Troubleshooting common issues
- ✅ Integrating with other Kubernetes resources
- ✅ CI/CD automation
Key Takeaways
- Always use declarative YAML manifests for reproducibility
- Implement health checks for self-healing applications
- Use rolling updates for zero-downtime deployments
- Set resource limits to prevent resource exhaustion
- Pin image versions for predictable deployments
- Monitor your deployments for proactive maintenance
- Implement proper security practices from the start
Next Steps
Now that you've mastered Kubernetes Deployments, consider exploring:
- Horizontal Pod Autoscaler (HPA) - Automatic scaling based on metrics
- Vertical Pod Autoscaler (VPA) - Automatic resource adjustment
- Helm Charts - Package management for Kubernetes
- Kustomize - Template-free configuration management
- GitOps - Git as the source of truth for infrastructure
- Service Mesh - Advanced networking and security features
- Pod Disruption Budgets - Ensuring application availability during maintenance
Resources
- Official Kubernetes Documentation - Deployments
- Kubernetes Best Practices
- CNCF Landscape
- KodeKloud Kubernetes Course
Top comments (0)