This project teaches you the core building blocks of Kubernetes by deploying a real web application. Kubernetes is the platform that runs containers at scale — every major tech company uses it. This project gives you hands-on experience with the resources you will use every single day as a DevOps engineer. You will deploy a web application using four essential Kubernetes resources: a Deployment that manages your pods, a Service that exposes the app, a ConfigMap that injects configuration, and a HorizontalPodAutoscaler that scales automatically under load. kubectl apply -f *.yaml | v Kubernetes Cluster (minikube) | +----+----+----+ | | | | v v v v Pod Pod Pod Pod (Deployment manages these) | | | | +----+----+----+ | v Service (load balances between pods) | v http://localhost (your app is accessible!)
Running a single Docker container is fine for one developer. But in production, you need multiple replicas for reliability, automatic restarts when containers crash, rolling updates with zero downtime, and automatic scaling when traffic increases. Docker alone cannot do any of this. Kubernetes solves all of it. You declare your desired state — three replicas of my web app — and Kubernetes continuously works to make reality match that declaration. If a pod crashes, Kubernetes starts a new one. If a node fails, Kubernetes reschedules pods onto healthy nodes. If traffic spikes, the HorizontalPodAutoscaler adds more pods automatically.
### Step 1: Install minikube and kubectl minikube runs a single-node Kubernetes cluster on your laptop — perfect for learning without cloud costs. ```bash ## Install minikube curl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 sudo install minikube-linux-amd64 /usr/local/bin/minikube minikube version ## Expected: minikube version: v1.33.0 ## Install kubectl (the CLI for Kubernetes) curl -LO "https://dl.k8s.io/release/$(curl -Ls https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl kubectl version --client ## Expected: Client Version: v1.29.x ## Start the minikube cluster ## This creates a local Kubernetes cluster (takes 2-3 minutes) minikube start --driver=docker --memory=4096 --cpus=2 ## Verify the cluster is running kubectl cluster-info ## Expected: Kubernetes control plane is running at https://127.0.0.1:PORT kubectl get nodes ## Expected: minikube Ready control-plane 2m v1.29.x ``` > 📌 **Remember:** minikube is for learning only. In production, you use managed Kubernetes like Amazon EKS, Google GKE, or Azure AKS. The concepts you learn with minikube apply identically to all of these. ### Step 2: Understand the Key Kubernetes Concepts Before deploying, understand what each resource does: * **Pod** — the smallest unit in Kubernetes. One or more containers running together. Pods are temporary — when they crash, Kubernetes creates new ones. * **Deployment** — manages a group of identical pods. You tell it how many replicas you want. It creates pods, replaces crashed ones, and handles rolling updates. * **Service** — a stable network endpoint for your pods. Pods have changing IP addresses, but the Service IP never changes. Load balances traffic across all pods. * **ConfigMap** — stores configuration data (environment variables, config files) separately from your container image. Change config without rebuilding the image. * **HorizontalPodAutoscaler** — watches CPU/memory usage and adds or removes pods automatically. ### Step 3: Create the Application Manifests Create a directory for your Kubernetes files: ```bash mkdir k8s-first-deploy && cd k8s-first-deploy ``` Create `configmap.yaml` — configuration separate from the container: ```yaml apiVersion: v1 kind: ConfigMap metadata: name: webapp-config labels: app: webapp data: # These key-value pairs become environment variables in the pods APP_NAME: "DevOps Network App" APP_VERSION: "1.0.0" ENVIRONMENT: "learning" LOG_LEVEL: "info" # Multi-line values are also supported WELCOME_MESSAGE: | Welcome to Kubernetes! Running on DevOps Network Platform. ``` Create `deployment.yaml` — the core resource that runs your app: ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: webapp labels: app: webapp spec: # How many identical pod replicas to run replicas: 3 # Which pods this Deployment manages # Must match the labels in template.metadata.labels selector: matchLabels: app: webapp # Rolling update strategy — how to update pods without downtime strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # Create 1 extra pod during update maxUnavailable: 0 # Never reduce below desired count # Pod template — this is what each pod looks like template: metadata: labels: app: webapp # Must match selector.matchLabels version: v1 spec: containers: * name: webapp image: nginx:1.25-alpine # Using nginx as a simple web server ports: * containerPort: 80 name: http # Inject ConfigMap values as environment variables envFrom: * configMapRef: name: webapp-config # Resource requests and limits are IMPORTANT # requests = minimum guaranteed resources # limits = maximum the container can use resources: requests: memory: "64Mi" # 64 megabytes RAM minimum cpu: "50m" # 50 millicores CPU minimum limits: memory: "128Mi" # Never exceed 128MB RAM cpu: "200m" # Never exceed 0.2 CPU cores # Health checks tell Kubernetes if the pod is working # readinessProbe: is the pod ready to receive traffic? readinessProbe: httpGet: path: / port: 80 initialDelaySeconds: 5 periodSeconds: 10 # livenessProbe: should Kubernetes restart this pod? livenessProbe: httpGet: path: / port: 80 initialDelaySeconds: 15 periodSeconds: 20 failureThreshold: 3 # Restart after 3 consecutive failures ``` Create `service.yaml` — exposes the deployment: ```yaml apiVersion: v1 kind: Service metadata: name: webapp labels: app: webapp spec: # NodePort exposes the service on a port on every node # This is how minikube can reach your service from your laptop type: NodePort # Routes traffic to pods with this label selector: app: webapp ports: * name: http port: 80 # Port the Service listens on targetPort: 80 # Port on the pod to forward to nodePort: 30080 # Port on the node (30000-32767 range) ``` Create `hpa.yaml` — automatic scaling based on CPU: ```yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: webapp-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: webapp minReplicas: 2 # Never scale below 2 pods maxReplicas: 10 # Never scale above 10 pods metrics: * type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 # Scale up when avg CPU > 70% ``` ### Step 4: Deploy Everything ```bash ## Enable the metrics server (needed for HPA to work) minikube addons enable metrics-server ## Apply all manifests ## The order matters: ConfigMap first, then Deployment, then Service kubectl apply -f configmap.yaml kubectl apply -f deployment.yaml kubectl apply -f service.yaml kubectl apply -f hpa.yaml ## Or apply everything at once (Kubernetes handles order) kubectl apply -f . ## Watch pods starting up kubectl get pods --watch ## Expected: 3 pods starting, then showing Running 1/1 ## Check the deployment status kubectl get deployments ## Expected: ## NAME READY UP-TO-DATE AVAILABLE AGE ## webapp 3/3 3 3 60s ## Check the service kubectl get services ## Expected: ## NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE ## webapp NodePort 10.x.x.x <none> 80:30080/TCP 60s ## Access the application minikube service webapp --url ## Expected: http://127.0.0.1:PORT ## Open this URL in your browser ``` ### Step 5: Explore and Troubleshoot These are the most important commands for daily Kubernetes work: ```bash ## Describe a pod — see events, resource usage, volumes kubectl describe pod webapp-POD-NAME ## Look at the Events section at the bottom — shows what happened ## View logs from a pod kubectl logs webapp-POD-NAME ## Follow logs in real time kubectl logs -f webapp-POD-NAME ## Get logs from all pods with the label app=webapp kubectl logs -l app=webapp ## Execute a command inside a running pod kubectl exec -it webapp-POD-NAME -- sh ## You are now inside the container! pwd # / env | grep APP # See environment variables from ConfigMap whoami # nginx exit # Leave the container ## See resource usage (needs metrics-server) kubectl top pods ## Expected: CPU and memory usage per pod ## See the HPA status kubectl get hpa ## Expected: TARGETS shows current CPU%, MINPODS, MAXPODS, REPLICAS ``` ### Step 6: Perform a Rolling Update A rolling update changes the container image without downtime — new pods start before old ones stop. ```bash ## Update the image to a newer nginx version kubectl set image deployment/webapp \ webapp=nginx:1.26-alpine ## Watch the rolling update happen kubectl rollout status deployment/webapp ## Expected: Waiting for rollout... then Successfully rolled out ## See the update history kubectl rollout history deployment/webapp ## Expected: Two revisions listed ## Rollback to the previous version kubectl rollout undo deployment/webapp kubectl rollout status deployment/webapp ## Expected: Successfully rolled out (back to old version) ## Verify the rollback kubectl get pods -o wide ## Expected: 3 new pods running the old image ``` > 💡 **Tip:** The `kubectl rollout undo` command is your emergency button in production. If you deploy a broken version, run this immediately and your traffic goes back to the last working version in under 30 seconds. ### Step 7: Test Pod Self-Healing ```bash ## Delete a pod manually — simulate a crash POD=$(kubectl get pods -l app=webapp \ -o jsonpath='{.items[0].metadata.name}') kubectl delete pod $POD ## Watch Kubernetes immediately create a replacement kubectl get pods --watch ## Expected: Old pod shows Terminating ## New pod appears immediately and reaches Running ## The Deployment always maintains 3 replicas kubectl get deployment webapp ## Expected: READY 3/3 within 30 seconds ```
```bash ## 1. Verify all 3 pods are running kubectl get pods -l app=webapp ## Expected: 3 pods, all STATUS=Running, READY=1/1 ## 2. Verify ConfigMap values are injected POD=$(kubectl get pods -l app=webapp \ -o jsonpath='{.items[0].metadata.name}') kubectl exec $POD -- env | grep APP_NAME ## Expected: APP_NAME=DevOps Network App ## 3. Verify the app responds APP_URL=$(minikube service webapp --url) curl $APP_URL ## Expected: Nginx HTML page ## 4. Verify load balancing works ## Run multiple requests and see different pod names in logs for i in {1..10}; do curl -s $APP_URL > /dev/null; done kubectl logs -l app=webapp --tail=5 ## Expected: Requests distributed across all 3 pods ## 5. Verify HPA is working kubectl get hpa webapp-hpa ## Expected: TARGETS shows current CPU% (likely <10%) ## Min and Max pods shown correctly ## 6. Verify rolling update leaves no downtime ## Run this in one terminal: while true; do curl -s -o /dev/null -w "%{http_code}\n" $APP_URL sleep 0.5 done ## In another terminal, trigger a rolling update: kubectl set image deployment/webapp webapp=nginx:1.26-alpine ## Expected: All responses remain 200 during the update ## 7. Clean up kubectl delete -f . minikube stop echo "Kubernetes project complete!" ```
This project teaches you the core building blocks of Kubernetes by deploying a real web application. Kubernetes is the p...
Running a single Docker container is fine for one developer. But in production, you need multiple replicas for reliabili...
Step 1: Install minikube and kubectl minikube runs a single-node Kubernetes cluster on your laptop — perfect for learnin...
...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.