Skip to content

Kubernetes Capstone and Next Steps

Overview

You have progressed from your first Pod to GitOps delivery, autoscaling, observability, and cluster hardening. This capstone deploys VoteStack — the multi-service poll application from the Docker capstone — on a production-style Kubernetes cluster. You will wire every layer from the Module 6 tutorials into one cohesive project and document a roadmap to Terraform for infrastructure and GitLab CI/CD for enterprise pipelines.

This is Tutorial 20 — the finale of Module 6: Production and the complete REBASH Academy Kubernetes track.

Prerequisites

Learning Objectives

By the end of this capstone, you will be able to:

  • Deploy VoteStack on Kubernetes using a Helm chart and Argo CD
  • Configure HPA, PDB, and topology spread for api and worker tiers
  • Expose the app via Ingress with TLS and internal NetworkPolicies
  • Instrument services with Prometheus metrics and centralized logging
  • Apply Pod Security Standards and Kyverno policies to the stack
  • Document operational runbooks and a learning path to Terraform and GitLab

Architecture Diagram

flowchart TB
    subgraph External
        USER[Browser]
        DNS[votestack.example.com]
    end

    subgraph IngressLayer["ingress-nginx"]
        ING[Ingress + TLS]
    end

    subgraph Votestack["namespace: votestack"]
        WEB[web Deployment]
        API[api Deployment + HPA]
        WORK[worker Deployment + HPA]
        REDIS[redis StatefulSet]
        PG[postgres StatefulSet + PVC]
    end

    subgraph Platform
        ARGO[Argo CD]
        PROM["Prometheus / Grafana"]
        KYV[Kyverno]
    end

    USER --> DNS --> ING
    ING --> WEB
    ING --> API
    API --> REDIS
    API --> PG
    WORK --> REDIS
    WORK --> PG
    ARGO -.->|sync| Votestack
    PROM -.->|scrape| API
    KYV -.->|enforce| Votestack

Project Overview — VoteStack on Kubernetes

VoteStack mirrors the Docker capstone with Kubernetes-native primitives:

Service Kubernetes resource Notes
web Deployment + Service Static UI; 2 replicas
api Deployment + Service + HPA + PDB REST API; /health, /ready, /metrics
worker Deployment + HPA Queue consumer; scales on Redis depth
redis StatefulSet + headless Service Persistent queue (dev lab); use ElastiCache in prod
postgres StatefulSet + PVC Dev lab; use RDS/Cloud SQL in prod
edge Ingress TLS via cert-manager

Same container images built in the Docker track — only deployment manifests change.

Project Structure

votestack-gitops/
├── apps/
│   ├── root-app.yaml              # App-of-Apps bootstrap
│   └── votestack/
│       └── application.yaml
├── charts/
│   └── votestack/
│       ├── Chart.yaml
│       ├── values.yaml
│       ├── values-dev.yaml
│       ├── values-prod.yaml
│       └── templates/
│           ├── namespace.yaml
│           ├── web/
│           ├── api/
│           ├── worker/
│           ├── redis/
│           ├── postgres/
│           ├── ingress.yaml
│           ├── hpa.yaml
│           ├── pdb.yaml
│           ├── networkpolicy.yaml
│           └── servicemonitor.yaml
├── policies/
│   └── kyverno/
│       ├── require-limits.yaml
│       └── disallow-latest.yaml
└── README.md

Hands-on Lab

Lab 1 — Bootstrap GitOps (App of Apps)

apps/root-app.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: votestack-root
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/org/votestack-gitops.git
    targetRevision: main
    path: charts/votestack
    helm:
      valueFiles:
        - values-dev.yaml
  destination:
    server: https://kubernetes.default.svc
    namespace: votestack
  syncPolicy:
    automated:
      prune: true
      selfHeal: true
    syncOptions:
      - CreateNamespace=true
kubectl apply -f apps/root-app.yaml
argocd app sync votestack-root
kubectl get all -n votestack

Lab 2 — Stateful data tier

Postgres StatefulSet excerpt (templates/postgres/statefulset.yaml):

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres
  namespace: votestack
spec:
  serviceName: postgres
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      securityContext:
        fsGroup: 999
      containers:
        - name: postgres
          image: postgres:16-alpine
          envFrom:
            - secretRef:
                name: postgres-credentials
          ports:
            - containerPort: 5432
          volumeMounts:
            - name: data
              mountPath: /var/lib/postgresql/data
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: [ReadWriteOnce]
        resources:
          requests:
            storage: 10Gi

Apply SealedSecret for credentials (see Kubernetes Security Hardening).

Verify: kubectl get pvc -n votestack

Lab 3 — Ingress with TLS

Install cert-manager (once per cluster):

helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
  -n cert-manager --create-namespace \
  --set crds.enabled=true

Ingress template:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: votestack
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
  ingressClassName: nginx
  tls:
    - hosts: [votestack.example.com]
      secretName: votestack-tls
  rules:
    - host: votestack.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: votestack-api
                port:
                  number: 8080
          - path: /
            pathType: Prefix
            backend:
              service:
                name: votestack-web
                port:
                  number: 3000

Smoke test:

curl -sf https://votestack.example.com/api/health
curl -sf https://votestack.example.com/ -o /dev/null

Lab 4 — HPA, PDB, and spread (production patterns)

Enable in values-dev.yaml:

api:
  replicas: 2
  autoscaling:
    enabled: true
    minReplicas: 2
    maxReplicas: 8
    targetCPUUtilization: 70
  pdb:
    minAvailable: 1
  topologySpread:
    enabled: true

worker:
  autoscaling:
    enabled: true
    minReplicas: 1
    maxReplicas: 5

Sync and validate:

kubectl get hpa,pdb -n votestack
kubectl get pods -n votestack -o wide

Lab 5 — Observability stack integration

Add ServiceMonitor to Helm chart (see Monitoring and Logging). Import VoteStack Grafana dashboard. Confirm alerts:

kubectl port-forward svc/kube-prometheus-grafana -n monitoring 3000:80
# Dashboard: error rate, p99 latency, pod restarts

Log query in Loki:

{namespace="votestack"} | json | level="error"

Lab 6 — Security hardening checklist

Apply the full security stack from Tutorial 19:

# Pod Security
kubectl label namespace votestack \
  pod-security.kubernetes.io/enforce=restricted --overwrite

# NetworkPolicies
kubectl apply -f charts/votestack/templates/networkpolicy.yaml

# Kyverno policies
kubectl apply -f policies/kyverno/

# Verify
kubectl run bad --rm -it --image=nginx:latest -n votestack
# Expected: blocked by admission policy

Lab 7 — Operations runbook

# Backup postgres
kubectl exec -n votestack postgres-0 -- \
  pg_dump -U voteapp votes > "backups/votes-$(date +%Y%m%d).sql"

# Rollback via GitOps
cd votestack-gitops
git revert HEAD && git push
argocd app sync votestack-root

# Scale manually (temporary — prefer HPA)
kubectl scale deployment votestack-api -n votestack --replicas=5

# Node drain simulation (respects PDB)
kubectl drain <node> --ignore-daemonsets --delete-emptydir-data

Document results in README.md — architecture diagram, deploy steps, rollback procedure.

Commands & Code

# End-to-end status
kubectl get deploy,sts,svc,ingress,hpa,pdb -n votestack
argocd app get votestack-root

# End-to-end smoke
curl -sf https://votestack.example.com/api/health
curl -sf https://votestack.example.com/api/polls | jq .

# Debug chain
kubectl logs -n votestack deploy/votestack-api --tail=50
kubectl describe pod -n votestack -l app=votestack-api
kubectl get events -n votestack --sort-by='.lastTimestamp' | tail -10

Common Mistakes

Running postgres/redis in prod without backups

StatefulSets need backup automation and tested restore — or use managed databases.

Skipping TLS on Ingress

allowInsecure is for dev only — prod requires cert-manager or cloud LB certs.

Capstone without NetworkPolicies

A complete stack demo that ignores segmentation fails security interviews.

Manual kubectl edits in GitOps workflow

selfHeal reverts them — always change Git, not live cluster.

No resource requests on any tier

HPA and scheduling break — every container needs requests.

Best Practices

Portfolio README

Include architecture diagram, tech stack, and kubectl get screenshot — strong interview artifact.

Managed services in real prod

Replace in-cluster postgres/redis with RDS and ElastiCache — keep StatefulSets for learning labs.

Environment parity

Same Helm chart, different values files — dev/staging/prod differ only in replicas, hosts, and secrets backend.

Chaos exercise

Delete api pods during load test — observe HPA, PDB, and Ingress recovery.

Continue the platform path

Kubernetes completes orchestration — Terraform provisions the cluster itself.

Troubleshooting

Issue Cause Solution
Ingress 502 api not ready Check probes; postgres/redis connectivity
TLS not issued cert-manager misconfig kubectl describe certificate -n votestack
HPA no scale Missing metrics-server Install metrics-server; verify requests
Argo OutOfSync loop Helm hook or ignored diff Add ignoreDifferences for known fields
NetworkPolicy blocks traffic Missing DNS/ingress rule Add egress UDP 53; allow ingress namespace
PVC Pending No StorageClass kubectl get sc; set default class

Summary

  • The VoteStack Kubernetes capstone combines Helm, GitOps, Ingress, StatefulSets, HPA, PDB, observability, and security hardening
  • Same images from the Docker track — Kubernetes adds scheduling, scaling, segmentation, and declarative delivery
  • GitOps is the deployment interface — runbooks center on Git revert, Argo sync, and backup/restore
  • Production reality swaps in-cluster databases for managed services and clusters for Terraform-provisioned infrastructure
  • You have finished all 20 Kubernetes tutorials — continue to Terraform, GitLab CI/CD, and Learning Paths

Interview Questions

  1. Walk through VoteStack architecture on Kubernetes — from Ingress to postgres.
  2. Why use StatefulSet for postgres instead of Deployment?
  3. How does GitOps rollback differ from kubectl rollout undo?
  4. What would you change moving from dev cluster to production AWS EKS?
  5. Explain how HPA, PDB, and topology spread work together during a node upgrade.
  6. How do NetworkPolicies map to the Docker Compose internal network model?
  7. What metrics and alerts would you define for VoteStack in production?
  8. Why seal secrets instead of using Kubernetes Secrets directly in Git?
  9. How does this capstone demonstrate the full Kubernetes track skills?
  10. What is the natural next skill after completing Kubernetes?
Sample Answers (Questions 1, 4, and 10)

Q1 — K8s VoteStack flow: Browser resolves votestack.example.com → Ingress (TLS) routes /api to api Service → api pods (HPA-scaled, PDB-protected) validate and enqueue votes to redis. worker pods consume queue, write to postgres StatefulSet. web pods serve UI. NetworkPolicies restrict api to redis/postgres only. Prometheus scrapes /metrics; logs flow to Loki. Argo CD syncs all resources from Git.

Q4 — Dev to EKS prod: Provision EKS with Terraform (VPC, node groups, IRSA). Replace in-cluster postgres/redis with RDS and ElastiCache. Use ALB Ingress Controller and ACM certs. External Secrets for credentials. Multi-AZ node groups; Cluster Autoscaler. Centralized observability (AMP/Grafana or Datadog). GitOps with prod approval gates; separate AWS accounts for envs.

Q10 — After Kubernetes: Terraform for infrastructure-as-code — VPC, EKS/GKE, IAM, RDS. GitLab CI/CD for enterprise pipeline patterns. Service mesh (Istio/Linkerd) for advanced traffic management. Platform engineering — Internal Developer Platforms (Backstage, Crossplane). Return to Learning Paths for role-specific roadmaps.

Next Steps — Terraform and GitLab

Terraform track

Kubernetes clusters do not appear by magic. The Terraform track teaches:

Topic Delivers
HCL fundamentals Variables, modules, state
AWS/GCP/Azure providers VPC, subnets, security groups
EKS/GKE modules Managed control plane + node pools
IAM and IRSA Pod-level AWS permissions without static keys

VoteStack prod target architecture:

Terraform → EKS cluster + RDS + ElastiCache + ECR
GitOps repo → Helm deploys VoteStack to EKS
CI pipeline → builds images, updates tags

GitLab CI/CD track

The GitLab track complements GitHub Actions patterns from Tutorial 16:

  • Multi-environment deploy pipelines with manual approval gates
  • Container registry integrated with CI
  • GitLab Agent for Kubernetes (agent-based deploy alternative)
  • Compliance frameworks and audit trails

If your organization standardizes on GitLab, port the VoteStack CI workflow — build, scan, update GitOps manifest — to .gitlab-ci.yml.

flowchart LR
    DOCKER[Docker track ✓]
    K8S[Kubernetes track ✓]
    TF[Terraform track]
    GL["GitLab CI/CD"]
    LP[Learning Paths]

    DOCKER --> K8S
    K8S --> TF
    K8S --> GL
    TF --> LP
    GL --> LP
  1. Deploy VoteStack capstone as portfolio project
  2. Begin Terraform – Introduction — provision a lab EKS cluster
  3. Migrate VoteStack GitOps target from kind/minikube to Terraform-managed EKS
  4. Optional: GitLab CI/CD Overview — enterprise pipeline patterns
  5. Follow DevOps Engineer Learning Path for role certification goals

References

Congratulations

You have completed all 20 tutorials in the REBASH Academy Kubernetes track — from orchestration fundamentals through GitOps delivery, autoscaling, observability, security hardening, and the VoteStack capstone. Return to the Kubernetes Overview to review the curriculum, publish VoteStack as a portfolio project, and begin the Terraform track when you are ready to provision cloud infrastructure that runs your clusters.