CKA Prep: Part 3 – Workloads & Scheduling
On this page
Kubernetes Workload Resources
Kubernetes provides several workload resources to manage containerized applications. Understanding these resources is crucial for the CKA exam.
Deployments
A Deployment provides declarative updates for Pods and ReplicaSets.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 3
selector:
matchLabels:
app: nginx
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 1
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"Key Features:
- Scaling: Easily scale the number of replicas up or down
- Rolling Updates: Gradually update pods without downtime
- Rollbacks: Revert to a previous version if problems occur
- Self-healing: Automatically replaces failed pods
Common Deployment Commands:
# Create a deployment
kubectl create deployment nginx --image=nginx:1.21
# Scale a deployment
kubectl scale deployment nginx --replicas=5
# Update a deployment's image
kubectl set image deployment/nginx nginx=nginx:1.22
# Check rollout status
kubectl rollout status deployment/nginx
# View rollout history
kubectl rollout history deployment/nginx
# Rollback to a previous revision
kubectl rollout undo deployment/nginx
kubectl rollout undo deployment/nginx --to-revision=2
# Pause/Resume rollout
kubectl rollout pause deployment/nginx
kubectl rollout resume deployment/nginxDaemonSets
A DaemonSet ensures that all (or some) nodes run a copy of a Pod.
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
namespace: monitoring
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
tolerations:
- key: node-role.kubernetes.io/master
effect: NoSchedule
containers:
- name: node-exporter
image: prom/node-exporter:v1.3.1
ports:
- containerPort: 9100
name: metricsKey Features:
- Runs a pod on every node (or selected nodes)
- Automatically adds pods to new nodes as they join the cluster
- Removes pods when nodes are removed
- Useful for node-level operations (monitoring, logging, storage, etc.)
Common DaemonSet Commands:
# Create a DaemonSet (typically from a YAML file)
kubectl apply -f daemonset.yaml
# View DaemonSets
kubectl get daemonsets -n monitoring
# Describe a DaemonSet
kubectl describe daemonset node-exporter -n monitoring
# Delete a DaemonSet
kubectl delete daemonset node-exporter -n monitoringStatefulSets
A StatefulSet is used to manage stateful applications, providing guarantees about the ordering and uniqueness of Pods.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "nginx"
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.21
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: "standard"
resources:
requests:
storage: 1GiKey Features:
- Stable, unique network identifiers for each pod
- Stable, persistent storage for each pod
- Ordered, graceful deployment and scaling
- Ordered, automated rolling updates
- Ideal for stateful applications (databases, etc.)
Common StatefulSet Commands:
# Create a StatefulSet (typically from a YAML file)
kubectl apply -f statefulset.yaml
# View StatefulSets
kubectl get statefulsets
# Scale a StatefulSet
kubectl scale statefulset web --replicas=5
# Delete a StatefulSet
kubectl delete statefulset webJobs and CronJobs
Jobs create pods that run until successful completion. CronJobs create Jobs on a schedule.
Job Example:
apiVersion: batch/v1
kind: Job
metadata:
name: pi-calculation
spec:
completions: 5 # Number of successful pod completions required
parallelism: 2 # Number of pods to run in parallel
backoffLimit: 6 # Number of retries before marking job failed
template:
spec:
containers:
- name: pi
image: perl:5.34
command: ["perl", "-Mbignum=bpi", "-wle", "print bpi(2000)"]
restartPolicy: Never # Important for JobsCronJob Example:
apiVersion: batch/v1
kind: CronJob
metadata:
name: backup-database
spec:
schedule: "0 2 * * *" # Cron schedule format (2 AM daily)
concurrencyPolicy: Forbid
jobTemplate:
spec:
template:
spec:
containers:
- name: backup
image: database-backup:v1.2
command: ["/bin/sh", "-c", "backup.sh"]
restartPolicy: OnFailureKey Features:
- Jobs: Run-to-completion workloads
- CronJobs: Scheduled jobs based on cron format
- Useful for batch processing, backups, and scheduled tasks
Common Job/CronJob Commands:
# Create a job
kubectl create job one-off --image=busybox -- date
# View jobs
kubectl get jobs
# View pods created by jobs
kubectl get pods --selector=job-name=pi-calculation
# Create a cronjob
kubectl create cronjob hello --image=busybox --schedule="*/1 * * * *" -- echo "Hello World"
# View cronjobs
kubectl get cronjobs
# View the jobs created by a cronjob
kubectl get jobs --selector=cronjob-name=helloApplication Configuration
ConfigMaps
ConfigMaps allow you to decouple configuration from container images.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
app.properties: |
environment=production
log_level=INFO
ui.properties: |
color.background=blue
color.text=white
DB_HOST: "mysql.example.com"
DB_PORT: "3306"Using ConfigMaps in a Pod:
apiVersion: v1
kind: Pod
metadata:
name: config-pod
spec:
containers:
- name: app
image: my-app:v1
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DB_PORT
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: app-configCommon ConfigMap Commands:
# Create a ConfigMap from literal values
kubectl create configmap app-settings --from-literal=APP_ENV=production --from-literal=APP_DEBUG=false
# Create a ConfigMap from a file
kubectl create configmap app-config --from-file=app.properties
# View ConfigMaps
kubectl get configmaps
kubectl describe configmap app-configSecrets
Secrets let you store and manage sensitive information separately from your application code.
apiVersion: v1
kind: Secret
metadata:
name: db-credentials
type: Opaque
data:
username: YWRtaW4= # base64 encoded "admin"
password: cGFzc3dvcmQxMjM= # base64 encoded "password123"Using Secrets in a Pod:
apiVersion: v1
kind: Pod
metadata:
name: secret-pod
spec:
containers:
- name: app
image: my-app:v1
env:
- name: DB_USERNAME
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
volumeMounts:
- name: secret-volume
mountPath: /etc/secrets
readOnly: true
volumes:
- name: secret-volume
secret:
secretName: db-credentialsCommon Secret Commands:
# Create a Secret from literal values
kubectl create secret generic db-credentials --from-literal=username=admin --from-literal=password=password123
# View Secrets
kubectl get secrets
kubectl describe secret db-credentials
# Decode a Secret value
kubectl get secret db-credentials -o jsonpath='{.data.username}' | base64 --decodeResource Management and Limits
Properly configuring resource requests and limits is crucial for efficient cluster utilization and application performance.
Resource Requests and Limits
apiVersion: v1
kind: Pod
metadata:
name: resource-demo
spec:
containers:
- name: resource-container
image: nginx
resources:
requests:
memory: "64Mi" # Memory request (what the container is guaranteed)
cpu: "250m" # CPU request (0.25 CPU cores)
limits:
memory: "128Mi" # Memory limit (max the container can use)
cpu: "500m" # CPU limit (0.5 CPU cores)Key Concepts:
- Resource Requests: The amount of resources guaranteed to the container
- Resource Limits: The maximum amount of resources the container can use
- CPU Units: Measured in cores or millicores (m), where 1000m = 1 core
- Memory Units: Measured in bytes (K, M, G, T, P, E suffixes for SI units)
Resource Quotas
ResourceQuota objects define constraints on resource consumption per namespace.
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: development
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 5Gi
limits.cpu: "8"
limits.memory: 10Gi
count/deployments.apps: "5"
count/replicasets.apps: "10"LimitRanges
LimitRange objects define default, min, and max resource constraints for individual containers.
apiVersion: v1
kind: LimitRange
metadata:
name: container-limits
namespace: development
spec:
limits:
- type: Container
default:
cpu: 500m
memory: 256Mi
defaultRequest:
cpu: 100m
memory: 50Mi
min:
cpu: 50m
memory: 10Mi
max:
cpu: "2"
memory: 1GiAdvanced Scheduling Concepts
The CKA exam tests your knowledge of how to influence pod scheduling decisions.
Node Selectors
The simplest way to constrain pods to nodes with specific labels.
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
containers:
- name: gpu-container
image: tensorflow/tensorflow:latest-gpu
nodeSelector:
hardware: gpuTo label a node:
kubectl label nodes node1 hardware=gpuNode Affinity and Anti-Affinity
Node affinity provides more expressive pod placement constraints than nodeSelector.
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: hardware
operator: In
values:
- gpu
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: zone
operator: In
values:
- us-east-1a
containers:
- name: with-node-affinity
image: tensorflow/tensorflow:latest-gpuTypes of Node Affinity:
- requiredDuringSchedulingIgnoredDuringExecution: Hard requirement that must be met for a pod to be scheduled
- preferredDuringSchedulingIgnoredDuringExecution: Soft requirement that the scheduler will try to enforce but won’t guarantee
Pod Affinity and Anti-Affinity
Pod affinity/anti-affinity allows you to constrain which nodes pods can be scheduled on based on labels of pods already running on the node.
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cache
topologyKey: kubernetes.io/hostname
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: nginxKey Concepts:
- Pod Affinity: Schedule pods on the same node or zone as other pods
- Pod Anti-Affinity: Avoid scheduling pods on the same node or zone as other pods
- topologyKey: The key for the node label that the system uses to denote the domain
Taints and Tolerations
Taints are properties of nodes that repel pods without matching tolerations.
To taint a node:
kubectl taint nodes node1 key=value:NoSchedulePod with tolerations:
apiVersion: v1
kind: Pod
metadata:
name: with-toleration
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"Taint Effects:
- NoSchedule: Pods won’t be scheduled on the node unless they tolerate the taint
- PreferNoSchedule: Kubernetes will try to avoid placing pods on the node, but it’s not guaranteed
- NoExecute: New pods won’t be scheduled, and existing pods will be evicted if they don’t tolerate the taint
Sample Exam Questions
Question 1: Pod Scheduling with Node Affinity
Task: Create a pod named app-pod using the nginx:1.21 image that will only be scheduled on nodes with the label disk=ssd and preferably in the zone us-east-1a.
Solution:
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk
operator: In
values:
- ssd
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: zone
operator: In
values:
- us-east-1a
containers:
- name: nginx
image: nginx:1.21
EOFQuestion 2: Create Deployment with ConfigMap
Task: Create a ConfigMap named app-config with the values DB_HOST=mysql and DB_PORT=3306. Then create a Deployment named web-app with 3 replicas using the nginx:1.21 image that uses these values as environment variables.
Solution:
# Create the ConfigMap
kubectl create configmap app-config --from-literal=DB_HOST=mysql --from-literal=DB_PORT=3306
# Create the Deployment
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-app
spec:
replicas: 3
selector:
matchLabels:
app: web-app
template:
metadata:
labels:
app: web-app
spec:
containers:
- name: nginx
image: nginx:1.21
env:
- name: DATABASE_HOST
valueFrom:
configMapKeyRef:
name: app-config
key: DB_HOST
- name: DATABASE_PORT
valueFrom:
configMapKeyRef:
name: app-config
key: DB_PORT
EOFQuestion 3: DaemonSet for Monitoring
Task: Create a DaemonSet named node-monitoring that runs on all nodes including master nodes. It should use the image prom/node-exporter:v1.3.1 and expose port 9100.
Solution:
cat << EOF | kubectl apply -f -
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-monitoring
spec:
selector:
matchLabels:
app: node-monitoring
template:
metadata:
labels:
app: node-monitoring
spec:
tolerations:
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
- key: node-role.kubernetes.io/master
operator: Exists
effect: NoSchedule
containers:
- name: node-exporter
image: prom/node-exporter:v1.3.1
ports:
- containerPort: 9100
name: metrics
EOFQuestion 4: Resource Quota Management
Task: Create a namespace named development and set a resource quota limiting the namespace to maximum 10 pods, 4 CPU cores, and 8GiB memory in total.
Solution:
# Create the namespace
kubectl create namespace development
# Create the ResourceQuota
cat << EOF | kubectl apply -f -
apiVersion: v1
kind: ResourceQuota
metadata:
name: compute-quota
namespace: development
spec:
hard:
pods: "10"
requests.cpu: "4"
requests.memory: 8Gi
limits.cpu: "4"
limits.memory: 8Gi
EOFKey Tips for Workloads and Scheduling
Master imperative pod creation:
- Use
kubectl runwith various flags for quick pod creation - Learn the flags for attaching resources, volumes, etc.
- Use
Understand deployment strategies:
- Know the difference between RollingUpdate and Recreate
- Be familiar with maxSurge and maxUnavailable parameters
Know when to use each workload type:
- Deployments: Stateless applications
- StatefulSets: Stateful applications
- DaemonSets: Node-level operations
- Jobs/CronJobs: Batch processing or scheduled tasks
Be efficient with ConfigMaps and Secrets:
- Know the different ways to use them (environment variables, volumes)
- Remember the different creation methods (from file, from literal)
Understand scheduling concepts deeply:
- Know the difference between node selectors, affinity, and taints/tolerations
- Practice combined scheduling scenarios
Practice Exercises
To reinforce your understanding, try these exercises in your practice environment:
- Create a Deployment with specific resource requests and limits
- Create a ConfigMap from multiple files and consume it in a pod
- Set up node affinity rules to schedule pods on specific nodes
- Create a DaemonSet that runs on specific nodes using node affinity
- Implement a pod anti-affinity strategy to ensure high availability
- Create a Job that runs multiple completions in parallel
- Set up a CronJob that runs a backup task every day at midnight
What’s Next
In the next part, we’ll explore Services and Networking in Kubernetes, covering:
- Different service types
- Network policies
- Ingress controllers and resources
- DNS configuration
- CNI plugins
👉 Continue to Part 4: Services & Networking