Deploy Your First Application on Kubernetes
Learn Kubernetes fundamentals by deploying a web app with a Deployment, Service, ConfigMap, and HorizontalPodAutoscaler on a local cluster using minikube.
Domains & Technologies
Blueprint Walkthrough
Architecture Overview
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 vPod Pod Pod Pod (Deployment manages these) | | | | +----+----+----+ | v Service (load balances between pods) | v http://localhost (your app is accessible!)Problem Solved
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-by-Step Implementation Guide
Step 1: Install minikube and kubectl
minikube runs a single-node Kubernetes cluster on your laptop — perfect for learning without cloud costs.
## Install minikubecurl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64sudo install minikube-linux-amd64 /usr/local/bin/minikubeminikube 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/kubectlkubectl 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 runningkubectl 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.xRememberminikube 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:
mkdir k8s-first-deploy && cd k8s-first-deployCreate configmap.yaml — configuration separate from the container:
apiVersion: v1kind: ConfigMapmetadata: name: webapp-config labels: app: webappdata: # 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:
apiVersion: apps/v1kind: Deploymentmetadata: name: webapp labels: app: webappspec: # 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 failuresCreate service.yaml — exposes the deployment:
apiVersion: v1kind: Servicemetadata: name: webapp labels: app: webappspec: # 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:
apiVersion: autoscaling/v2kind: HorizontalPodAutoscalermetadata: name: webapp-hpaspec: 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
## 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 Servicekubectl apply -f configmap.yamlkubectl apply -f deployment.yamlkubectl apply -f service.yamlkubectl apply -f hpa.yaml ## Or apply everything at once (Kubernetes handles order)kubectl apply -f . ## Watch pods starting upkubectl get pods --watch## Expected: 3 pods starting, then showing Running 1/1 ## Check the deployment statuskubectl get deployments## Expected:## NAME READY UP-TO-DATE AVAILABLE AGE## webapp 3/3 3 3 60s ## Check the servicekubectl 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 applicationminikube service webapp --url## Expected: http://127.0.0.1:PORT## Open this URL in your browserStep 5: Explore and Troubleshoot
These are the most important commands for daily Kubernetes work:
## Describe a pod — see events, resource usage, volumeskubectl describe pod webapp-POD-NAME## Look at the Events section at the bottom — shows what happened ## View logs from a podkubectl logs webapp-POD-NAME## Follow logs in real timekubectl logs -f webapp-POD-NAME ## Get logs from all pods with the label app=webappkubectl logs -l app=webapp ## Execute a command inside a running podkubectl exec -it webapp-POD-NAME -- sh## You are now inside the container!pwd # /env | grep APP # See environment variables from ConfigMapwhoami # nginxexit # Leave the container ## See resource usage (needs metrics-server)kubectl top pods## Expected: CPU and memory usage per pod ## See the HPA statuskubectl get hpa## Expected: TARGETS shows current CPU%, MINPODS, MAXPODS, REPLICASStep 6: Perform a Rolling Update
A rolling update changes the container image without downtime — new pods start before old ones stop.
## Update the image to a newer nginx versionkubectl set image deployment/webapp \ webapp=nginx:1.26-alpine ## Watch the rolling update happenkubectl rollout status deployment/webapp## Expected: Waiting for rollout... then Successfully rolled out ## See the update historykubectl rollout history deployment/webapp## Expected: Two revisions listed ## Rollback to the previous versionkubectl rollout undo deployment/webappkubectl rollout status deployment/webapp## Expected: Successfully rolled out (back to old version) ## Verify the rollbackkubectl get pods -o wide## Expected: 3 new pods running the old imageTipThe
kubectl rollout undocommand 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
## Delete a pod manually — simulate a crashPOD=$(kubectl get pods -l app=webapp \ -o jsonpath='{.items[0].metadata.name}')kubectl delete pod $POD ## Watch Kubernetes immediately create a replacementkubectl get pods --watch## Expected: Old pod shows Terminating## New pod appears immediately and reaches Running ## The Deployment always maintains 3 replicaskubectl get deployment webapp## Expected: READY 3/3 within 30 secondsValidation & Testing
## 1. Verify all 3 pods are runningkubectl get pods -l app=webapp## Expected: 3 pods, all STATUS=Running, READY=1/1 ## 2. Verify ConfigMap values are injectedPOD=$(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 respondsAPP_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 logsfor i in {1..10}; do curl -s $APP_URL > /dev/null; donekubectl logs -l app=webapp --tail=5## Expected: Requests distributed across all 3 pods ## 5. Verify HPA is workingkubectl 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.5done## 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 upkubectl delete -f .minikube stopecho "Kubernetes project complete!"Videos & Guides
Kubernetes Tutorial for Beginners — TechWorld with Nana
Complete 4-hour Kubernetes beginner course covering all core concepts — pods, deployments, services, ConfigMaps, namespaces, Ingress, and Helm with hands-on examples.
Kubernetes Official Documentation — Concepts
Official Kubernetes documentation covering all core concepts including workloads, services, storage, configuration, security, and cluster administration.
kubectl Cheat Sheet — Official Reference
Official kubectl command reference covering get, describe, logs, exec, apply, delete, rollout, scale, and all essential commands for daily Kubernetes operations.