intermediateCKAD6-8 weeks prep6 min read

CKAD: Certified Kubernetes Application Developer — Study Guide

Study guide for the CKAD Certified Kubernetes Application Developer exam. Focuses on deploying, configuring, and troubleshooting applications in Kubernetes — for developers, not admins.

kubernetesckadk8sdeveloperintermediatecncflinux-foundationcontainers

Domains

8

Key concepts

13

Study time

6-8 weeks

Exam Overview

DetailInfo
Exam codeCKAD
Duration2 hours
FormatHands-on performance-based (real clusters)
Passing score66%
Cost$395 USD (includes 1 free retake)
Validity3 years

CKAD vs CKA

CKADCKA
FocusApplication deployment and configurationCluster administration
AudienceDevelopersPlatform/ops engineers
OverlapPods, Services, NetworkingCluster setup, etcd, RBAC
Harder topicMulti-container patterns, Helmkubeadm, troubleshooting

Domain Weightings

DomainWeight
Application Design and Build20%
Application Deployment20%
Application Observability and Maintenance15%
Application Environment, Configuration, and Security25%
Services and Networking20%

Domain 1: Application Design and Build (20%)

Multi-container pod patterns

# Sidecar pattern — logging agent alongside main app
spec:
  containers:
  - name: app
    image: myapp:1.0
    volumeMounts:
    - name: log-vol
      mountPath: /var/log/app
  - name: log-shipper
    image: fluentd:latest
    volumeMounts:
    - name: log-vol
      mountPath: /var/log/app
  volumes:
  - name: log-vol
    emptyDir: {}
# Init container — run setup before main app starts
spec:
  initContainers:
  - name: wait-for-db
    image: busybox
    command: ['sh', '-c', 'until nc -z db 5432; do sleep 2; done']
  containers:
  - name: app
    image: myapp:1.0

Jobs and CronJobs

# One-off Job
kubectl create job pi --image=perl -- perl -Mbignum=bpi -wle 'print bpi(2000)'

# CronJob (run every minute)
kubectl create cronjob hello --image=busybox --schedule="*/1 * * * *" \
  -- echo "Hello from CronJob"

Domain 2: Application Deployment (20%)

Deployment strategies

# Rolling update (default)
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxUnavailable: 1
    maxSurge: 1

# Recreate (downtime)
strategy:
  type: Recreate
# Blue-green deployment (manual)
kubectl set image deployment/app-blue app=myapp:1.0
kubectl set image deployment/app-green app=myapp:2.0
# Switch service selector from blue to green:
kubectl patch service app-svc -p '{"spec":{"selector":{"version":"green"}}}'

Helm fundamentals

# Add repo and install
helm repo add bitnami https://charts.bitnami.com/bitnami
helm install my-release bitnami/nginx

# Override values
helm install my-release bitnami/nginx --set service.type=NodePort

# Upgrade
helm upgrade my-release bitnami/nginx --set image.tag=1.22

# Rollback
helm rollback my-release 1

# List releases
helm list -A

# Template rendering (debug)
helm template my-release bitnami/nginx --set service.type=NodePort

Domain 3: Observability and Maintenance (15%)

Probes

livenessProbe:
  httpGet:
    path: /healthz
    port: 8080
  initialDelaySeconds: 15
  periodSeconds: 10
  failureThreshold: 3

readinessProbe:
  httpGet:
    path: /ready
    port: 8080
  initialDelaySeconds: 5
  periodSeconds: 5

startupProbe:
  httpGet:
    path: /started
    port: 8080
  failureThreshold: 30
  periodSeconds: 10
  # Allows 5 minutes (30*10s) for slow-starting containers
ProbeAction on failureUse for
livenessRestart the containerDetect deadlocks
readinessRemove from service endpointsNot ready to handle traffic
startupRestart if not started in timeSlow-start containers

Debugging commands

kubectl logs <pod> [-c <container>] [--previous]
kubectl describe pod <pod>
kubectl exec -it <pod> -- /bin/sh
kubectl top pods -n <ns>
kubectl get events -n <ns> --sort-by='.lastTimestamp'

Domain 4: Configuration and Security (25%)

ConfigMaps

# Create
kubectl create configmap app-config \
  --from-literal=DB_HOST=mydb \
  --from-literal=DB_PORT=5432

# Use as environment variables
kubectl set env deployment/app --from=configmap/app-config

# Use as a volume (each key becomes a file)
volumes:
  - name: config
    configMap:
      name: app-config
containers:
  - volumeMounts:
    - name: config
      mountPath: /etc/config

Secrets

kubectl create secret generic db-secret \
  --from-literal=username=admin \
  --from-literal=password='S3cur3!'

# Use as env vars
kubectl set env deployment/app --from=secret/db-secret

Resource quotas and limits

# LimitRange — default limits for a namespace
apiVersion: v1
kind: LimitRange
metadata:
  name: default-limits
  namespace: dev
spec:
  limits:
  - default:
      cpu: 500m
      memory: 256Mi
    defaultRequest:
      cpu: 100m
      memory: 128Mi
    type: Container

# ResourceQuota — total namespace limit
apiVersion: v1
kind: ResourceQuota
metadata:
  name: ns-quota
  namespace: dev
spec:
  hard:
    requests.cpu: "4"
    requests.memory: 4Gi
    limits.cpu: "8"
    limits.memory: 8Gi
    pods: "20"

Security contexts

securityContext:
  runAsUser: 1000          # don't run as root
  runAsGroup: 3000
  fsGroup: 2000
  readOnlyRootFilesystem: true  # immutable container FS
  allowPrivilegeEscalation: false
  capabilities:
    drop: [ALL]
    add: [NET_BIND_SERVICE]

ServiceAccount

# Create dedicated service account for pod (not default)
kubectl create serviceaccount app-sa

# Assign to pod
kubectl run myapp --image=nginx --serviceaccount=app-sa $do > pod.yaml

Domain 5: Services and Networking (20%)

Service selector matching

# Pods must have labels matching the service selector
kubectl label pod mypod app=frontend

# Service selects pods with app=frontend
kubectl expose pod mypod --port=80 --name=frontend-svc

Ingress with path routing

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: app-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
  ingressClassName: nginx
  rules:
  - http:
      paths:
      - path: /api(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: api-svc
            port:
              number: 8080
      - path: /web(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: web-svc
            port:
              number: 80

NetworkPolicy (egress + ingress)

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-isolation
spec:
  podSelector:
    matchLabels:
      app: database
  policyTypes: [Ingress, Egress]
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: backend
    ports:
    - port: 5432
  egress:
  - ports:
    - port: 53
      protocol: UDP
    - port: 53
      protocol: TCP

Study Plan (6–8 Weeks)

WeeksFocus
1Pods, Deployments, ReplicaSets, Services — kubectl speed drills
2ConfigMaps, Secrets, resource limits, namespaces
3Multi-container pods, init containers, Jobs, CronJobs
4Probes, rolling updates, Helm basics
5Security contexts, ServiceAccounts, NetworkPolicy
6Ingress, PVC, persistent storage, Kustomize
7–8Timed mock exams (killer.sh) + speed practice

Key Resources

ResourceNotes
killer.shIncluded with purchase; do it multiple times
KodeKloud CKADBest hands-on practice platform
Mumshad Mannambeth (Udemy)Most popular CKAD course
CKAD exercises on GitHubdgkanatsios/CKAD-exercises — free practice questions