Module 12: Capstone — DeployMart on Kubernetes
🎯 What You'll Build: A production-style Kubernetes platform for DeployMart with Django, Next.js, PostgreSQL, Redis, autoscaling, monitoring, security, TLS, GitOps, and disaster-recovery practices.
⏱️ Time: 10 hours
📋 Prerequisites: Module 11 — CI/CD Pipeline with GitHub Actions + ArgoCD
🎯 Difficulty: Advanced
You have now learned the individual pieces of Kubernetes.
In the previous modules, you:
- Created Kubernetes Deployments.
- Exposed applications through Services.
- Configured Ingress.
- Deployed Django and Next.js.
- Used ConfigMaps and Secrets.
- Created Kubernetes manifests.
- Built a GitHub Actions CI/CD pipeline.
- Used Kustomize for deployment configuration.
- Introduced ArgoCD and GitOps.
Now it is time to combine everything into one realistic platform.
This is the DeployMart Kubernetes Capstone.
The goal is not simply to make Pods run.
The goal is to design a platform that can:
- Scale application workloads.
- Recover from failed Pods.
- Store persistent data.
- Handle HTTP and HTTPS traffic.
- Monitor application health.
- Enforce network boundaries.
- Manage permissions.
- Automatically deploy changes.
- Support repeatable environments.
- Provide operational documentation.
- Recover from failures.
This is the point where Kubernetes stops being a collection of commands and becomes a platform-engineering discipline.
The Capstone Architecture
The final DeployMart platform looks like this:
1 Internet 2 │ 3 ▼ 4 ┌─────────────────┐ 5 │ Cloudflare / │ 6 │ Load Balancer │ 7 └────────┬────────┘ 8 │ 9 ▼ 10 ┌────────────────────────┐ 11 │ NGINX Ingress │ 12 │ Controller │ 13 └───────────┬────────────┘ 14 │ 15 ┌─────────────┴─────────────┐ 16 │ │ 17 api.deploymart.com app.deploymart.com 18 │ │ 19 ▼ ▼ 20 ┌─────────────────┐ ┌─────────────────┐ 21 │ Django Service │ │ Next.js Service │ 22 └────────┬────────┘ └────────┬────────┘ 23 │ │ 24 ┌─────┴─────┐ ┌─────┴─────┐ 25 ▼ ▼ ▼ ▼ 26 Django Django Next.js Next.js 27 Pods Pods Pods Pods 28 │ │ │ │ 29 └───── HPA: 3-10 ───────────┴───────────┘ 30 │ 31 ┌──────────┴───────────┐ 32 │ │ 33 ▼ ▼ 34 PostgreSQL Redis 35 StatefulSet Deployment 36 │ │ 37 ▼ ▼ 38 PVC Cache 39 │ 40 ▼ 41Persistent Storage 42 43 ┌─────────────────────────────────────┐ 44 │ Observability │ 45 │ │ 46 │ Prometheus → Metrics │ 47 │ Grafana → Dashboards │ 48 └─────────────────────────────────────┘ 49 50 ┌─────────────────────────────────────┐ 51 │ GitOps │ 52 │ │ 53 │ GitHub → GitHub Actions → ArgoCD │ 54 └─────────────────────────────────────┘ 55 56 ┌─────────────────────────────────────┐ 57 │ Security │ 58 │ │ 59 │ RBAC + NetworkPolicies + TLS │ 60 └─────────────────────────────────────┘
The architecture contains several independent layers.
1Traffic 2 ↓ 3Ingress 4 ↓ 5Application 6 ↓ 7Data 8 ↓ 9Observability 10 ↓ 11Security 12 ↓ 13GitOps
Understanding these boundaries is more important than memorizing individual YAML fields.
Capstone Goals
By the end of this project, you should have a repository that can reproduce the DeployMart platform from configuration.
The platform should contain:
1Django 2Next.js 3PostgreSQL 4Redis 5NGINX Ingress 6cert-manager 7Prometheus 8Grafana 9ArgoCD 10Kustomize 11HPA 12NetworkPolicies 13RBAC 14Persistent Storage
You should also be able to demonstrate:
1Code change 2 ↓ 3CI 4 ↓ 5Docker image 6 ↓ 7GitOps update 8 ↓ 9ArgoCD 10 ↓ 11Kubernetes rollout
and:
1Traffic increase 2 ↓ 3HPA 4 ↓ 5More Pods
and:
1Pod failure 2 ↓ 3Kubernetes detects failure 4 ↓ 5Replacement Pod 6 ↓ 7Service continues routing traffic
Step 1: Organize the Repository
A scalable project structure should separate reusable base configuration from environment-specific configuration.
1deploymart-gitops/ 2├── base/ 3│ ├── namespace.yaml 4│ ├── backend-deployment.yaml 5│ ├── backend-service.yaml 6│ ├── frontend-deployment.yaml 7│ ├── frontend-service.yaml 8│ ├── postgres-statefulset.yaml 9│ ├── postgres-service.yaml 10│ ├── redis-deployment.yaml 11│ ├── redis-service.yaml 12│ ├── ingress.yaml 13│ ├── hpa.yaml 14│ ├── network-policy.yaml 15│ └── kustomization.yaml 16│ 17├── overlays/ 18│ ├── development/ 19│ │ ├── kustomization.yaml 20│ │ └── patches.yaml 21│ │ 22│ └── production/ 23│ ├── kustomization.yaml 24│ └── patches.yaml 25│ 26├── monitoring/ 27│ ├── prometheus/ 28│ └── grafana/ 29│ 30└── docs/ 31 ├── architecture.md 32 ├── runbook.md 33 └── adr/
This structure allows you to maintain one base architecture while changing settings for each environment.
Step 2: Use Kustomize Base and Overlays
The base contains common resources.
For example:
1apiVersion: kustomize.config.k8s.io/v1beta1 2kind: Kustomization 3 4resources: 5 - namespace.yaml 6 - backend-deployment.yaml 7 - backend-service.yaml 8 - frontend-deployment.yaml 9 - frontend-service.yaml 10 - postgres-statefulset.yaml 11 - postgres-service.yaml 12 - redis-deployment.yaml 13 - redis-service.yaml 14 - ingress.yaml 15 - hpa.yaml 16 - network-policy.yaml
The development environment can reference the base:
1apiVersion: kustomize.config.k8s.io/v1beta1 2kind: Kustomization 3 4namespace: deploymart-dev 5 6resources: 7 - ../../base
Production can use the same base:
1apiVersion: kustomize.config.k8s.io/v1beta1 2kind: Kustomization 3 4namespace: deploymart 5 6resources: 7 - ../../base
The important concept is:
1 Base 2 │ 3 ┌───────┴───────┐ 4 ▼ ▼ 5 Development Production 6 │ │ 7 smaller larger 8 resources resources
This prevents you from maintaining completely separate copies of every Kubernetes manifest.
Step 3: Deploy Django for Production
The Django Deployment should use multiple replicas.
A simplified configuration:
1apiVersion: apps/v1 2kind: Deployment 3 4metadata: 5 name: deploymart-backend 6 7spec: 8 replicas: 3 9 10 selector: 11 matchLabels: 12 app: deploymart-backend 13 14 template: 15 metadata: 16 labels: 17 app: deploymart-backend 18 19 spec: 20 containers: 21 - name: django 22 image: ghcr.io/example/deploymart-backend:1.0.0 23 24 ports: 25 - containerPort: 8000 26 27 resources: 28 requests: 29 cpu: "250m" 30 memory: "256Mi" 31 32 limits: 33 cpu: "1" 34 memory: "512Mi" 35 36 readinessProbe: 37 httpGet: 38 path: /health/ 39 port: 8000 40 41 livenessProbe: 42 httpGet: 43 path: /health/ 44 port: 8000
Three replicas provide a better starting point for the production environment than a single Pod.
The important principle is:
Never assume one application Pod is sufficient for a highly available web workload.
Actual availability depends on many other factors, including node failures, topology, database availability, and cluster architecture.
Step 4: Configure Horizontal Pod Autoscaling
The application should be able to scale when demand increases.
For example:
1apiVersion: autoscaling/v2 2kind: HorizontalPodAutoscaler 3 4metadata: 5 name: deploymart-backend 6 7spec: 8 scaleTargetRef: 9 apiVersion: apps/v1 10 kind: Deployment 11 name: deploymart-backend 12 13 minReplicas: 3 14 maxReplicas: 10 15 16 metrics: 17 - type: Resource 18 resource: 19 name: cpu 20 target: 21 type: Utilization 22 averageUtilization: 70
The frontend can have its own HPA:
1apiVersion: autoscaling/v2 2kind: HorizontalPodAutoscaler 3 4metadata: 5 name: deploymart-frontend 6 7spec: 8 scaleTargetRef: 9 apiVersion: apps/v1 10 kind: Deployment 11 name: deploymart-frontend 12 13 minReplicas: 3 14 maxReplicas: 10 15 16 metrics: 17 - type: Resource 18 resource: 19 name: cpu 20 target: 21 type: Utilization 22 averageUtilization: 70
The flow becomes:
1Low traffic 2 ↓ 33 Pods 4 5Traffic increases 6 ↓ 7CPU utilization increases 8 ↓ 9HPA evaluates metrics 10 ↓ 114 → 5 → 6 Pods
HPA is not simply "automatic scaling because traffic exists." It makes scaling decisions based on configured metrics and the available metrics pipeline.
Step 5: PostgreSQL StatefulSet
Unlike Django and Next.js, PostgreSQL stores important state.
That changes how you deploy it.
A Deployment is generally intended for stateless workloads.
A StatefulSet provides stable identity and works with persistent storage.
A simplified PostgreSQL StatefulSet might look like:
1apiVersion: apps/v1 2kind: StatefulSet 3 4metadata: 5 name: postgres 6 7spec: 8 serviceName: postgres 9 replicas: 1 10 11 selector: 12 matchLabels: 13 app: postgres 14 15 template: 16 metadata: 17 labels: 18 app: postgres 19 20 spec: 21 containers: 22 - name: postgres 23 image: postgres:16 24 25 ports: 26 - containerPort: 5432 27 28 env: 29 - name: POSTGRES_DB 30 value: deploymart 31 32 - name: POSTGRES_USER 33 value: deploymart 34 35 - name: POSTGRES_PASSWORD 36 valueFrom: 37 secretKeyRef: 38 name: postgres-secret 39 key: password 40 41 volumeMounts: 42 - name: postgres-data 43 mountPath: /var/lib/postgresql/data 44 45 volumeClaimTemplates: 46 - metadata: 47 name: postgres-data 48 49 spec: 50 accessModes: 51 - ReadWriteOnce 52 53 resources: 54 requests: 55 storage: 20Gi
The important concept is:
1PostgreSQL 2 │ 3 ▼ 4Persistent Volume Claim 5 │ 6 ▼ 7Persistent Volume 8 │ 9 ▼ 10Storage
If the PostgreSQL Pod is recreated, the data should remain on persistent storage rather than existing only inside the container filesystem.
Persistent Storage Is Not a Backup
This distinction is critical.
A PVC provides persistence.
It does not automatically provide a complete disaster-recovery strategy.
Think of these as separate concepts:
1Persistence 2 ↓ 3Data survives Pod replacement 4 5Backup 6 ↓ 7Recover deleted/corrupted data 8 9Disaster Recovery 10 ↓ 11Recover from a larger infrastructure failure
A production database should have a tested backup and restoration strategy.
Step 6: Redis Deployment
Redis can be used for caching, sessions, queues, or other application-specific workloads.
A simplified Redis Deployment:
1apiVersion: apps/v1 2kind: Deployment 3 4metadata: 5 name: redis 6 7spec: 8 replicas: 1 9 10 selector: 11 matchLabels: 12 app: redis 13 14 template: 15 metadata: 16 labels: 17 app: redis 18 19 spec: 20 containers: 21 - name: redis 22 image: redis:7-alpine 23 24 ports: 25 - containerPort: 6379 26 27 resources: 28 requests: 29 cpu: "100m" 30 memory: "128Mi" 31 32 limits: 33 cpu: "500m" 34 memory: "256Mi"
Create a Service:
1apiVersion: v1 2kind: Service 3 4metadata: 5 name: redis 6 7spec: 8 selector: 9 app: redis 10 11 ports: 12 - port: 6379 13 targetPort: 6379
Django can then connect to:
1redis:6379
inside the Kubernetes namespace.
For production workloads that require Redis data durability or high availability, the architecture should be designed specifically for those requirements rather than treating a single Redis Pod as highly available.
Step 7: Configure Ingress
The public application should have clear traffic boundaries.
For example:
1api.deploymart.com 2 │ 3 ▼ 4Django Service 5 6app.deploymart.com 7 │ 8 ▼ 9Next.js Service
An Ingress can route these hosts:
1apiVersion: networking.k8s.io/v1 2kind: Ingress 3 4metadata: 5 name: deploymart-ingress 6 7spec: 8 ingressClassName: nginx 9 10 rules: 11 - host: api.deploymart.com 12 http: 13 paths: 14 - path: / 15 pathType: Prefix 16 backend: 17 service: 18 name: deploymart-backend 19 port: 20 number: 8000 21 22 - host: app.deploymart.com 23 http: 24 paths: 25 - path: / 26 pathType: Prefix 27 backend: 28 service: 29 name: deploymart-frontend 30 port: 31 number: 3000
This creates clean separation between frontend and backend traffic.
Step 8: Enable HTTPS with cert-manager
Production applications should use HTTPS.
Instead of manually creating certificates every time, cert-manager can automate certificate management when configured with an appropriate certificate authority and issuer.
Conceptually:
1Internet 2 ↓ 3HTTPS 4 ↓ 5Ingress 6 ↓ 7TLS certificate 8 ↓ 9Django / Next.js
A certificate resource can look like:
1apiVersion: cert-manager.io/v1 2kind: Certificate 3 4metadata: 5 name: deploymart-tls 6 7spec: 8 secretName: deploymart-tls 9 10 dnsNames: 11 - api.deploymart.com 12 - app.deploymart.com 13 14 issuerRef: 15 name: letsencrypt-prod 16 kind: ClusterIssuer
The actual ClusterIssuer configuration depends on your DNS and certificate setup.
Do not blindly copy certificate configuration into production without understanding the chosen challenge method.
Step 9: Secure the Application with NetworkPolicies
By default, Kubernetes networking may allow broad Pod-to-Pod communication depending on the cluster network implementation.
NetworkPolicies let you explicitly define permitted traffic.
For example, you may want:
1Internet 2 ↓ 3Ingress 4 ↓ 5Frontend 6 7Ingress 8 ↓ 9Backend 10 11Backend 12 ↓ 13PostgreSQL 14 15Backend 16 ↓ 17Redis
but prevent unrelated Pods from communicating with PostgreSQL.
A simplified policy could look like:
1apiVersion: networking.k8s.io/v1 2kind: NetworkPolicy 3 4metadata: 5 name: postgres-policy 6 7spec: 8 podSelector: 9 matchLabels: 10 app: postgres 11 12 policyTypes: 13 - Ingress 14 15 ingress: 16 - from: 17 - podSelector: 18 matchLabels: 19 app: deploymart-backend 20 21 ports: 22 - protocol: TCP 23 port: 5432
Now PostgreSQL accepts traffic only from Pods matching:
1app: deploymart-backend
NetworkPolicies require a compatible network implementation in the cluster.
Step 10: Apply Least-Privilege RBAC
RBAC controls what Kubernetes identities are allowed to do.
Avoid giving an application:
1cluster-admin
unless there is a compelling and carefully reviewed reason.
A basic RBAC model is:
1User / ServiceAccount 2 ↓ 3Role / ClusterRole 4 ↓ 5RoleBinding / ClusterRoleBinding 6 ↓ 7Allowed Kubernetes API actions
For example:
1apiVersion: v1 2kind: ServiceAccount 3 4metadata: 5 name: deploymart-backend 6 namespace: deploymart
Then define only the permissions the workload actually requires.
The principle is:
If the application does not need permission, do not grant it.
Step 11: Run Containers as Non-Root
Container security should begin inside the Pod specification.
For example:
1securityContext: 2 runAsNonRoot: true 3 allowPrivilegeEscalation: false 4 capabilities: 5 drop: 6 - ALL
You may also configure:
1securityContext: 2 seccompProfile: 3 type: RuntimeDefault
Not every application can immediately support every hardening option, so test these settings with your actual image.
The goal is to reduce the privileges available if a container is compromised.
Step 12: Add Prometheus Monitoring
A production platform needs visibility.
Prometheus collects metrics from applications and infrastructure.
The monitoring architecture is:
1Applications 2 │ 3 ▼ 4Metrics 5 │ 6 ▼ 7Prometheus 8 │ 9 ▼ 10Time-series data 11 │ 12 ▼ 13Grafana 14 │ 15 ▼ 16Dashboards
Useful metrics include:
- CPU utilization.
- Memory usage.
- Request rate.
- Request latency.
- Error rate.
- Pod restarts.
- Deployment status.
- Node health.
- Database metrics.
- HTTP response codes.
The Four Golden Signals
For application monitoring, learn the four golden signals:
Latency
How long requests take.
1p50 2p95 3p99
Percentiles are usually more informative than only looking at averages.
Traffic
How much demand the application is receiving.
For example:
1requests/second
Errors
How many requests are failing.
For example:
1HTTP 5xx rate
Saturation
How close the system is to its capacity.
Examples include:
1CPU utilization 2Memory utilization 3Connection pool usage 4Disk usage
These four signals provide a useful starting point for understanding production behavior.
Step 13: Build Grafana Dashboards
Grafana visualizes metrics collected by Prometheus.
A useful DeployMart dashboard could contain:
1┌─────────────────────────────────────────────┐ 2│ DeployMart Production │ 3├──────────────────┬──────────────────────────┤ 4│ Request Rate │ Error Rate │ 5│ 2.4k req/min │ 0.12% │ 6├──────────────────┼──────────────────────────┤ 7│ P95 Latency │ CPU Usage │ 8│ 180 ms │ 61% │ 9├──────────────────┼──────────────────────────┤ 10│ Memory Usage │ Pod Count │ 11│ 2.4 GB │ 6 / 10 │ 12└──────────────────┴──────────────────────────┘
A dashboard should answer operational questions quickly.
For example:
Is the application currently healthy?
Are errors increasing?
Is latency increasing?
Is Kubernetes scaling the application?
Is a node running out of resources?
A dashboard full of graphs is not automatically useful. The metrics should support decisions.
Step 14: Monitor Kubernetes Events
Metrics are important, but Kubernetes events can reveal deployment problems quickly.
Run:
1kubectl get events \ 2 -n deploymart \ 3 --sort-by='.lastTimestamp'
Look for events involving:
- Failed scheduling.
- Image pull errors.
- Failed mounts.
- Probe failures.
- Container restarts.
- Failed deployments.
This can be one of the fastest ways to understand why a workload is unhealthy.
Step 15: Create Production Alerts
Monitoring without alerts often means someone discovers a problem after users do.
Useful alerts include:
1High error rate 2High latency 3Pod crash loops 4High CPU 5High memory 6Disk nearly full 7Database unavailable 8Deployment unavailable 9Certificate expiration
For example:
1HTTP 5xx rate 2 │ 3 ▼ 4above threshold 5 │ 6 ▼ 7Prometheus alert 8 │ 9 ▼ 10Alerting system 11 │ 12 ▼ 13Engineering team
Alert thresholds should be based on your application's actual behavior rather than arbitrary numbers.
Step 16: Connect CI/CD to the Capstone
Your Module 11 pipeline now becomes part of the production platform.
The complete workflow is:
1Developer 2 │ 3 ▼ 4GitHub 5 │ 6 ▼ 7GitHub Actions 8 │ 9 ├── Tests 10 ├── Build 11 ├── Security checks 12 └── Push image 13 │ 14 ▼ 15 Container Registry 16 │ 17 ▼ 18 GitOps Repository 19 │ 20 ▼ 21 ArgoCD 22 │ 23 ▼ 24 Kubernetes 25 │ 26 ┌─────┴─────┐ 27 ▼ ▼ 28 Django Next.js 29 │ 30 ┌───┴────┐ 31 ▼ ▼ 32PostgreSQL Redis
This is the central DevOps lifecycle for the capstone.
Step 17: Add Deployment Safety
A production deployment should not simply replace every Pod immediately.
Use rolling deployments.
For example:
1strategy: 2 type: RollingUpdate 3 4 rollingUpdate: 5 maxUnavailable: 0 6 maxSurge: 1
This can help maintain application capacity while new Pods are introduced.
Combined with readiness probes:
1Old Pod 2 │ 3 │ running 4 ▼ 5New Pod starts 6 │ 7 ▼ 8Readiness check 9 │ 10 ├── FAIL → keep old Pod 11 │ 12 └── PASS 13 │ 14 ▼ 15 route traffic 16 │ 17 ▼ 18 remove old Pod
This is much safer than blindly replacing all application instances.
Step 18: Test Failure Recovery
A production-style platform must be tested under failure.
Do not simply verify that everything works when everything is healthy.
Delete a Django Pod:
1kubectl delete pod <backend-pod> -n deploymart
Then watch:
1kubectl get pods -n deploymart -w
You should see Kubernetes create a replacement.
The flow is:
1Pod deleted 2 ↓ 3Deployment notices replica count 4 ↓ 5New Pod created 6 ↓ 7Container starts 8 ↓ 9Readiness probe passes 10 ↓ 11Service routes traffic
This demonstrates Kubernetes reconciliation.
Step 19: Test Horizontal Scaling
Scale the application manually first:
1kubectl scale deployment deploymart-backend \ 2 --replicas=5 \ 3 -n deploymart
Check:
1kubectl get pods -n deploymart
Then restore the desired HPA-controlled configuration.
The important lesson is:
Scaling is a desired-state operation, not manual server management.
Step 20: Test a Bad Deployment
A valuable production exercise is intentionally deploying a broken version in a development environment.
For example, deploy an image that does not start correctly.
Observe:
1Deployment 2 ↓ 3New Pod 4 ↓ 5Container fails 6 ↓ 7CrashLoopBackOff
Inspect:
1kubectl get pods -n deploymart
Then:
1kubectl describe pod <pod-name> -n deploymart
and:
1kubectl logs <pod-name> -n deploymart
Finally, use GitOps to restore the previous known-good image.
This exercise teaches more than simply reading a successful deployment log.
Step 21: Disaster Recovery Plan
A production platform needs a recovery plan.
At minimum, document:
1What is backed up? 2Where are backups stored? 3How often are backups created? 4How long are they retained? 5Who can restore them? 6How is restoration tested? 7What happens if the cluster is lost?
For PostgreSQL, your recovery plan might include:
1PostgreSQL 2 ↓ 3Scheduled backup 4 ↓ 5Object storage 6 ↓ 7Retention policy 8 ↓ 9Restore test
The most important part is testing restoration.
A backup that has never been restored is an assumption, not a verified recovery strategy.
RPO and RTO
Two important disaster-recovery concepts are:
Recovery Point Objective
RPO asks:
How much data can we afford to lose?
For example:
1RPO = 15 minutes
means your recovery design aims to limit potential data loss to approximately 15 minutes.
Recovery Time Objective
RTO asks:
How quickly must the service be restored?
For example:
1RTO = 1 hour
means the recovery process should aim to restore service within approximately one hour.
These numbers should come from business requirements, not from arbitrary technical preferences.
Step 22: Create a Runbook
A runbook tells an engineer what to do during common incidents.
Create:
1docs/runbook.md
Include procedures such as:
Application Is Down
1kubectl get pods -n deploymart 2kubectl get deployments -n deploymart 3kubectl get ingress -n deploymart
Then inspect unhealthy workloads.
High Error Rate
Check:
1kubectl logs deployment/deploymart-backend \ 2 -n deploymart
Then inspect:
- Recent deployments.
- Application logs.
- Database availability.
- Redis availability.
- Ingress errors.
- Prometheus metrics.
Database Is Unavailable
Check:
1kubectl get pods -l app=postgres -n deploymart
Then:
1kubectl describe pod <postgres-pod> -n deploymart
Also verify the PVC:
1kubectl get pvc -n deploymart
Deployment Is Stuck
Run:
1kubectl rollout status \ 2 deployment/deploymart-backend \ 3 -n deploymart
Then inspect:
1kubectl describe deployment \ 2 deploymart-backend \ 3 -n deploymart
Step 23: Architecture Decision Records
Large technical projects involve decisions.
Document important decisions using ADRs.
For example:
1docs/adr/ 2├── 001-use-kubernetes.md 3├── 002-use-argocd-gitops.md 4├── 003-use-postgresql.md 5├── 004-use-redis.md 6└── 005-use-prometheus-grafana.md
An ADR should explain:
1Decision 2Context 3Alternatives 4Consequences
For example:
1Decision: 2Use ArgoCD for Kubernetes deployment. 3 4Context: 5We need a GitOps-based deployment model. 6 7Alternatives: 8GitHub Actions running kubectl directly. 9 10Consequences: 11Git becomes the desired-state source of truth and ArgoCD continuously reconciles the cluster.
The goal is not to create documentation for the sake of documentation.
The goal is to preserve the reasoning behind important engineering decisions.
Step 24: Validate the Complete Platform
Before declaring the capstone complete, validate each layer.
Kubernetes Cluster
1kubectl get nodes
All required nodes should be available.
Application Pods
1kubectl get pods -n deploymart
Backend and frontend Pods should be healthy.
Services
1kubectl get services -n deploymart
Verify the expected Services exist.
Ingress
1kubectl get ingress -n deploymart
Verify host routing.
Persistent Storage
1kubectl get pvc -n deploymart
Verify PostgreSQL storage is bound.
HPA
1kubectl get hpa -n deploymart
Verify the desired scaling configuration.
ArgoCD
1kubectl get applications -n argocd
Verify the DeployMart application is synchronized and healthy.
NetworkPolicies
1kubectl get networkpolicies -n deploymart
Verify the expected network restrictions exist.
Capstone Validation Matrix
| Area | Validation |
|---|---|
| Kubernetes | Nodes healthy |
| Django | Multiple replicas running |
| Next.js | Multiple replicas running |
| PostgreSQL | Stateful workload + PVC |
| Redis | Service available |
| Ingress | Correct host routing |
| TLS | Certificate valid |
| HPA | Scaling configured |
| Monitoring | Prometheus collecting metrics |
| Dashboards | Grafana dashboard available |
| Security | RBAC + NetworkPolicies |
| Containers | Non-root where supported |
| GitOps | ArgoCD synchronized |
| CI/CD | GitHub Actions successful |
| Recovery | Pod failure tested |
| Backup | Restore process documented |
| Documentation | Runbook + ADRs |
Final Demo
Your capstone should finish with a short demonstration.
A five-minute demo can follow this sequence.
Minute 1: Architecture
Explain:
1Cloudflare / Load Balancer 2 ↓ 3Ingress 4 ↓ 5Django + Next.js 6 ↓ 7PostgreSQL + Redis
Minute 2: GitOps
Show:
1GitHub 2 ↓ 3GitHub Actions 4 ↓ 5Docker Registry 6 ↓ 7GitOps Repository 8 ↓ 9ArgoCD
Minute 3: Monitoring
Open Grafana and demonstrate:
- Request traffic.
- CPU usage.
- Memory usage.
- Error rate.
- Pod count.
Minute 4: Scaling
Generate additional application traffic or otherwise demonstrate the HPA behavior.
Show:
1kubectl get hpa -n deploymart
and:
1kubectl get pods -n deploymart
Minute 5: Failure Recovery
Delete an application Pod:
1kubectl delete pod <pod-name> -n deploymart
Then show Kubernetes replacing it.
This demonstrates that the platform is not simply deployed; it is actively reconciling and recovering workloads.
Capstone Deliverables
Your final project should contain the following.
Kubernetes Manifests
1base/ 2overlays/development/ 3overlays/production/
Include:
- Deployments.
- Services.
- StatefulSet.
- PVC.
- Ingress.
- HPA.
- ConfigMaps.
- Secrets.
- NetworkPolicies.
- RBAC.
CI/CD Pipeline
1GitHub Actions 2 ↓ 3Tests 4 ↓ 5Docker Build 6 ↓ 7Registry 8 ↓ 9GitOps Update
GitOps
1GitOps Repository 2 ↓ 3 ArgoCD 4 ↓ 5 Kubernetes
Monitoring
1Prometheus 2 ↓ 3Grafana
Include dashboards for application and infrastructure health.
Security
Demonstrate:
- Non-root containers where supported.
- Least-privilege RBAC.
- NetworkPolicies.
- Protected Git repositories.
- Secure secret handling.
- HTTPS.
Documentation
Include:
1README.md 2docs/architecture.md 3docs/runbook.md 4docs/adr/
Demo
Create a five-minute walkthrough demonstrating:
1Deployment 2Monitoring 3Scaling 4GitOps 5Failure recovery
Production Readiness Checklist
Use this checklist before considering DeployMart complete:
- Kubernetes manifests are stored in Git.
- Development and production overlays are separated.
- Django runs with multiple replicas.
- Next.js runs with multiple replicas.
- Readiness probes are configured.
- Liveness probes are configured.
- CPU and memory requests are defined.
- CPU and memory limits are reviewed.
- HPA is configured.
- PostgreSQL uses persistent storage.
- PostgreSQL backup strategy is documented.
- Redis is available to the backend.
- Ingress routes frontend and backend traffic.
- HTTPS is configured.
- NetworkPolicies restrict unnecessary traffic.
- RBAC follows least privilege.
- Containers run as non-root where supported.
- GitHub Actions runs automated tests.
- Docker images use traceable tags.
- Images are stored in a container registry.
- ArgoCD manages deployment state.
- GitOps rollback has been tested.
- Prometheus collects required metrics.
- Grafana dashboards are available.
- Alerts are configured for important failures.
- Pod failure recovery has been tested.
- Database recovery procedures are documented.
Final Exam
The final exam is designed to verify that you can operate the platform rather than simply copy its YAML.
Run the following checks:
1kubectl get nodes 2 3kubectl get pods -n deploymart 4 5kubectl get deployments -n deploymart 6 7kubectl get services -n deploymart 8 9kubectl get ingress -n deploymart 10 11kubectl get pvc -n deploymart 12 13kubectl get hpa -n deploymart 14 15kubectl get networkpolicies -n deploymart 16 17kubectl get applications -n argocd
Then perform the following tasks:
11. Deploy a new application version. 2 32. Verify the GitHub Actions workflow. 4 53. Verify that the Docker image was published. 6 74. Verify that the GitOps repository contains the new image tag. 8 95. Verify that ArgoCD detects the change. 10 116. Verify that Kubernetes performs the rollout. 12 137. Verify that the new Pods become Ready. 14 158. Demonstrate HPA configuration. 16 179. Delete one application Pod. 18 1910. Demonstrate that Kubernetes replaces it. 20 2111. Check Prometheus metrics. 22 2312. Open the Grafana dashboard. 24 2513. Explain the PostgreSQL backup and restore strategy. 26 2714. Explain your RBAC and NetworkPolicy design. 28 2915. Demonstrate how you would roll back a failed release.
A strong capstone submission should not only show that commands succeed.
You should be able to explain why each component exists and what happens when it fails.
Final Kubernetes Architecture
After completing all three Kubernetes modules, your learning path has evolved from a simple application deployment into a complete platform:
1 Internet 2 │ 3 ▼ 4 Cloudflare / LB 5 │ 6 ▼ 7 NGINX Ingress 8 Controller 9 │ │ 10 │ │ 11 api.domain app.domain 12 │ │ 13 ▼ ▼ 14 Django Next.js 15 Service Service 16 │ │ 17 ┌────┴───┐ ┌─┴──────┐ 18 │ │ │ │ 19 Pod Pod Pod Pod 20 │ 21 ├───────────────┐ 22 ▼ ▼ 23 PostgreSQL Redis 24 StatefulSet Deployment 25 │ 26 ▼ 27 PVC 28 │ 29 ▼ 30 Persistent Storage 31 32 ┌─────────────────┐ 33 │ Prometheus │ 34 └────────┬────────┘ 35 │ 36 ▼ 37 ┌───────────┐ 38 │ Grafana │ 39 └───────────┘ 40 41Developer 42 │ 43 ▼ 44 GitHub 45 │ 46 ▼ 47GitHub Actions 48 │ 49 ▼ 50Container Registry 51 │ 52 ▼ 53GitOps Repository 54 │ 55 ▼ 56 ArgoCD 57 │ 58 ▼ 59Kubernetes
The Complete DevOps Learning Journey
The most important achievement of this capstone is that you can now connect the technologies together.
1Docker 2 ↓ 3Containerization 4 ↓ 5Docker Compose 6 ↓ 7Kubernetes 8 ↓ 9Kubernetes Manifests 10 ↓ 11Ingress + Services 12 ↓ 13GitHub Actions 14 ↓ 15Container Registry 16 ↓ 17Kustomize 18 ↓ 19ArgoCD 20 ↓ 21GitOps 22 ↓ 23HPA 24 ↓ 25Prometheus + Grafana 26 ↓ 27Security 28 ↓ 29Disaster Recovery
You are no longer just deploying containers.
You are designing a system that can deploy, scale, observe, secure, and recover applications.
That is the real objective of the DeployMart capstone.
Final Takeaway
A production-grade Kubernetes platform is not defined by how much YAML it contains.
It is defined by how well it handles change and failure.
A strong platform should answer these questions:
1What happens when traffic increases? 2 ↓ 3 HPA 4 5What happens when a Pod crashes? 6 ↓ 7 Kubernetes reconciliation 8 9What happens when code changes? 10 ↓ 11 CI/CD + GitOps 12 13What happens when configuration changes? 14 ↓ 15 Git + ArgoCD 16 17What happens when a deployment fails? 18 ↓ 19 Rollback 20 21What happens when the database fails? 22 ↓ 23 Recovery strategy 24 25How do we know the system is healthy? 26 ↓ 27 Prometheus + Grafana 28 29Who can access Kubernetes? 30 ↓ 31 RBAC 32 33Which workloads can communicate? 34 ↓ 35 NetworkPolicies 36 37How is traffic protected? 38 ↓ 39 TLS 40 41How do we reproduce the platform? 42 ↓ 43 Infrastructure configuration in Git
If you can build and explain this architecture, troubleshoot its failures, demonstrate its scaling behavior, and recover from a bad deployment, you have completed the DeployMart Kubernetes capstone at a level that goes well beyond basic Kubernetes commands.
🎓 Capstone Complete: You have built the foundation of a production-style Kubernetes and GitOps platform. The next step is to deepen these skills with Helm, advanced Kustomize overlays, Kubernetes security, observability, service meshes, and cloud-native production operations.