Deploy Todo App with Kustomize

Deploy Todo Application to Kubernetes using Kustomize

Learn environment-specific deployments with Kustomize overlays.

What You’ll Learn

  • Kustomize basics - Built into kubectl, no extra tools needed
  • Base + Overlays pattern - DRY (Don’t Repeat Yourself) configuration
  • Environment variants - Deploy same app to Docker Desktop, EKS with Docker Hub, and EKS with ECR
  • Storage differences - How storage varies between local and cloud
  • Service types - NodePort vs LoadBalancer

Prerequisites:

  • Completed Exercise 2 (MongoDB Todo App)
  • Docker images built and pushed (Exercise 2)
  • kubectl configured for Docker Desktop and/or EKS cluster

Understanding the Architecture

Three Deployment Targets

EnvironmentKubernetesImage RegistryStorageService Type
docker-desktopDocker Desktop K8sDocker HubhostpathNodePort
eks-dockerhubAWS EKSDocker Hub (public)EBS (gp3)LoadBalancer
eks-ecrAWS EKSAWS ECR (private)EBS (gp3)LoadBalancer

Key Differences to Handle

Storage:

  • Docker Desktop: Uses built-in hostpath provisioner (no StorageClass needed)
  • EKS: Requires explicit StorageClass with ebs.csi.eks.amazonaws.com provisioner

Networking:

  • Docker Desktop: NodePort for local access (http://localhost:30080)
  • EKS: LoadBalancer creates AWS ELB for internet access

Image Registry:

  • Docker Hub: Public, no authentication needed in cluster
  • ECR: Private, requires IAM permissions (handled by EKS node role)

Step 1: Create Directory Structure

Create the Kustomize layout

cd /path/to/todo-app
mkdir -p kubernetes/{base,overlays/{docker-desktop,eks-dockerhub,eks-ecr}}

Final structure

todo-app/
β”œβ”€β”€ kubernetes/
β”‚   β”œβ”€β”€ base/
β”‚   β”‚   β”œβ”€β”€ kustomization.yaml
β”‚   β”‚   β”œβ”€β”€ namespace.yaml
β”‚   β”‚   β”œβ”€β”€ mongodb-statefulset.yaml
β”‚   β”‚   β”œβ”€β”€ mongodb-service.yaml
β”‚   β”‚   β”œβ”€β”€ mongodb-init-job.yaml
β”‚   β”‚   β”œβ”€β”€ webapp-configmap.yaml
β”‚   β”‚   β”œβ”€β”€ mongo-express-deployment.yaml
β”‚   β”‚   β”œβ”€β”€ mongo-express-service.yaml
β”‚   β”‚   β”œβ”€β”€ webapp-deployment.yaml
β”‚   β”‚   └── webapp-service.yaml
β”‚   β”‚
β”‚   └── overlays/
β”‚       β”œβ”€β”€ docker-desktop/
β”‚       β”‚   β”œβ”€β”€ kustomization.yaml
β”‚       β”‚   β”œβ”€β”€ webapp-service-patch.yaml
β”‚       β”‚   └── mongo-express-service-patch.yaml
β”‚       β”‚
β”‚       β”œβ”€β”€ eks-dockerhub/
β”‚       β”‚   β”œβ”€β”€ kustomization.yaml
β”‚       β”‚   └── storageclass.yaml
β”‚       β”‚
β”‚       └── eks-ecr/
β”‚           β”œβ”€β”€ kustomization.yaml
β”‚           └── storageclass.yaml
β”‚
β”œβ”€β”€ webapp/
β”œβ”€β”€ docker-compose.yaml
└── ...

Step 2: Create Base Manifests

2.1 Namespace

Create kubernetes/base/namespace.yaml:

apiVersion: v1
kind: Namespace
metadata:
  name: todo-app

2.2 MongoDB StatefulSet and Service

Create kubernetes/base/mongodb-statefulset.yaml:

# Headless service for StatefulSet
apiVersion: v1
kind: Service
metadata:
  name: mongodb-service
  namespace: todo-app
spec:
  selector:
    app: mongodb
  ports:
  - port: 27017
    targetPort: 27017
  clusterIP: None  # Headless service for stable network identity

---
# StatefulSet with persistent storage
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mongodb
  namespace: todo-app
spec:
  serviceName: mongodb-service
  replicas: 1
  selector:
    matchLabels:
      app: mongodb
  template:
    metadata:
      labels:
        app: mongodb
    spec:
      containers:
      - name: mongodb
        image: mongo:latest
        ports:
        - containerPort: 27017
        volumeMounts:
        - name: mongodb-data
          mountPath: /data/db
        resources:
          requests:
            memory: "256Mi"
            cpu: "250m"
          limits:
            memory: "512Mi"
            cpu: "500m"
  volumeClaimTemplates:
  - metadata:
      name: mongodb-data
    spec:
      accessModes: ["ReadWriteOnce"]
      # StorageClass will be patched per environment
      storageClassName: ""  # Empty - will be set by overlay
      resources:
        requests:
          storage: 1Gi

Note: storageClassName: "" will be overridden by overlays.

2.3 MongoDB Initialization Job

Create kubernetes/base/mongodb-init-job.yaml:

apiVersion: batch/v1
kind: Job
metadata:
  name: mongodb-init
  namespace: todo-app
spec:
  template:
    spec:
      containers:
      - name: mongo-init
        image: mongo:latest
        command:
        - /bin/bash
        - -c
        - |
          sleep 10
          mongosh mongodb-service:27017/ToDoAppDb --eval '
            db.TodoItems.insertMany([
              {
                "Id": 1,
                "Name": "Learn Kubernetes",
                "IsComplete": false
              },
              {
                "Id": 2,
                "Name": "Deploy MongoDB",
                "IsComplete": true
              }
            ]);
            print("Database initialized successfully!");
          '          
      restartPolicy: OnFailure
  backoffLimit: 4

2.4 WebApp ConfigMap

Create kubernetes/base/webapp-configmap.yaml:

apiVersion: v1
kind: ConfigMap
metadata:
  name: webapp-config
  namespace: todo-app
data:
  MONGODB_HOST: "mongodb-service"
  MONGODB_PORT: "27017"
  MONGODB_DATABASE: "ToDoAppDb"

2.5 WebApp Deployment and Service

Create kubernetes/base/webapp-deployment.yaml:

# Service for WebApp
apiVersion: v1
kind: Service
metadata:
  name: todo-webapp-service
  namespace: todo-app
  labels:
    app: todo-webapp
spec:
  # Service type will be patched per environment
  type: LoadBalancer  # Default - will be overridden for docker-desktop
  selector:
    app: todo-webapp
  ports:
  - port: 80
    targetPort: 8080

---
# WebApp Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: todo-webapp
  namespace: todo-app
  labels:
    app: todo-webapp
spec:
  replicas: 2
  selector:
    matchLabels:
      app: todo-webapp
  template:
    metadata:
      labels:
        app: todo-webapp
    spec:
      containers:
      - name: webapp
        # Image will be replaced by Kustomize overlay
        image: todo-app:latest  # Placeholder - replaced by overlay
        imagePullPolicy: Always
        ports:
        - containerPort: 8080
        envFrom:
        - configMapRef:
            name: webapp-config
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"

2.6 Mongo Express Deployment and Service

Create kubernetes/base/mongo-express-deployment.yaml:

# Service for Mongo Express
apiVersion: v1
kind: Service
metadata:
  name: mongo-express-service
  namespace: todo-app
  labels:
    app: mongo-express
spec:
  # Service type will be patched per environment
  type: LoadBalancer  # Default - will be overridden for docker-desktop
  selector:
    app: mongo-express
  ports:
  - port: 80
    targetPort: 8081

---
# Mongo Express Deployment
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mongo-express
  namespace: todo-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mongo-express
  template:
    metadata:
      labels:
        app: mongo-express
    spec:
      containers:
      - name: mongo-express
        image: mongo-express:latest
        ports:
        - containerPort: 8081
        env:
        - name: ME_CONFIG_MONGODB_URL
          value: "mongodb://mongodb-service:27017"
        - name: ME_CONFIG_BASICAUTH_USERNAME
          value: "admin"
        - name: ME_CONFIG_BASICAUTH_PASSWORD
          value: "pass"
        resources:
          requests:
            memory: "128Mi"
            cpu: "100m"
          limits:
            memory: "256Mi"
            cpu: "200m"

2.7 Base Kustomization

Create kubernetes/base/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
  - namespace.yaml
  - mongodb-statefulset.yaml
  - mongodb-init-job.yaml
  - webapp-configmap.yaml
  - mongo-express-deployment.yaml
  - webapp-deployment.yaml

Step 3: Create Overlay for Docker Desktop

3.1 Docker Desktop Kustomization

Create kubernetes/overlays/docker-desktop/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: todo-app

resources:
  - ../../base

# Use Docker Hub image
images:
  - name: todo-app
    newName: larsappel/todo-app
    newTag: latest

# Patch services to use NodePort for local access
patches:
  - path: webapp-service-patch.yaml
  - path: mongo-express-service-patch.yaml
  # Patch MongoDB to use default StorageClass (hostpath)
  - target:
      group: apps
      version: v1
      kind: StatefulSet
      name: mongodb
    patch: |-
      - op: replace
        path: /spec/volumeClaimTemplates/0/spec/storageClassName
        value: hostpath      

3.2 WebApp Service Patch

Create kubernetes/overlays/docker-desktop/webapp-service-patch.yaml:

apiVersion: v1
kind: Service
metadata:
  name: todo-webapp-service
  namespace: todo-app
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8080
    nodePort: 30080  # Access via http://localhost:30080

3.3 Mongo Express Service Patch

Create kubernetes/overlays/docker-desktop/mongo-express-service-patch.yaml:

apiVersion: v1
kind: Service
metadata:
  name: mongo-express-service
  namespace: todo-app
spec:
  type: NodePort
  ports:
  - port: 80
    targetPort: 8081
    nodePort: 30081  # Access via http://localhost:30081

Key differences:

  • βœ… Uses NodePort instead of LoadBalancer (no cloud provider)
  • βœ… Fixed node ports (30080, 30081) for easy access
  • βœ… Uses default hostpath StorageClass (built into Docker Desktop)
  • βœ… Docker Hub image (public)

Step 4: Create Overlay for EKS with Docker Hub

4.1 EKS Docker Hub Kustomization

Create kubernetes/overlays/eks-dockerhub/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: todo-app

resources:
  - ../../base
  - storageclass.yaml

# Use Docker Hub image
images:
  - name: todo-app
    newName: larsappel/todo-app
    newTag: latest

# Patch MongoDB to use EKS StorageClass and add AWS LoadBalancer annotations
patches:
  - target:
      group: apps
      version: v1
      kind: StatefulSet
      name: mongodb
    patch: |-
      - op: replace
        path: /spec/volumeClaimTemplates/0/spec/storageClassName
        value: ebs-sc      
  - patch: |-
      apiVersion: v1
      kind: Service
      metadata:
        name: todo-webapp-service
        namespace: todo-app
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      spec:
        type: LoadBalancer      
  - patch: |-
      apiVersion: v1
      kind: Service
      metadata:
        name: mongo-express-service
        namespace: todo-app
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      spec:
        type: LoadBalancer      

4.2 EKS StorageClass

Create kubernetes/overlays/eks-dockerhub/storageclass.yaml:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.eks.amazonaws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  encrypted: "true"

Key differences:

  • βœ… Uses LoadBalancer service type (creates AWS ELB)
  • βœ… Requires ebs-sc StorageClass for persistent volumes
  • βœ… AWS-specific annotations for internet-facing load balancer
  • βœ… Docker Hub image (public, no auth needed)

Step 5: Create Overlay for EKS with ECR

5.1 EKS ECR Kustomization

Create kubernetes/overlays/eks-ecr/kustomization.yaml:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

namespace: todo-app

resources:
  - ../../base
  - storageclass.yaml

# Use ECR private image
images:
  - name: todo-app
    newName: 880731366811.dkr.ecr.eu-west-1.amazonaws.com/todo-app
    newTag: latest

# Patch MongoDB to use EKS StorageClass and add AWS LoadBalancer annotations
patches:
  - target:
      group: apps
      version: v1
      kind: StatefulSet
      name: mongodb
    patch: |-
      - op: replace
        path: /spec/volumeClaimTemplates/0/spec/storageClassName
        value: ebs-sc      
  - patch: |-
      apiVersion: v1
      kind: Service
      metadata:
        name: todo-webapp-service
        namespace: todo-app
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      spec:
        type: LoadBalancer      
  - patch: |-
      apiVersion: v1
      kind: Service
      metadata:
        name: mongo-express-service
        namespace: todo-app
        annotations:
          service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
      spec:
        type: LoadBalancer      

5.2 EKS StorageClass (Same as Docker Hub)

Create kubernetes/overlays/eks-ecr/storageclass.yaml:

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.eks.amazonaws.com
volumeBindingMode: WaitForFirstConsumer
parameters:
  type: gp3
  encrypted: "true"

Key differences:

  • βœ… Uses ECR private registry instead of Docker Hub
  • βœ… No image pull secrets needed (EKS node IAM role handles auth)
  • βœ… Same LoadBalancer and StorageClass as eks-dockerhub
  • βœ… Better for production (private registry, vulnerability scanning)

Step 6: Deploy to Docker Desktop

6.1 Verify Kustomize Build

Preview what will be deployed:

kubectl kustomize kubernetes/overlays/docker-desktop

This shows the final YAML after Kustomize applies all patches and overlays.

6.2 Deploy

kubectl apply -k kubernetes/overlays/docker-desktop

Expected output:

namespace/todo-app created
service/mongodb-service created
statefulset.apps/mongodb created
job.batch/mongodb-init created
configmap/webapp-config created
service/mongo-express-service created
deployment.apps/mongo-express created
service/todo-webapp-service created
deployment.apps/todo-webapp created

6.3 Verify Deployment

# Check all resources
kubectl get all -n todo-app

# Check PVC (should use hostpath)
kubectl get pvc -n todo-app

# Wait for pods to be ready
kubectl wait --for=condition=ready pod -l app=mongodb -n todo-app --timeout=120s
kubectl wait --for=condition=ready pod -l app=todo-webapp -n todo-app --timeout=120s

6.4 Access the Application

Todo App:

http://localhost:30080

Mongo Express:

http://localhost:30081

Login: admin / pass

6.5 Test CRUD Operations

# Get all todos
curl http://localhost:30080/api/todos

# Create a new todo
curl -X POST http://localhost:30080/api/todos \
  -H "Content-Type: application/json" \
  -d '{"id":3,"name":"Test Kustomize","isComplete":false}'

# Verify
curl http://localhost:30080/api/todos

Step 7: Deploy to EKS with Docker Hub

7.1 Switch kubectl Context

# List contexts
kubectl config get-contexts

# Switch to EKS cluster
kubectl config use-context <your-eks-context>

# Verify
kubectl cluster-info

7.2 Preview and Deploy

# Preview
kubectl kustomize kubernetes/overlays/eks-dockerhub

# Deploy
kubectl apply -k kubernetes/overlays/eks-dockerhub

7.3 Monitor Deployment

# Watch pod creation
kubectl get pods -n todo-app -w

# Check StorageClass was created
kubectl get storageclass ebs-sc

# Check PVC (should use ebs-sc)
kubectl get pvc -n todo-app -o wide

# Check services (LoadBalancer provisioning takes ~2 minutes)
kubectl get svc -n todo-app -w

7.4 Get Load Balancer URLs

# Get webapp URL
kubectl get svc todo-webapp-service -n todo-app -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

# Get Mongo Express URL
kubectl get svc mongo-express-service -n todo-app -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'

Access:

# Todo App
WEBAPP_URL=$(kubectl get svc todo-webapp-service -n todo-app -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "Todo App: http://${WEBAPP_URL}"

# Mongo Express
MONGO_EXPRESS_URL=$(kubectl get svc mongo-express-service -n todo-app -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo "Mongo Express: http://${MONGO_EXPRESS_URL}"

7.5 Verify

# Test API
curl http://${WEBAPP_URL}/api/todos

# Open in browser
open http://${WEBAPP_URL}
open http://${MONGO_EXPRESS_URL}

Step 8: Deploy to EKS with ECR

8.1 Ensure ECR Image Exists

Verify the image was pushed in Exercise 2:

aws ecr describe-images \
  --repository-name todo-app \
  --region eu-west-1 \
  --query 'imageDetails[?imageTags[?contains(@, `latest`)]]'

8.2 Update Kustomization with Your Account ID

Edit kubernetes/overlays/eks-ecr/kustomization.yaml and replace the account ID:

images:
  - name: todo-app
    newName: <YOUR-ACCOUNT-ID>.dkr.ecr.<YOUR-REGION>.amazonaws.com/todo-app
    newTag: latest

8.3 Deploy

# Preview
kubectl kustomize kubernetes/overlays/eks-ecr

# Deploy
kubectl apply -k kubernetes/overlays/eks-ecr

8.4 Verify Image Pull

Check that pods successfully pulled from ECR:

# Describe webapp pod to see image source
kubectl describe pod -l app=todo-webapp -n todo-app | grep -A 5 "Image:"

# Should show ECR URL, not Docker Hub

8.5 Test Application

Same as Step 7.5 - get LoadBalancer URLs and test.


Step 9: Understanding the Differences

Compare Deployments

Storage

Docker Desktop:

kubectl get pvc -n todo-app -o custom-columns=NAME:.metadata.name,STORAGECLASS:.spec.storageClassName

Output: hostpath

EKS:

kubectl get pvc -n todo-app -o custom-columns=NAME:.metadata.name,STORAGECLASS:.spec.storageClassName

Output: ebs-sc

Explanation:

  • Docker Desktop uses local storage (hostpath)
  • EKS uses AWS EBS volumes (gp3 SSD)
  • EBS volumes are network-attached, can move between nodes
  • Hostpath is tied to specific node

Services

Docker Desktop:

kubectl get svc -n todo-app

Output: NodePort with ports 30080, 30081

EKS:

kubectl get svc -n todo-app

Output: LoadBalancer with external AWS ELB hostnames

Explanation:

  • NodePort: Exposes service on each node’s IP at static port
  • LoadBalancer: Creates cloud provider load balancer (AWS ELB)
  • NodePort requires port forwarding for external access
  • LoadBalancer provides public DNS name automatically

Images

Check deployed image:

kubectl get deployment todo-webapp -n todo-app -o jsonpath='{.spec.template.spec.containers[0].image}'

Docker Desktop / EKS-DockerHub:

larsappel/todo-app:latest

EKS-ECR:

880731366811.dkr.ecr.eu-west-1.amazonaws.com/todo-app:latest

Explanation:

  • Docker Hub: Public registry, no authentication needed
  • ECR: Private registry, uses EKS node IAM role for authentication
  • ECR includes vulnerability scanning
  • ECR better for production (private, compliance, scanning)

Step 10: Cleanup

Delete from Docker Desktop

kubectl delete -k kubernetes/overlays/docker-desktop

# Verify namespace is gone
kubectl get ns todo-app

Delete from EKS

# Delete application
kubectl delete -k kubernetes/overlays/eks-dockerhub
# OR
kubectl delete -k kubernetes/overlays/eks-ecr

# Delete StorageClass (optional - may be used by other apps)
kubectl delete storageclass ebs-sc

# Verify PVCs are deleted (important to avoid orphaned EBS volumes)
kubectl get pvc --all-namespaces | grep todo-app

Important: Deleting the namespace automatically deletes PVCs, which triggers EBS volume deletion. Verify in AWS Console if needed.


Troubleshooting

Pod ImagePullBackOff on EKS with ECR

Symptom:

kubectl get pods -n todo-app
# Shows ImagePullBackOff

Check:

kubectl describe pod <pod-name> -n todo-app | grep -A 10 Events

Common causes:

  1. Wrong ECR URL (check account ID and region)
  2. Image doesn’t exist in ECR
  3. EKS node role lacks ECR permissions

Fix:

# Verify image exists
aws ecr describe-images --repository-name todo-app --region eu-west-1

# Check EKS node IAM role has AmazonEC2ContainerRegistryReadOnly policy

PVC Stuck in Pending on EKS

Symptom:

kubectl get pvc -n todo-app
# Shows Pending

Check:

kubectl describe pvc -n todo-app

Common causes:

  1. StorageClass doesn’t exist
  2. EBS CSI driver not installed (should be automatic with EKS Auto)
  3. No available AZ

Fix:

# Verify StorageClass exists
kubectl get storageclass ebs-sc

# For EKS Auto Mode, StorageClass should work automatically
# For standard EKS, ensure EBS CSI driver is installed

LoadBalancer Stuck in Pending

Symptom:

kubectl get svc -n todo-app
# Shows <pending> for EXTERNAL-IP

Check:

kubectl describe svc todo-webapp-service -n todo-app

Common causes:

  1. AWS Load Balancer Controller not installed (EKS Auto handles this)
  2. Service account lacking permissions
  3. Subnet configuration issues

Wait: LoadBalancer provisioning can take 2-5 minutes.

NodePort Not Accessible on Docker Desktop

Symptom: http://localhost:30080 times out

Check:

# Verify service is NodePort
kubectl get svc -n todo-app

# Check pods are running
kubectl get pods -n todo-app

Fix:

  • Ensure Docker Desktop Kubernetes is running
  • Verify NodePort is in valid range (30000-32767)
  • Try kubectl port-forward as alternative:
    kubectl port-forward -n todo-app svc/todo-webapp-service 8080:80
    # Access at http://localhost:8080

Key Takeaways

Kustomize Benefits

βœ… DRY Principle: Base manifests shared across environments βœ… No Templating: Pure YAML, easier to read than Helm βœ… Built-in: No additional tools needed (kubectl -k) βœ… Patch Flexibility: Strategic merge, JSON 6902, replacements βœ… Environment Variants: Easy to manage dev/staging/prod differences

Environment Differences Summary

AspectDocker DesktopEKS (Docker Hub)EKS (ECR)
StoragehostpathEBS (gp3)EBS (gp3)
ServiceNodePortLoadBalancerLoadBalancer
Image RegistryDocker HubDocker HubAWS ECR
AuthenticationNoneNoneIAM Role
CostFreeELB + EBS costsELB + EBS costs
Public Accesslocalhost onlyInternet-facingInternet-facing

When to Use Each

Docker Desktop (docker-desktop):

  • Local development and testing
  • No cloud costs
  • Fast iteration
  • No internet access needed

EKS + Docker Hub (eks-dockerhub):

  • Public images
  • Multi-cloud compatibility
  • Easy sharing (public registry)
  • No ECR setup needed

EKS + ECR (eks-ecr):

  • Production workloads
  • Private images
  • Vulnerability scanning
  • Compliance requirements
  • Better security (private registry)

Next Steps

Now that you’ve mastered Kustomize deployments, you can:

  1. Add more overlays - Create staging, testing environments
  2. Use Kustomize components - Reusable pieces across overlays
  3. Integrate with CI/CD - Automate deployments with GitHub Actions
  4. Learn Helm - More advanced templating and packaging
  5. Implement GitOps - ArgoCD for automated sync from Git

Congratulations! πŸŽ‰

You’ve successfully deployed the same application to three different environments using Kustomize, understanding how to handle:

  • Storage differences (local vs cloud)
  • Networking differences (NodePort vs LoadBalancer)
  • Registry differences (public vs private)
  • Environment-specific configurations

You’re now ready for production Kubernetes deployments!


Reference Commands

Preview before applying

kubectl kustomize kubernetes/overlays/<overlay-name>

Deploy

kubectl apply -k kubernetes/overlays/<overlay-name>

Delete

kubectl delete -k kubernetes/overlays/<overlay-name>

Get resources in namespace

kubectl get all -n todo-app

View Kustomize build with diffs

kubectl diff -k kubernetes/overlays/<overlay-name>