Today I completed a full real-world DevOps deployment where I built, containerized, and deployed a Node.js application using Docker, Kubernetes, Minikube, Ingress, HTTPS, and RBAC, all running on AWS EC2.
This project helped me connect all core DevOps concepts into one working system.
π§ Tech Stack Used
Node.js β Application layer
Docker (Multi-Stage Build) β Optimized container image
Docker Hub β Image registry
AWS EC2 (Linux) β Cloud infrastructure
Kubernetes (Minikube) β Container orchestration
kubectl β Cluster management
Kubernetes Deployment & Service
NodePort Service
Ingress Controller
HTTPS (TLS Certificates)
Docker Volumes & Networks
RBAC (Role & RoleBinding)
π§± Step 1: Node.js Application
I started with a simple Node.js web application that serves a static page to confirm deployment status.
π³ Step 2: Docker Multi-Stage Build
To keep the image lightweight and production-ready, I used a multi-stage Docker build:
FROM node:18 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
FROM node:18-alpine
WORKDIR /app
COPY --from=build /app .
EXPOSE 3000
CMD ["node", "app.js"]
Benefits:
Smaller image size
Faster deployments
Better security
π¦ Step 3: Push Image to Docker Hub
docker build -t /devops-node .
docker login
docker push /devops-node
Now the image is accessible from anywhere, including Kubernetes.
βοΈ Step 4: AWS EC2 Setup
Launched an EC2 Linux instance
Installed:
Docker
kubectl
Minikube
Ran Minikube inside EC2 to simulate a real Kubernetes environment
βΈοΈ Step 5: Kubernetes Deployment
Created a Deployment with multiple replicas:
apiVersion: apps/v1
kind: Deployment
metadata:
name: node-deploy
spec:
replicas: 2
selector:
matchLabels:
app: node
template:
metadata:
labels:
app: node
spec:
containers:
- name: node
image: /devops-node
ports:
- containerPort: 3000
Applied using:
kubectl apply -f deployment.yaml
π Step 6: Kubernetes Service (NodePort)
apiVersion: v1
kind: Service
metadata:
name: node-service
spec:
type: NodePort
selector:
app: node
ports:
- port: 80 targetPort: 3000
This exposed the app internally within the cluster.
π Step 7: Ingress Controller
Enabled ingress in Minikube:
minikube addons enable ingress
Ingress configuration:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: node-ingress
spec:
rules:
- host: devops.local
http:
paths:
- path: / pathType: Prefix backend: service: name: node-service port: number: 80
Mapped the domain in /etc/hosts:
devops.local
π Step 8: HTTPS with TLS
Generated certificates:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 \
-keyout key.pem -out cert.pem
Created Kubernetes TLS secret:
kubectl create secret tls node-tls --cert=cert.pem --key=key.pem
Updated ingress with TLS configuration and re-applied it.
The site now runs on HTTPS.
π¦ Step 9: Docker Volumes & Network
Created Docker volume for persistent data
Used Docker networks for container communication
Ensured clean separation of concerns
π Step 10: RBAC Security
Created a Role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: devops-role
rules:
- apiGroups: [""] resources: ["pods"] verbs: ["get", "list"]
Bound it using RoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: devops-binding
subjects:
- kind: User name: devops-user roleRef: kind: Role name: devops-role apiGroup: rbac.authorization.k8s.io
This ensured least-privilege access inside the cluster.
β Final Outcome
β Node.js app running on AWS EC2
β Docker multi-stage image pushed to Docker Hub
β Kubernetes Deployment & Service
β Ingress routing with HTTPS
β Persistent storage using volumes
β Secure access using RBAC
π― What I Learned
How real DevOps components connect end-to-end
Debugging Kubernetes ImagePullBackOff issues
Difference between NodePort, Service & Ingress
HTTPS using Kubernetes TLS secrets
Importance of RBAC in production clusters
Top comments (0)