DEV Community

Madhav Nakra
Madhav Nakra

Posted on

Deploying a Dockerized Node.js Application on Kubernetes 🚀

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
Enter fullscreen mode Exit fullscreen mode

Why Kubernetes?

Running a container using Docker is straightforward:

docker run -p 3000:3000 madhavnaks/node-app:latest
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Understanding the Deployment Configuration

Replica Count

replicas: 2
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Kubernetes pulls the image directly from Docker Hub and uses it to create containers.


Container Port

containerPort: 3000
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

This is the port exposed by the Kubernetes Service inside the cluster.


Target Port

targetPort: 3000
Enter fullscreen mode Exit fullscreen mode

Traffic arriving at the Service is forwarded to port 3000 inside the container.


NodePort

nodePort: 32000
Enter fullscreen mode Exit fullscreen mode

This exposes the application outside the cluster.

Requests reaching:

<Node-IP>:32000
Enter fullscreen mode Exit fullscreen mode

are forwarded to:

Service Port → Target Port → Container
Enter fullscreen mode Exit fullscreen mode

which means:

32000 → 123 → 3000
Enter fullscreen mode Exit fullscreen mode

Deploying the Application

Apply the manifest:

kubectl apply -f complete.yaml
Enter fullscreen mode Exit fullscreen mode

Expected output:

deployment.apps/node-app created
service/node-app created
Enter fullscreen mode Exit fullscreen mode

Verify the Deployment

Check Deployments:

kubectl get deployments
Enter fullscreen mode Exit fullscreen mode

Example output:

NAME       READY   UP-TO-DATE   AVAILABLE
node-app   2/2     2            2
Enter fullscreen mode Exit fullscreen mode

Check Pods:

kubectl get pods
Enter fullscreen mode Exit fullscreen mode

Example:

NAME                        READY   STATUS
node-app-xxxxx              1/1     Running
node-app-yyyyy              1/1     Running
Enter fullscreen mode Exit fullscreen mode

Notice that Kubernetes created two Pods because we specified:

replicas: 2
Enter fullscreen mode Exit fullscreen mode

Check Services:

kubectl get svc
Enter fullscreen mode Exit fullscreen mode

Example:

NAME         TYPE       CLUSTER-IP      PORT(S)
node-app     NodePort   10.x.x.x        123:32000/TCP
Enter fullscreen mode Exit fullscreen mode

Accessing the Application

To access the application:

http://localhost:32000
Enter fullscreen mode Exit fullscreen mode

Or:

http://<Node-IP>:32000
Enter fullscreen mode Exit fullscreen mode

depending on your Kubernetes setup.

The request flow looks like:

User
   │
   ▼
NodePort (32000)
   │
   ▼
Service Port (123)
   │
   ▼
Target Port (3000)
   │
   ▼
Node.js Container
Enter fullscreen mode Exit fullscreen mode

Benefits of Using a Deployment

Deployments provide several production-grade capabilities:

Self-Healing

If a Pod crashes:

kubectl delete pod <pod-name>
Enter fullscreen mode Exit fullscreen mode

Kubernetes automatically creates a replacement Pod.


Scaling

Increase replicas easily:

replicas: 5
Enter fullscreen mode Exit fullscreen mode

Apply again:

kubectl apply -f complete.yaml
Enter fullscreen mode Exit fullscreen mode

Kubernetes creates additional Pods automatically.


Rolling Updates

When a new Docker image version is pushed:

image: madhavnaks/node-app:v2
Enter fullscreen mode Exit fullscreen mode

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)