An application deployed on the Kubernetes cluster requires an update with new features developed by the Nautilus application development team. The existing setup includes a deployment named nginx-deployment and a service named nginx-service. Below are the necessary changes to be implemented without deleting the deployment and service:
1.) Modify the service nodeport from 30008 to 32165
2.) Change the replicas count from 1 to 5
3.) Update the image from nginx:1.19 to nginx:latest
Introduction
Imagine you're a DevOps engineer, and the development team just released new features for your application. You need to update the running application without any downtime. How do you do it in Kubernetes?
In this beginner-friendly guide, we'll walk through updating a Kubernetes deployment and service step by step. We'll cover changing service ports, scaling applications, and updating container images—all without deleting anything!
What You'll Learn
- How to update Kubernetes services and deployments
- How to scale applications up or down
- How to update container images
- How to find and fix common update errors
- How to verify your updates are working
Table of Contents
- Understanding the Scenario
- Prerequisites
- Step 1: Check Current State
- Step 2: Update the Service NodePort
- Step 3: Scale the Deployment
- Step 4: Update the Container Image
- Step 5: Verify All Changes
- Common Issues and Solutions
- Essential Commands Reference
- Best Practices
- Conclusion
Understanding the Scenario
The Problem
The Nautilus development team has created new features for their application. They need you to update the existing Kubernetes deployment without deleting anything.
Current Setup
Before the update, we have:
┌─────────────────────────────────────────────────────────┐
│ Current Setup │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Deployment: nginx-deployment │ │
│ │ Replicas: 1 │ │
│ │ Image: nginx:1.19 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Service: nginx-service │ │
│ │ Type: NodePort │ │
│ │ NodePort: 30008 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
What Needs to Change
| Component | Current | New | Why? |
|---|---|---|---|
| NodePort | 30008 | 32165 | Port conflict or new requirement |
| Replicas | 1 | 5 | High availability and load distribution |
| Image | nginx:1.19 | nginx:latest | New features and security patches |
Desired State
┌─────────────────────────────────────────────────────────┐
│ Desired Setup │
├─────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Deployment: nginx-deployment │ │
│ │ Replicas: 5 │ │
│ │ Image: nginx:latest │ │
│ └─────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Service: nginx-service │ │
│ │ Type: NodePort │ │
│ │ NodePort: 32165 │ │
│ └─────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────┘
Prerequisites
Before we start, make sure you have:
- ✅ A Kubernetes cluster (Minikube, kind, or cloud-based)
- ✅
kubectlconfigured and working - ✅ A deployment named
nginx-deployment - ✅ A service named
nginx-service - ✅ Basic understanding of Kubernetes concepts
Step 1: Check Current State
Before making any changes, let's see what we're working with.
Check the Deployment
kubectl get deployment nginx-deployment
Expected Output:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 1/1 1 1 66s
What This Tells Us:
- READY: 1/1 - One pod is running and ready
- UP-TO-DATE: 1 - All pods are on the current version
- AVAILABLE: 1 - One pod is available to serve traffic
Check the Service
kubectl get service nginx-service
Expected Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.43.22.56 <none> 80:30008/TCP 66s
What This Tells Us:
- TYPE: NodePort - Service is exposed on a node port
- PORT(S): 80:30008/TCP - Port 80 maps to node port 30008
Check the Pods
kubectl get pods
Expected Output:
NAME READY STATUS RESTARTS AGE
nginx-deployment-6655dc8cfb-5ps5g 1/1 Running 0 66s
What This Tells Us:
- READY: 1/1 - The pod is ready
- STATUS: Running - The pod is running correctly
Check the Image Version
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].image}'
Expected Output:
nginx:1.19
Step 2: Update the Service NodePort
The first change we need to make is updating the NodePort from 30008 to 32165.
Option A: Using kubectl edit (Interactive)
This is the most intuitive way for beginners:
kubectl edit service nginx-service
This opens the service YAML in your default editor. Find the nodePort field and change it:
spec:
ports:
- nodePort: 32165 # Change from 30008 to 32165
port: 80
protocol: TCP
targetPort: 80
Save and exit. The service will update automatically.
💡 Pro Tip: Your editor might be nano, vim, or vi. Use the appropriate commands to save and exit.
Option B: Using kubectl patch (Quick Command)
For a quick update without opening an editor:
kubectl patch service nginx-service -p '{"spec":{"ports":[{"nodePort":32165,"port":80,"protocol":"TCP","targetPort":80}]}}'
Option C: Using YAML File (Recommended for Production)
First, save the current service YAML:
kubectl get service nginx-service -o yaml > nginx-service.yaml
Edit the file:
nano nginx-service.yaml
Change the nodePort:
spec:
ports:
- nodePort: 32165
port: 80
protocol: TCP
targetPort: 80
Apply the changes:
kubectl replace -f nginx-service.yaml
Verify the Update
kubectl get service nginx-service
Expected Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.43.22.56 <none> 80:32165/TCP 2m
Notice the NodePort has changed to 32165!
Step 3: Scale the Deployment
Now let's increase the number of replicas from 1 to 5.
Option A: Using kubectl scale (Recommended)
kubectl scale deployment nginx-deployment --replicas=5
Expected Output:
deployment.apps/nginx-deployment scaled
Option B: Using kubectl edit
kubectl edit deployment nginx-deployment
Find and change:
spec:
replicas: 5 # Change from 1 to 5
Save and exit.
Option C: Using kubectl patch
kubectl patch deployment nginx-deployment -p '{"spec":{"replicas":5}}'
Watch the Scaling Happen
You can watch as new pods are created:
kubectl get pods -w
Expected Output:
NAME READY STATUS RESTARTS AGE
nginx-deployment-6655dc8cfb-5ps5g 1/1 Running 0 2m
nginx-deployment-6655dc8cfb-7xyzx 0/1 Pending 0 1s
nginx-deployment-6655dc8cfb-8abcd 0/1 Pending 0 1s
nginx-deployment-6655dc8cfb-9efgh 0/1 Pending 0 1s
nginx-deployment-6655dc8cfb-0ijkl 0/1 Pending 0 1s
After a few seconds, they'll all be running.
Verify the Scaling
kubectl get deployment nginx-deployment
Expected Output:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 5/5 5 5 3m
Now we have 5 pods running!
kubectl get pods
Expected Output:
NAME READY STATUS RESTARTS AGE
nginx-deployment-6655dc8cfb-5ps5g 1/1 Running 0 3m
nginx-deployment-6655dc8cfb-7xyzx 1/1 Running 0 30s
nginx-deployment-6655dc8cfb-8abcd 1/1 Running 0 30s
nginx-deployment-6655dc8cfb-9efgh 1/1 Running 0 30s
nginx-deployment-6655dc8cfb-0ijkl 1/1 Running 0 30s
Step 4: Update the Container Image
Now we need to update the image from nginx:1.19 to nginx:latest.
First: Find the Container Name
This is a common pitfall! You need to know the container name to update it.
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].name}'
Or use describe:
kubectl describe deployment nginx-deployment | grep -A 5 "Containers:"
Expected Output:
Containers:
nginx-container:
Image: nginx:1.19
Port: <none>
Host Port: <none>
Environment: <none>
The container name is nginx-container.
Update the Image
Option A: Using kubectl set image (Recommended)
kubectl set image deployment/nginx-deployment nginx-container=nginx:latest
Expected Output:
deployment.apps/nginx-deployment image updated
Option B: Using Wildcard
kubectl set image deployment/nginx-deployment *=nginx:latest
Option C: Using Container Index
kubectl set image deployment/nginx-deployment [0]=nginx:latest
Option D: Using kubectl edit
kubectl edit deployment nginx-deployment
Find and change:
spec:
template:
spec:
containers:
- image: nginx:latest # Change from nginx:1.19
Watch the Rolling Update
kubectl rollout status deployment nginx-deployment
Expected Output:
Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 3 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 4 out of 5 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 5 out of 5 new replicas have been updated...
deployment "nginx-deployment" successfully rolled out
Understanding the Rolling Update
When you update the image, Kubernetes performs a rolling update:
Before Update:
┌─────────────────────────────────────────────────────────┐
│ Old ReplicaSet (nginx:1.19) │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ │ │ │ │ │ │ │ │ │ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
│ 1 2 3 4 5 │
└─────────────────────────────────────────────────────────┘
During Update:
┌─────────────────────────────────────────────────────────┐
│ Old ReplicaSet │ New ReplicaSet │
│ (nginx:1.19) │ (nginx:latest) │
│ ┌───┐ ┌───┐ ┌───┐ │ ┌───┐ │
│ │ │ │ │ │ │ │ │ │ │
│ └───┘ └───┘ └───┘ │ └───┘ │
│ 1 2 3 │ 4 (new) │
│ │ │
│ ┌───┐ ┌───┐ │ ┌───┐ ┌───┐ │
│ │ │ │ │ │ │ │ │ │ │
│ └───┘ └───┘ │ └───┘ └───┘ │
│ 4 5 │ 5 (new) 6 (new) │
└─────────────────────────────────────────────────────────┘
After Update:
┌─────────────────────────────────────────────────────────┐
│ New ReplicaSet (nginx:latest) │
│ ┌───┐ ┌───┐ ┌───┐ ┌───┐ ┌───┐ │
│ │ │ │ │ │ │ │ │ │ │ │
│ └───┘ └───┘ └───┘ └───┘ └───┘ │
│ 1 2 3 4 5 │
└─────────────────────────────────────────────────────────┘
Key Points:
- New pods are created before old ones are removed
- Zero downtime during the update
- If something goes wrong, Kubernetes stops the update
Step 5: Verify All Changes
Now let's verify everything was updated correctly.
Complete Verification Script
#!/bin/bash
echo "=== Deployment and Service Update Verification ==="
echo "==================================================="
echo -e "\n📦 DEPLOYMENT STATUS:"
kubectl get deployment nginx-deployment
echo -e "\n🔌 SERVICE STATUS:"
kubectl get service nginx-service
echo -e "\n📊 POD STATUS:"
kubectl get pods -l app=nginx
echo -e "\n🖼️ CURRENT IMAGE:"
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].image}'
echo ""
echo -e "\n🔢 REPLICA COUNT:"
kubectl get deployment nginx-deployment -o jsonpath='{.spec.replicas}'
echo ""
echo -e "\n🚪 NODEPORT:"
kubectl get service nginx-service -o jsonpath='{.spec.ports[0].nodePort}'
echo ""
echo -e "\n📈 ROLLOUT STATUS:"
kubectl rollout status deployment nginx-deployment
echo -e "\n📋 ROLLOUT HISTORY:"
kubectl rollout history deployment nginx-deployment
echo -e "\n==================================================="
echo -e "✅ All verification complete!"
Manual Verification Commands
1. Check Deployment:
kubectl get deployment nginx-deployment
Expected Output:
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 5/5 5 5 5m
2. Check Service:
kubectl get service nginx-service
Expected Output:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-service NodePort 10.43.22.56 <none> 80:32165/TCP 5m
3. Check Pods:
kubectl get pods
Expected Output:
NAME READY STATUS RESTARTS AGE
nginx-deployment-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
nginx-deployment-xxxxxxxxxx-yyyyy 1/1 Running 0 2m
nginx-deployment-xxxxxxxxxx-zzzzz 1/1 Running 0 2m
nginx-deployment-xxxxxxxxxx-aaaaa 1/1 Running 0 2m
nginx-deployment-xxxxxxxxxx-bbbbb 1/1 Running 0 2m
4. Check Image:
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].image}'
Expected Output:
nginx:latest
5. Check Replicas:
kubectl get deployment nginx-deployment -o jsonpath='{.spec.replicas}'
Expected Output:
5
6. Check NodePort:
kubectl get service nginx-service -o jsonpath='{.spec.ports[0].nodePort}'
Expected Output:
32165
7. Check Rollout History:
kubectl rollout history deployment nginx-deployment
Expected Output:
REVISION CHANGE-CAUSE
1 <none>
2 <none>
Common Issues and Solutions
Issue 1: "Unable to find container named 'nginx'"
Error:
error: unable to find container named "nginx"
Why This Happens:
- The container name in your deployment isn't
nginx - Container names are case-sensitive
Solution:
# Find the correct container name
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].name}'
# Use the correct name
kubectl set image deployment/nginx-deployment <correct-name>=nginx:latest
# Or use wildcard
kubectl set image deployment/nginx-deployment *=nginx:latest
Issue 2: Service YAML Not Found
Error:
error: the path "nginx-service.yaml" does not exist
Why This Happens:
- You tried to use
kubectl replace -fbut the file doesn't exist
Solution:
# Save the current service to a file
kubectl get service nginx-service -o yaml > nginx-service.yaml
# Edit the file
nano nginx-service.yaml
# Now apply it
kubectl replace -f nginx-service.yaml
Issue 3: NodePort Already in Use
Error:
Error: node port 32165 is already in use
Why This Happens:
- Another service is using the same NodePort
Solution:
# Check what's using the port
kubectl get services --all-namespaces | grep 32165
# Choose a different port
kubectl patch service nginx-service -p '{"spec":{"ports":[{"nodePort":32166,"port":80,"protocol":"TCP","targetPort":80}]}}'
Issue 4: Rolling Update Stuck
Error:
deployment "nginx-deployment" exceeded its progress deadline
Why This Happens:
- New pods aren't becoming ready
- Image pull issues
- Resource constraints
Solution:
# Check pod status
kubectl get pods
# Check pod details
kubectl describe pod -l app=nginx
# Check events
kubectl get events --field-selector involvedObject.name=nginx-deployment
# If stuck, rollback
kubectl rollout undo deployment nginx-deployment
Issue 5: ImagePullBackOff
Error:
ImagePullBackOff
Why This Happens:
- Image tag doesn't exist
- Wrong image name
- Registry authentication issues
Solution:
# Check if image exists locally
docker pull nginx:latest
# Check the image tag
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].image}'
# Fix the image tag
kubectl set image deployment/nginx-deployment nginx-container=nginx:1.25
Essential Commands Reference
Service Commands
| Command | Description |
|---|---|
kubectl get service nginx-service |
View service details |
kubectl describe service nginx-service |
Detailed service info |
kubectl edit service nginx-service |
Edit service |
kubectl patch service nginx-service -p '...' |
Patch service |
kubectl get service nginx-service -o yaml |
Get service YAML |
Deployment Commands
| Command | Description |
|---|---|
kubectl get deployment nginx-deployment |
View deployment |
kubectl scale deployment nginx-deployment --replicas=5 |
Scale replicas |
kubectl set image deployment/nginx-deployment CONTAINER=IMAGE |
Update image |
kubectl rollout status deployment nginx-deployment |
Check rollout |
kubectl rollout history deployment nginx-deployment |
View history |
kubectl rollout undo deployment nginx-deployment |
Rollback |
Pod Commands
| Command | Description |
|---|---|
kubectl get pods |
List pods |
kubectl describe pod POD_NAME |
Pod details |
kubectl logs POD_NAME |
View logs |
kubectl exec -it POD_NAME -- /bin/bash |
Shell into pod |
Verification Commands
| Command | Description |
|---|---|
kubectl get deployment -o jsonpath='{.spec.replicas}' |
Get replica count |
kubectl get deployment -o jsonpath='{.spec.template.spec.containers[0].image}' |
Get image |
kubectl get service -o jsonpath='{.spec.ports[0].nodePort}' |
Get NodePort |
kubectl get pods -l app=nginx |
Filter by label |
Best Practices
✅ DO's
1. Always Check Current State First
# Before making changes
kubectl get deployment,service,pods
2. Use --dry-run to Test Commands
kubectl set image deployment/nginx-deployment nginx-container=nginx:latest --dry-run=client
3. Find Container Name Before Updating Images
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].name}'
4. Monitor Rollout Status
kubectl rollout status deployment nginx-deployment
5. Save YAML Files for Repeatability
kubectl get deployment nginx-deployment -o yaml > nginx-deployment.yaml
kubectl get service nginx-service -o yaml > nginx-service.yaml
6. Use Specific Image Tags in Production
# Development
image: nginx:latest
# Production
image: nginx:1.25.3
7. Test Changes in Staging First
# Test in staging
kubectl set image deployment/nginx-staging nginx-container=nginx:latest
# After testing, apply to production
kubectl set image deployment/nginx-production nginx-container=nginx:latest
8. Document Your Changes
kubectl annotate deployment nginx-deployment kubernetes.io/change-cause="Updated to nginx:latest for new features"
❌ DON'Ts
1. Don't Delete Resources
# BAD - This deletes everything
kubectl delete deployment nginx-deployment
kubectl delete service nginx-service
# GOOD - Update instead
kubectl scale deployment nginx-deployment --replicas=5
kubectl set image deployment/nginx-deployment nginx-container=nginx:latest
2. Don't Use Wrong Container Names
# BAD - Wrong name
kubectl set image deployment/nginx-deployment nginx=nginx:latest
# GOOD - Check name first
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].name}'
kubectl set image deployment/nginx-deployment nginx-container=nginx:latest
3. Don't Forget to Verify
# Always verify after changes
kubectl get deployment,service,pods
4. Don't Ignore Error Messages
# Read and understand errors
# They tell you exactly what's wrong
5. Don't Scale Without Understanding Impact
# Consider resource constraints
# Ensure you have enough capacity
kubectl describe nodes
Complete Real-World Example
Here's a complete session showing the entire process:
# 1. Check current state
echo "=== Current State ==="
kubectl get deployment nginx-deployment
kubectl get service nginx-service
kubectl get pods
# Output:
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx-deployment 1/1 1 1 66s
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-service NodePort 10.43.22.56 <none> 80:30008/TCP 66s
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-6655dc8cfb-5ps5g 1/1 Running 0 66s
# 2. Update service nodePort
echo -e "\n=== Updating Service ==="
kubectl patch service nginx-service -p '{"spec":{"ports":[{"nodePort":32165,"port":80,"protocol":"TCP","targetPort":80}]}}'
# Output: service/nginx-service patched
# 3. Scale deployment
echo -e "\n=== Scaling Deployment ==="
kubectl scale deployment nginx-deployment --replicas=5
# Output: deployment.apps/nginx-deployment scaled
# 4. Find container name
echo -e "\n=== Finding Container Name ==="
kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].name}'
# Output: nginx-container
# 5. Update image
echo -e "\n\n=== Updating Image ==="
kubectl set image deployment/nginx-deployment nginx-container=nginx:latest
# Output: deployment.apps/nginx-deployment image updated
# 6. Monitor rollout
echo -e "\n=== Rollout Status ==="
kubectl rollout status deployment nginx-deployment
# Output: deployment "nginx-deployment" successfully rolled out
# 7. Verify all changes
echo -e "\n=== Final State ==="
kubectl get deployment nginx-deployment
kubectl get service nginx-service
kubectl get pods
echo -e "\n=== Detailed Verification ==="
echo "Replicas: $(kubectl get deployment nginx-deployment -o jsonpath='{.spec.replicas}')"
echo "Image: $(kubectl get deployment nginx-deployment -o jsonpath='{.spec.template.spec.containers[0].image}')"
echo "NodePort: $(kubectl get service nginx-service -o jsonpath='{.spec.ports[0].nodePort}')"
echo "Pods: $(kubectl get pods -l app=nginx --no-headers | wc -l)"
# Output:
# === Final State ===
# NAME READY UP-TO-DATE AVAILABLE AGE
# nginx-deployment 5/5 5 5 5m
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
# nginx-service NodePort 10.43.22.56 <none> 80:32165/TCP 5m
# NAME READY STATUS RESTARTS AGE
# nginx-deployment-xxxxxxxxxx-xxxxx 1/1 Running 0 2m
# nginx-deployment-xxxxxxxxxx-yyyyy 1/1 Running 0 2m
# nginx-deployment-xxxxxxxxxx-zzzzz 1/1 Running 0 2m
# nginx-deployment-xxxxxxxxxx-aaaaa 1/1 Running 0 2m
# nginx-deployment-xxxxxxxxxx-bbbbb 1/1 Running 0 2m
# === Detailed Verification ===
# Replicas: 5
# Image: nginx:latest
# NodePort: 32165
# Pods: 5
Summary
Key Takeaways
- Updates Are Easy: Kubernetes makes it simple to update services and deployments
- Zero Downtime: Rolling updates ensure your application stays available
- Find Container Names First: Always check container names before updating images
- Verify Everything: Always check that your updates worked correctly
- Use the Right Tools: Different commands for different updates
What You Learned
✅ How to check current deployment and service status
✅ How to update a service NodePort
✅ How to scale a deployment
✅ How to find the correct container name
✅ How to update container images
✅ How to monitor rolling updates
✅ How to verify all changes
Final Status
After completing all updates:
┌─────────────────────────────────────────────────────────┐
│ Successful Update! │
├─────────────────────────────────────────────────────────┤
│ │
│ ✅ Deployment: nginx-deployment │
│ Replicas: 5 (scaled from 1) │
│ Image: nginx:latest (updated from 1.19) │
│ │
│ ✅ Service: nginx-service │
│ Type: NodePort │
│ NodePort: 32165 (updated from 30008) │
│ │
│ ✅ Pods: 5 running │
│ Status: All healthy │
│ │
└─────────────────────────────────────────────────────────┘
Top comments (0)