blog / Build. Containerize. Deploy.—Node.js App in Minikube with Helm

Build. Containerize. Deploy.—Node.js App in Minikube with Helm

k8skubernetesdockernodejsSDE
May 24, 2025

You must’ve built a Node.js app and wondered, “Now what?” Localhost is great, but what if you want to simulate how things run in a real-world environment—without jumping straight into the deep end of cloud platforms?

That’s where this project comes in. We’ll create a full Kubernetes deployment—locally—using Minikube, Docker, and Helm. Think of it as your app's first real-world rehearsal, all happening on your machine. No cloud accounts. No surprises. Just a clean, practical way to learn how modern app deployment works.

What are we gonna do?

  1. Create a basic Node.js/Express application
  2. Containerize it with Docker
  3. Start a Minikube cluster
  4. Build the Docker image within Minikube’s environment
  5. Create a Helm chart for deployment
  6. Deploy the application using Helm
  7. Access the deployed application

Create a simple Node.js app

No point wasting time on this step—unless you've somehow made it this far without ever touching Express. In that case...Oopsie Daisy! 💀

Only this man can save you now @kirat_tw

Prerequisites → You'll need Docker, Minikube, kubectl, Helm, and WSL 2— just Google or YouTube will gladly show you how to install them.

It’s time we spin the minikube cluster!

You want your app to run in its own clean, isolated environment—enter pods. In real-world, production-grade setups, we use orchestration tools like Kubernetes to manage dozens (or thousands) of these pods across clusters (check out my other blog if you're curious).

But—we're not building the next Netflix (yet). So instead of spinning up a massive cloud cluster, we use Minikube. It's a handy tool that lets you run a single-node Kubernetes cluster right on your local machine. Perfect for development, testing, providing a simplified environment without needing a full-scale cloud cluster.

  1. Start Minikube with Docker driver
minikube start --driver=docker

Basically, this command starts a Minikube cluster and uses Docker as the driver ( other options are VMware, etc.—but Docker's the only one I actually know how to use 😌).

  1. Verify Cluster:
# Check cluster info
kubectl cluster-info

# Check nodes
kubectl get nodes

# Check Minikube status
minikube status

after smashing above commands and seeing exactly what’s in the screenshot—congrats, you’re basically a DevOps engineer already. Move on to the next step( If not… well, f**king ChatGPT it is. That’s what I did!)

Important: Docker Environment

minikube docker-env | Invoke-Expression
docker info | grep Name

→ Key points to keep in mind:

  • When working with Minikube, you need to build your Docker images inside Minikube's Docker environment, not your local environment. This is because Minikube runs its own Docker daemon separate from your host system.
  • This configuration is session-specific - if you open a new terminal, you'll need to run the command again
  • To revert back to your local Docker, close the terminal or run eval $(docker-env -u)

Let’s GO Docker

  1. To containerize our Node.js app, we need a Dockerfile sitting right next to it. Here's a simple one to get started:
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "start"]

Dockerfile is your app’s instructions for becoming a container—For now, just roll with this. (Yes, a deep-dive Docker blog is in the works, stay tuned.)

  1. Build an image (inside minikube’s docker enviroment)
eval $(minikube docker-env)   # connect to Minikube's Docker
docker build -t node-app:v1 .

The command docker build -t node-app:v1 . is used to create a Docker image from your app. You're basically telling Docker: “Take everything in this folder and package it using the Dockerfile here.” The -t flag lets you name the image (node-app) and give it a version tag (v1). The . at the end just means “use the current directory as the context”—that’s where Docker looks for the Dockerfile and everything it needs to build the image.

docker images | grep node-app # "node-app" is the name of the image

👆 this is what you should get!

Helm handling!

Okay! Helm is the most crucial part of this entire project—our main objective was to understand Helm.

It’s basically a package manager, just like npm for Node.js. Helm helps you install, upgrade, and manage applications on Kubernetes with ease.

Instead of writing long, repetitive YAML files for deployments, services, configs, etc., Helm lets you package everything into something called a "Helm Charts"—a reusable bundle of Kubernetes configs.

  1. Create new Helm chart
helm create my-node-app-chart

✒️ Note: This will create a directory, and that will seem bit overwhelming at start therefore would urge to you refer repository that exist in reference section of this at the bottom .

  1. Deploy with Helm
 helm install node-app ./my-node-app-chart

If you see this on your screen, well you’re good to go.

  1. Check deployment status
helm list

# Check pod status
kubectl get pods

# Check service details
kubectl get services

# View pod logs (pod-name get from 2nd cmd)
kubectl logs <pod-name> 

When you see this message, “App running on port 3000”, you’ve made it 😌. And in case you keep your cool, share your issue with ChatGPT, try to debug.🪰

Finally! Access your application

  1. Just one CMD away:
minikube service <service-name> --url

✒️ Note: When you hit cmd kubectl get services that’s your service name.

Above command provides a URL that you can use to access a service running in your Minikube cluster from your local machine. Kubernetes services run inside the cluster's network by default, services aren't accessible from outside

Understanding How Minikube Exposes a Node.js App

Kubernetes networking in Minikube works through layers to route traffic to your app. When you hit the app from your browser, it goes to Minikube’s IP (192.168.49.2) on a high NodePort (31391). That traffic is forwarded to a Kubernetes Service with a ClusterIP (10.105.x.x) on port 80, which then routes it to your Node.js Pod running on a private IP (172.17.0.x) and port 3000. Your app responds, and the data flows back the same way. This setup keeps things clean, modular, and accessible. Running minikube service my-node-app --url gives you the exact URL to access it.

Everything Has an End!

  1. Clean up your environment
# Delete the Helm deployment
helm uninstall node-app

# Stop Minikube (keeps your cluster configuration for later)
minikube stop

# Or completely delete the Minikube cluster if you're done
minikube delete

And thus we conclude our containerization of a simple Node.js app—Docker image built, Minikube cluster running, and Helm chart deployed. If you made it this far without breaking anything, you can now officially call yourself a DevOps guy.

References

→ GitHub Repo: https://github.com/puri-adityakumar/minikube_nodejs

→ Docker quick tutorial: https://www.youtube.com/watch?v=DQdB7wFEygo&pp=ygUGZG9ja2Vy

→ K8s : https://www.youtube.com/watch?v=TlHvYWVUZyc&pp=ygUDazhz