After containerizing an application with Docker, the next logical step is deploying it on Kubernetes.
Kubernetes helps automate application deployment, scaling, networking, and management of containerized workloads. Instead of manually running containers, Kubernetes ensures your application remains available and can easily scale when needed.
In this guide, we'll deploy a Docker image of a Node.js application on Kubernetes using a Deployment and a Service.
Prerequisites
Before starting, make sure you have:
- Docker installed
- Kubernetes cluster running (Docker Desktop Kubernetes, Minikube, Kind, EKS, etc.)
- kubectl configured
- A Docker image pushed to Docker Hub
In my case, the image was:
madhavnaks/node-app:latest
Why Kubernetes?
Running a container using Docker is straightforward:
docker run -p 3000:3000 madhavnaks/node-app:latest
However, in production environments we need much more than simply running a container.
Kubernetes provides:
- High availability
- Self-healing containers
- Load balancing
- Service discovery
- Horizontal scaling
- Rolling updates
This makes it the industry standard for container orchestration.
Understanding the Kubernetes Architecture for This Deployment
For this deployment, we'll use two Kubernetes resources:
Deployment
A Deployment is responsible for:
- Creating Pods
- Maintaining desired replica count
- Recreating failed Pods automatically
- Managing updates and rollbacks
Service
A Service provides a stable network endpoint for Pods.
Since Pod IPs change frequently, Services allow applications and users to communicate reliably with Pods.
Deployment and Service Manifest
Create a file named:
app.yaml
Add the following configuration:
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-app
spec:
replicas: 2
selector:
matchLabels:
app: node-app
template:
metadata:
labels:
app: node-app
spec:
containers:
- name: node-app
image: madhavnaks/node-app:latest
ports:
- containerPort: 3000
---
apiVersion: v1
kind: Service
metadata:
name: node-app
spec:
selector:
app: node-app
type: NodePort
ports:
- port: 123
targetPort: 3000
nodePort: 32000
Understanding the Deployment Configuration
Replica Count
replicas: 2
Kubernetes will maintain two running Pod instances of the application.
If one Pod crashes, Kubernetes automatically creates another one to maintain the desired state.
Docker Image
image: madhavnaks/node-app:latest
Kubernetes pulls the image directly from Docker Hub and uses it to create containers.
Container Port
containerPort: 3000
This specifies the port on which the Node.js application listens inside the container.
Understanding the Service Configuration
The Service exposes our Pods to network traffic.
Service Port
port: 123
This is the port exposed by the Kubernetes Service inside the cluster.
Target Port
targetPort: 3000
Traffic arriving at the Service is forwarded to port 3000 inside the container.
NodePort
nodePort: 32000
This exposes the application outside the cluster.
Requests reaching:
<Node-IP>:32000
are forwarded to:
Service Port → Target Port → Container
which means:
32000 → 123 → 3000
Deploying the Application
Apply the manifest:
kubectl apply -f complete.yaml
Expected output:
deployment.apps/node-app created
service/node-app created
Verify the Deployment
Check Deployments:
kubectl get deployments
Example output:
NAME READY UP-TO-DATE AVAILABLE
node-app 2/2 2 2
Check Pods:
kubectl get pods
Example:
NAME READY STATUS
node-app-xxxxx 1/1 Running
node-app-yyyyy 1/1 Running
Notice that Kubernetes created two Pods because we specified:
replicas: 2
Check Services:
kubectl get svc
Example:
NAME TYPE CLUSTER-IP PORT(S)
node-app NodePort 10.x.x.x 123:32000/TCP
Accessing the Application
To access the application:
http://localhost:32000
Or:
http://<Node-IP>:32000
depending on your Kubernetes setup.
The request flow looks like:
User
│
▼
NodePort (32000)
│
▼
Service Port (123)
│
▼
Target Port (3000)
│
▼
Node.js Container
Benefits of Using a Deployment
Deployments provide several production-grade capabilities:
Self-Healing
If a Pod crashes:
kubectl delete pod <pod-name>
Kubernetes automatically creates a replacement Pod.
Scaling
Increase replicas easily:
replicas: 5
Apply again:
kubectl apply -f complete.yaml
Kubernetes creates additional Pods automatically.
Rolling Updates
When a new Docker image version is pushed:
image: madhavnaks/node-app:v2
Applying the updated manifest performs a rolling update with minimal downtime.
Key Takeaways
✅ Deployments manage Pods automatically
✅ Replica count ensures high availability
✅ Services provide stable networking
✅ NodePort exposes applications outside the cluster
✅ Kubernetes continuously maintains the desired state of the application
Conclusion
Deploying a containerized application on Kubernetes is a major step toward building production-ready cloud-native applications.
Using a Deployment and Service, Kubernetes can automatically manage application availability, networking, scaling, and recovery without manual intervention.
Once you're comfortable with these fundamentals, the next topics to explore are ConfigMaps, Secrets, Ingress, Persistent Volumes, and Helm Charts.
Happy Learning and Happy Kubernetes! 🚀
Top comments (0)