Deploying a Node.js Application with Kustomize on Minikube

5 min read• By Noel Tandap
Blog
Learn to deploy a Node.js app on Minikube using Kustomize. Manage dev, staging, and prod environments effortlessly without complex templates or duplicate YAML.

Introduction

In this article, we will explore how to deploy a Node.js application using Kustomize on a Minikube cluster. We will cover the project structure, Dockerfile setup, Kubernetes manifests, and how to use Kustomize to manage different configurations for development, staging, and production environments. We will also discuss the advantages of using Kustomize over other alternatives.

Prerequisites

Before we begin, ensure you have the following installed on your machine:

Project Structure

Here is the structure of our project:

profile-app/ structure
profile-app/
├── config/
│ └── config.json
├── k8s/
│ ├── base/
│ │ ├── deployment.yaml
│ │ ├── service.yaml
│ │ ├── pvc.yaml
│ │ ├── namespace.yaml
│ │ └── kustomization.yaml
│ └── overlays/
│ ├── dev/
│ │ ├── config.json
│ │ └── kustomization.yaml
│ ├── prod/
│ │ ├── config.json
│ │ └── kustomization.yaml
│ └── staging/
│ ├── config.json
│ └── kustomization.yaml
├── app.js
├── package.json
├── Dockerfile
└── docs/
└── readme.md

Application Code

app.js

app.js
1const express = require("express");
2const fs = require("fs");
3const app = express();
4const PORT = process.env.PORT || 3001;
5// Read the mounted config file
6const CONFIG_PATH = "./config/config.json";
7let config = { name: "Noel Bansikah", role: "DevOps Engineer", nameColor: "black", roleColor: "gray", environment: "development" };
8// Check if the config file exists
9if (fs.existsSync(CONFIG_PATH)) {
10 config = JSON.parse(fs.readFileSync(CONFIG_PATH, "utf-8"));
11}
12// Define a color map for meaningful colors
13const colorMap = {
14 black: "#000000",
15 gray: "#6c757d",
16 blue: "#007BFF",
17 yellow: "#FFC107",
18 red: "#DC3545",
19 green: "#28A745"
20};
21// Get the colors from the config or default to black and gray
22const nameColor = colorMap[config.nameColor] || colorMap.black;
23const roleColor = colorMap[config.roleColor] || colorMap.gray;
24app.get("/", (req, res) => {
25 res.send(`
26 <html>
27 <body style="background-color: white; text-align: center; padding: 50px;">
28 <h1 style="color: ${nameColor};">Hello, I am ${config.name} 🚀</h1>
29 <h2 style="color: ${roleColor};">Role: ${config.role}</h2>
30 <h3>Environment: ${config.environment}</h3>
31 <p>GitHub: <a href="https://github.com/bansikah22">bansikah22</a></p>
32 <p>GitLab: <a href="https://gitlab.com/tandapnoelbansikah">bansikah22</a></p>
33 <p>LinkedIn: <a href="https://linkedin.com/in/tandapnoelbansikah">bansikah22</a></p>
34 </body>
35 </html>
36 `);
37});
38app.listen(PORT, () => console.log(`Server running on port ${PORT}...`));

Dockerfile

Dockerfile
1# Stage 1: Build stage
2FROM node:18-alpine AS build
3WORKDIR /app
4COPY package.json package-lock.json ./
5RUN npm ci --production
6COPY app.js ./
7# Stage 2: Production stage
8FROM node:18-slim
9WORKDIR /app
10RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
11COPY --from=build /app/node_modules /app/node_modules
12COPY --from=build /app/app.js /app/app.js
13CMD ["node", "app.js"]
14EXPOSE 3001

Building and Pushing the Docker Image

To build and push the Docker image to Docker Hub, follow these steps:

  1. Build the Docker image:

Bash
docker build -t <your-dockerhub-username>/profile-app:latest .

2. Push the Docker image to Docker Hub:

Bash
docker push <your-dockerhub-username>/profile-app:latest

Replace <your-dockerhub-username> with your actual Docker Hub username.

Kubernetes Manifests

Base Manifests

The base directory contains the common configuration that is shared across all environments. This includes the deployment, service, PVC, and namespace definitions.

k8s/base/deployment.yaml

k8s/base/deployment.yaml
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4 name: profile-app
5spec:
6 replicas: 1
7 selector:
8 matchLabels:
9 app: profile-app
10 template:
11 metadata:
12 labels:
13 app: profile-app
14 spec:
15 containers:
16 - name: profile-app
17 image: <your-dockerhub-username>/profile-app:latest
18 imagePullPolicy: Always
19 ports:
20 - containerPort: 3001
21 volumeMounts:
22 - name: config-volume
23 mountPath: /app/config
24 subPath: config.json
25 readOnly: false
26 volumes:
27 - name: config-volume
28 configMap:
29 name: profile-app-config

k8s/base/service.yaml

k8s/base/service.yaml
1apiVersion: v1
2kind: Service
3metadata:
4 name: profile-service
5spec:
6 selector:
7 app: profile-app
8 ports:
9 - protocol: TCP
10 port: 80
11 targetPort: 3001
12 type: ClusterIP

k8s/base/pvc.yaml

k8s/base/pvc.yaml
1apiVersion: v1
2kind: PersistentVolumeClaim
3metadata:
4 name: profile-app-pvc
5spec:
6 accessModes:
7 - ReadWriteOnce
8 resources:
9 requests:
10 storage: 1Gi

k8s/base/namespace.yaml

k8s/base/namespace.yaml
1apiVersion: v1
2kind: Namespace
3metadata:
4 name: profile-app

k8s/base/kustomization.yaml

The kustomization.yaml file in the base directory defines the resources and images used in the base configuration.

k8s/base/kustomization.yaml
1resources:
2 - deployment.yaml
3 - service.yaml
4 - pvc.yaml
5 - namespace.yaml
6
7images:
8 - name: profile-app
9 newName: <your-dockerhub-username>/profile-app
10 newTag: latest

Overlays

The overlays directory contains environment-specific configurations. Each environment (dev, prod, staging) has its own directory with a config.json file and a kustomization.yaml file.

k8s/overlays/dev/config.json

k8s/overlays/dev/config.json
1{
2 "name": "Noel Bansikah",
3 "role": "DevOps Engineer and Software Developer",
4 "nameColor": "blue",
5 "roleColor": "green",
6 "environment": "development"
7}

k8s/overlays/dev/kustomization.yaml

k8s/overlays/dev/Kustomization.json
1namespace: dev
2resources:
3 - ../../base
4
5configMapGenerator:
6 - name: profile-app-config
7 files:
8 - config.json=config.json

k8s/overlays/prod/config.json

k8s/overlays/prod/config.json
1{
2 "name": "Noel Bansikah",
3 "role": "Senior DevOps Engineer",
4 "nameColor": "red",
5 "roleColor": "yellow",
6 "environment": "production"
7}

k8s/overlays/prod/kustomization.yaml

k8s/overlays/prod/kustomization.json
1namespace: prod
2resources:
3 - ../../base
4
5configMapGenerator:
6 - name: profile-app-config
7 files:
8 - config.json=config.json

k8s/overlays/staging/config.json

k8s/overlays/staging/config.json
1{
2 "name": "Noel Bansikah",
3 "role": "DevOps Engineer",
4 "nameColor": "green",
5 "roleColor": "blue",
6 "environment": "staging"
7}

k8s/overlays/staging/kustomization.yaml

k8s/overlays/staging/kustomization.json
1namespace: staging
2resources:
3 - ../../base
4
5configMapGenerator:
6 - name: profile-app-config
7 files:
8 - config.json=config.json

Using Kustomize

Kustomize is a tool that allows you to customize Kubernetes resource configurations. It provides a way to manage different configurations for different environments without duplicating YAML files. Kustomize is built into kubectl, making it easy to use.

Advantages of Kustomize

  • Declarative Management: Kustomize allows you to manage Kubernetes resources declaratively.

  • Environment-Specific Configurations: You can manage different configurations for different environments using overlays.

  • No Templating: Kustomize does not use templating, making it easier to understand and maintain.

  • Built into kubectl: Kustomize is integrated into kubectl, so you don't need to install any additional tools.

Alternatives to Kustomize

  • Helm: Helm is a package manager for Kubernetes that uses templating to manage configurations. While Helm is powerful and widely used, it can be more complex to manage compared to Kustomize.

  • Ksonnet: Ksonnet was another tool for managing Kubernetes configurations, but it has been deprecated in favor of Kustomize and Helm.

Why We Prefer Kustomize

We prefer Kustomize for our application because it provides a simple and declarative way to manage configurations for different environments. It is easy to use, integrated into kubectl, and does not require templating, making it easier to maintain.

Deploying the Application

1. Start Minikube

Bash
minikube start

2. Deploy to Kubernetes

// title: Bash // copy: true // lines: False // maxLines: 10 kubectl apply -k k8s/overlays/dev kubectl apply -k k8s/overlays/prod kubectl apply -k k8s/overlays/staging

3. Test the App

Port Forwarding

// title: Bash // copy: true // lines: False // maxLines: 10 kubectl port-forward -n dev svc/profile-service 8080:80 kubectl port-forward -n staging svc/profile-service 8081:80 kubectl port-forward -n prod svc/profile-service 8082:80

Access the App

Open your browser and navigate to:

developement access to app minikube
  • Staging: http://localhost:8081

    staging access to app minikube
  • Production: http://localhost:8082

    production access to app minikube

4. Verify Deployments

Bash
kubectl get pods -n dev
kubectl get pods -n staging
kubectl get pods -n prod
kubectl get services -n dev
kubectl get services -n staging
kubectl get services -n prod

5. Check Logs to Confirm Colors

Bash
kubectl logs -n dev deployment/profile-app
kubectl logs -n staging deployment/profile-app
kubectl logs -n prod deployment/profile-app

6. Test Persistent Storage

Check the Volume Mount

Bash
kubectl exec -n dev -it $(kubectl get pod -n dev -l app=profile-app -o jsonpath='{.items[0].metadata.name}') -- ls /app/config
Check the Volume Mount minikube

Restart the Pod & Check if Config Persists

Bash
kubectl delete pod -n dev -l app=profile-app
kubectl get pods -n dev -w

7. Verify the Updated Config

Bash
kubectl exec -n dev -it $(kubectl get pod -n dev -l app=profile-app -o jsonpath='{.items[0].metadata.name}') -- curl profile-service
Verify the Updated Config Minikube

Open http://localhost:8080 in your browser to see the updated configuration! 🎉

Conclusion

In this article, we explored how to deploy a Node.js application using Kustomize on a Minikube cluster. We covered the project structure, Dockerfile setup, Kubernetes manifests, and how to use Kustomize to manage different configurations for development, staging, and production environments. We also discussed the advantages of using Kustomize over other alternatives. LInk to the Code

If you have any questions or face any challenges, feel free to ask in the comments section below. Happy coding!

References

Happy coding! 🎉

© 2026 adorsys. Alle Rechte vorbehalten.
Certificate TopCompany Kununu
Certificate ISO 27001
Certificate ISO 9001