Production Note
In production, use external secret managers (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) integrated with Kubernetes via CSI driver or operators. Never commit secrets to version control.
Build, containerize, and deploy a full application to Kubernetes with ConfigMaps, Secrets, Services, Ingress, and scaling.
Imagine you've built a lemonade stand. Now you need to set it up in a busy marketplace. You need to 1) pack all your supplies (containerize), 2) pick a spot and set up the stand (deploy), 3) put up a sign so people can find you (service/ingress), 4) hire helpers when lines get long (scaling), and 5) protect the recipe (secrets). This lesson puts it all together.
# Create a dedicated namespace for isolation kubectl create namespace webapp-demo # Set it as default context (optional but convenient) kubectl config set-context --current --namespace=webapp-demo
# configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: webapp-config namespace: webapp-demo data: APP_ENV: "production" APP_PORT: "8080" LOG_LEVEL: "info" WELCOME_MESSAGE: "Welcome to SKILLY Kubernetes Demo!"
kubectl apply -f configmap.yaml
# Create secret imperatively (values auto base64-encoded) kubectl create secret generic webapp-secret \ --from-literal=DB_PASSWORD='s3cureP@ss!' \ --from-literal=API_KEY='sk-abc123xyz' \ -n webapp-demo
In production, use external secret managers (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault) integrated with Kubernetes via CSI driver or operators. Never commit secrets to version control.
# deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: webapp
namespace: webapp-demo
labels:
app: webapp
spec:
replicas: 3
selector:
matchLabels:
app: webapp
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0 # Zero-downtime deployment
template:
metadata:
labels:
app: webapp
version: v1
spec:
containers:
- name: webapp
image: nginx:1.25-alpine
ports:
- containerPort: 80
envFrom:
- configMapRef:
name: webapp-config
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: webapp-secret
key: DB_PASSWORD
resources:
requests:
cpu: 100m
memory: 64Mi
limits:
cpu: 250m
memory: 128Mi
livenessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 5
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: 80
initialDelaySeconds: 3
periodSeconds: 5
kubectl apply -f deployment.yaml # Watch pods come up kubectl get pods -w -n webapp-demo # Verify all 3 replicas are Running kubectl get deployment webapp -n webapp-demo
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: webapp-svc
namespace: webapp-demo
spec:
type: ClusterIP
selector:
app: webapp
ports:
- port: 80
targetPort: 80
protocol: TCP
kubectl apply -f service.yaml # Verify endpoints exist (should show 3 pod IPs) kubectl get endpoints webapp-svc -n webapp-demo # Quick test via port-forward kubectl port-forward svc/webapp-svc 8080:80 -n webapp-demo # Visit http://localhost:8080
# ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: webapp-ingress
namespace: webapp-demo
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.local
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: webapp-svc
port:
number: 80
kubectl apply -f ingress.yaml # On local machine, add to /etc/hosts (or C:\Windows\System32\drivers\etc\hosts) # 127.0.0.1 myapp.local # Verify ingress kubectl get ingress -n webapp-demo
# hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: webapp-hpa
namespace: webapp-demo
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: webapp
minReplicas: 3
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
kubectl apply -f hpa.yaml # Check HPA status kubectl get hpa -n webapp-demo
# Update the image version kubectl set image deployment/webapp webapp=nginx:1.26-alpine -n webapp-demo # Watch the rollout kubectl rollout status deployment/webapp -n webapp-demo # View rollout history kubectl rollout history deployment/webapp -n webapp-demo # If something goes wrong, rollback kubectl rollout undo deployment/webapp -n webapp-demo
# Run through entire verification echo "=== Namespace ===" kubectl get ns webapp-demo echo "=== ConfigMap ===" kubectl get configmap webapp-config -n webapp-demo echo "=== Secret ===" kubectl get secret webapp-secret -n webapp-demo echo "=== Deployment ===" kubectl get deployment webapp -n webapp-demo echo "=== Pods ===" kubectl get pods -n webapp-demo -o wide echo "=== Service ===" kubectl get svc webapp-svc -n webapp-demo echo "=== Endpoints ===" kubectl get endpoints webapp-svc -n webapp-demo echo "=== Ingress ===" kubectl get ingress -n webapp-demo echo "=== HPA ===" kubectl get hpa -n webapp-demo echo "=== Events ===" kubectl get events -n webapp-demo --sort-by=.lastTimestamp | tail -10
# Delete everything at once by removing the namespace kubectl delete namespace webapp-demo
| Issue | Check | Fix |
|---|---|---|
| Pods stuck in Pending | kubectl describe pod โ Events | Insufficient resources; reduce requests or add nodes |
| ImagePullBackOff | kubectl describe pod โ image name | Fix image name/tag or add imagePullSecrets |
| Service has no endpoints | kubectl get endpoints | Fix selector labels to match pod labels |
| Ingress returns 404 | kubectl describe ingress | Check service name, port, and ingressClassName |
| HPA shows <unknown> | kubectl top pods | Install metrics-server |