08. Kubernetes Advanced
08. Kubernetes Advanced¶
Learning Objectives¶
- Routing external traffic through Ingress
- Managing stateful applications with StatefulSet
- Using PersistentVolume/PersistentVolumeClaim
- Advanced usage of ConfigMap and Secret
- Using DaemonSet and Job
- Advanced scheduling techniques
Table of Contents¶
- Ingress
- StatefulSet
- Persistent Storage
- ConfigMap Advanced
- DaemonSet and Job
- Advanced Scheduling
- Practice Exercises
1. Ingress¶
1.1 Ingress Concepts¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Ingress Architecture β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Internet β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββββ β
β β Ingress Controller β β
β β (nginx, traefik, haproxy, etc.) β β
β βββββββββββββββββββββ¬ββββββββββββββββββββββββ β
β β β
β βββββββββββββββΌββββββββββββββ β
β β β β β
β βΌ βΌ βΌ β
β βββββββββββ βββββββββββ βββββββββββ β
β βIngress β βIngress β βIngress β β
β βResource β βResource β βResource β β
β ββββββ¬βββββ ββββββ¬βββββ ββββββ¬βββββ β
β β β β β
β βΌ βΌ βΌ β
β βββββββββββ βββββββββββ βββββββββββ β
β βService Aβ βService Bβ βService Cβ β
β βββββββββββ βββββββββββ βββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
1.2 Installing Ingress Controller¶
# Install NGINX Ingress Controller
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.8.2/deploy/static/provider/cloud/deploy.yaml
# Verify installation
kubectl get pods -n ingress-nginx
kubectl get svc -n ingress-nginx
# Check IngressClass
kubectl get ingressclass
1.3 Basic Ingress¶
# simple-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: simple-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: nginx
rules:
- host: myapp.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
---
# Host-based routing
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: host-based-ingress
spec:
ingressClassName: nginx
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
- host: admin.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: admin-service
port:
number: 3000
1.4 Path-Based Routing¶
# path-based-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-based-ingress
annotations:
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
rules:
- host: app.example.com
http:
paths:
# /api/* β api-service
- path: /api(/|$)(.*)
pathType: ImplementationSpecific
backend:
service:
name: api-service
port:
number: 8080
# /static/* β static-service
- path: /static
pathType: Prefix
backend:
service:
name: static-service
port:
number: 80
# Default β frontend
- path: /
pathType: Prefix
backend:
service:
name: frontend-service
port:
number: 80
1.5 TLS Configuration¶
# tls-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- secure.example.com
secretName: tls-secret # TLS Secret
rules:
- host: secure.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: secure-service
port:
number: 443
---
# Create TLS Secret
apiVersion: v1
kind: Secret
metadata:
name: tls-secret
type: kubernetes.io/tls
data:
tls.crt: <base64-encoded-cert>
tls.key: <base64-encoded-key>
1.6 Advanced Ingress Configuration¶
# advanced-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: advanced-ingress
annotations:
# Basic settings
nginx.ingress.kubernetes.io/proxy-body-size: "50m"
nginx.ingress.kubernetes.io/proxy-read-timeout: "60"
nginx.ingress.kubernetes.io/proxy-send-timeout: "60"
# Rate Limiting
nginx.ingress.kubernetes.io/limit-rps: "100"
nginx.ingress.kubernetes.io/limit-connections: "50"
# CORS
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-origin: "https://frontend.example.com"
nginx.ingress.kubernetes.io/cors-allow-methods: "GET, POST, PUT, DELETE, OPTIONS"
# Authentication
nginx.ingress.kubernetes.io/auth-type: basic
nginx.ingress.kubernetes.io/auth-secret: basic-auth
nginx.ingress.kubernetes.io/auth-realm: "Authentication Required"
# Custom headers
nginx.ingress.kubernetes.io/configuration-snippet: |
add_header X-Frame-Options "SAMEORIGIN";
add_header X-Content-Type-Options "nosniff";
spec:
ingressClassName: nginx
tls:
- hosts:
- api.example.com
secretName: api-tls
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 8080
2. StatefulSet¶
2.1 StatefulSet Concepts¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β StatefulSet vs Deployment β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β Deployment (Stateless) β
β βββββββββ βββββββββ βββββββββ β
β βpod-xyzβ βpod-abcβ βpod-123β Random names, replaceable β
β βββββββββ βββββββββ βββββββββ β
β β
β StatefulSet (Stateful) β
β βββββββββ βββββββββ βββββββββ β
β βweb-0 β βweb-1 β βweb-2 β Ordered, unique IDs β
β β β β β β β β β β β
β βpvc-0 β βpvc-1 β βpvc-2 β Dedicated storage each β
β βββββββββ βββββββββ βββββββββ β
β β
β Features: β
β β’ Ordered creation/deletion (0 β 1 β 2) β
β β’ Fixed network IDs (pod-name.service-name) β
β β’ Persistent storage attached β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2.2 StatefulSet Definition¶
# statefulset-example.yaml
apiVersion: v1
kind: Service
metadata:
name: web-headless
labels:
app: web
spec:
ports:
- port: 80
name: web
clusterIP: None # Headless Service
selector:
app: web
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
serviceName: "web-headless" # Connect to Headless Service
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
# Volume claim templates
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: standard
resources:
requests:
storage: 1Gi
# Update strategy
updateStrategy:
type: RollingUpdate
rollingUpdate:
partition: 0 # Only Pods >= this number are updated
# Pod management policy
podManagementPolicy: OrderedReady # Or Parallel
2.3 Database StatefulSet¶
# mysql-statefulset.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: mysql-config
data:
my.cnf: |
[mysqld]
bind-address = 0.0.0.0
default_authentication_plugin = mysql_native_password
---
apiVersion: v1
kind: Secret
metadata:
name: mysql-secret
type: Opaque
stringData:
root-password: "rootpass123"
user-password: "userpass123"
---
apiVersion: v1
kind: Service
metadata:
name: mysql-headless
spec:
clusterIP: None
selector:
app: mysql
ports:
- port: 3306
---
apiVersion: v1
kind: Service
metadata:
name: mysql
spec:
selector:
app: mysql
statefulset.kubernetes.io/pod-name: mysql-0 # Primary only
ports:
- port: 3306
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: mysql
spec:
serviceName: mysql-headless
replicas: 3
selector:
matchLabels:
app: mysql
template:
metadata:
labels:
app: mysql
spec:
initContainers:
- name: init-mysql
image: mysql:8.0
command:
- bash
- "-c"
- |
set -ex
# Generate server-id from Pod index
[[ `hostname` =~ -([0-9]+)$ ]] || exit 1
ordinal=${BASH_REMATCH[1]}
echo [mysqld] > /mnt/conf.d/server-id.cnf
echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf
volumeMounts:
- name: conf
mountPath: /mnt/conf.d
containers:
- name: mysql
image: mysql:8.0
env:
- name: MYSQL_ROOT_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: root-password
ports:
- containerPort: 3306
volumeMounts:
- name: data
mountPath: /var/lib/mysql
- name: conf
mountPath: /etc/mysql/conf.d
- name: config
mountPath: /etc/mysql/my.cnf
subPath: my.cnf
resources:
requests:
cpu: 500m
memory: 1Gi
livenessProbe:
exec:
command: ["mysqladmin", "ping"]
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
exec:
command: ["mysql", "-h", "127.0.0.1", "-e", "SELECT 1"]
initialDelaySeconds: 5
periodSeconds: 2
volumes:
- name: conf
emptyDir: {}
- name: config
configMap:
name: mysql-config
volumeClaimTemplates:
- metadata:
name: data
spec:
accessModes: ["ReadWriteOnce"]
storageClassName: fast
resources:
requests:
storage: 10Gi
2.4 StatefulSet Management¶
# View StatefulSets
kubectl get statefulset
kubectl describe statefulset web
# Check Pods (ordered names)
kubectl get pods -l app=web
# NAME READY STATUS
# web-0 1/1 Running
# web-1 1/1 Running
# web-2 1/1 Running
# Check DNS
# Each Pod: web-0.web-headless.default.svc.cluster.local
kubectl run -it --rm debug --image=busybox -- nslookup web-0.web-headless
# Scaling
kubectl scale statefulset web --replicas=5
# Rolling update
kubectl set image statefulset/web nginx=nginx:1.26
# Update specific Pods only (using partition)
kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"rollingUpdate":{"partition":2}}}}'
# Delete (PVCs are retained)
kubectl delete statefulset web
kubectl delete pvc -l app=web # Delete PVCs
3. Persistent Storage¶
3.1 Storage Hierarchy¶
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Storage Hierarchy β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β Pod β β
β β βββββββββββββββββββββββββββββββββββ β β
β β β Volume Mount β β β
β β β /data β β β
β β βββββββββββββββ¬ββββββββββββββββββββ β β
β βββββββββββββββββββΌββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β PersistentVolumeClaim (PVC) β β
β β β’ Storage request β β
β β β’ Namespace-scoped β β
β βββββββββββββββββββ¬ββββββββββββββββββββββββ β
β β Binding β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β PersistentVolume (PV) β β
β β β’ Actual storage β β
β β β’ Cluster-scoped β β
β βββββββββββββββββββ¬ββββββββββββββββββββββββ β
β β β
β βΌ β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β StorageClass β β
β β β’ Dynamic provisioning β β
β β β’ Storage type definition β β
β βββββββββββββββββββββββββββββββββββββββββββ β
β β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
3.2 StorageClass¶
# storageclass.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: fast
annotations:
storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/gce-pd # Varies by cloud provider
parameters:
type: pd-ssd
reclaimPolicy: Delete # Delete or Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer # Or Immediate
---
# AWS EBS StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: aws-fast
provisioner: ebs.csi.aws.com
parameters:
type: gp3
iops: "3000"
throughput: "125"
reclaimPolicy: Delete
allowVolumeExpansion: true
---
# Local StorageClass
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
3.3 PersistentVolume (Static Provisioning)¶
# pv-static.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-manual
labels:
type: local
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: manual
hostPath:
path: /mnt/data
---
# NFS PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs
spec:
capacity:
storage: 100Gi
accessModes:
- ReadWriteMany
persistentVolumeReclaimPolicy: Retain
storageClassName: nfs
nfs:
server: nfs-server.example.com
path: /exports/data
---
# AWS EBS PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-aws-ebs
spec:
capacity:
storage: 50Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: aws-fast
awsElasticBlockStore:
volumeID: vol-0123456789abcdef
fsType: ext4
3.4 PersistentVolumeClaim¶
# pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: app-data-pvc
namespace: production
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: fast # Dynamic provisioning
# selector: # Use for static binding
# matchLabels:
# type: local
---
# Using PVC in Pod
apiVersion: v1
kind: Pod
metadata:
name: app-with-storage
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: data
mountPath: /app/data
volumes:
- name: data
persistentVolumeClaim:
claimName: app-data-pvc
3.5 Volume Expansion and Snapshots¶
# Expand PVC (requires allowVolumeExpansion: true)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: expandable-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 20Gi # Expanded from 5Gi
storageClassName: fast
---
# VolumeSnapshot (requires CSI driver)
apiVersion: snapshot.storage.k8s.io/v1
kind: VolumeSnapshot
metadata:
name: data-snapshot
spec:
volumeSnapshotClassName: csi-snapclass
source:
persistentVolumeClaimName: app-data-pvc
---
# Restore PVC from snapshot
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: restored-pvc
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 5Gi
storageClassName: fast
dataSource:
name: data-snapshot
kind: VolumeSnapshot
apiGroup: snapshot.storage.k8s.io
4. ConfigMap Advanced¶
4.1 ConfigMap Creation Methods¶
# Create from literals
kubectl create configmap app-config \
--from-literal=LOG_LEVEL=info \
--from-literal=MAX_CONNECTIONS=100
# Create from file
kubectl create configmap nginx-config \
--from-file=nginx.conf
# Create from directory
kubectl create configmap app-configs \
--from-file=config/
# configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
data:
# Simple key-value
LOG_LEVEL: "info"
DATABASE_HOST: "db.example.com"
# File format
app.properties: |
server.port=8080
server.host=0.0.0.0
logging.level=INFO
nginx.conf: |
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
location /api {
proxy_pass http://backend:8080;
}
}
4.2 ConfigMap Usage¶
# configmap-usage.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-pod
spec:
containers:
- name: app
image: myapp:latest
# Inject as environment variable
env:
- name: LOG_LEVEL
valueFrom:
configMapKeyRef:
name: app-config
key: LOG_LEVEL
# Entire ConfigMap as environment variables
envFrom:
- configMapRef:
name: app-config
prefix: APP_ # Optional prefix
volumeMounts:
# Mount as file
- name: config-volume
mountPath: /etc/app
# Mount specific key only
- name: nginx-volume
mountPath: /etc/nginx/conf.d
volumes:
- name: config-volume
configMap:
name: app-config
# All items
- name: nginx-volume
configMap:
name: app-config
items:
- key: nginx.conf
path: default.conf
mode: 0644
4.3 ConfigMap Change Detection¶
# Auto-reload (using Reloader)
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-deployment
annotations:
# stakater/Reloader annotation
reloader.stakater.com/auto: "true"
# Or specific ConfigMap only
configmap.reloader.stakater.com/reload: "app-config"
spec:
template:
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: config
mountPath: /etc/app
volumes:
- name: config
configMap:
name: app-config
---
# Sidecar for change detection
apiVersion: v1
kind: Pod
metadata:
name: app-with-reloader
spec:
containers:
- name: app
image: myapp:latest
volumeMounts:
- name: config
mountPath: /etc/app
- name: config-reloader
image: jimmidyson/configmap-reload:v0.5.0
args:
- --volume-dir=/etc/app
- --webhook-url=http://localhost:8080/-/reload
volumeMounts:
- name: config
mountPath: /etc/app
readOnly: true
volumes:
- name: config
configMap:
name: app-config
5. DaemonSet and Job¶
5.1 DaemonSet¶
# daemonset.yaml
# Deploy Pod on every node
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: node-exporter
labels:
app: node-exporter
spec:
selector:
matchLabels:
app: node-exporter
template:
metadata:
labels:
app: node-exporter
spec:
# Deploy on specific nodes only
nodeSelector:
monitoring: "true"
tolerations:
# Deploy on master nodes too
- key: node-role.kubernetes.io/control-plane
operator: Exists
effect: NoSchedule
containers:
- name: node-exporter
image: prom/node-exporter:v1.6.1
ports:
- containerPort: 9100
hostPort: 9100
volumeMounts:
- name: proc
mountPath: /host/proc
readOnly: true
- name: sys
mountPath: /host/sys
readOnly: true
resources:
limits:
cpu: 200m
memory: 100Mi
requests:
cpu: 100m
memory: 50Mi
hostNetwork: true
hostPID: true
volumes:
- name: proc
hostPath:
path: /proc
- name: sys
hostPath:
path: /sys
updateStrategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 1
5.2 Job¶
# job.yaml
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
# Completion conditions
completions: 1 # Number of successful Pods required
parallelism: 1 # Number of concurrent Pods
backoffLimit: 3 # Retry count on failure
activeDeadlineSeconds: 600 # Maximum execution time
# Delete after completion
ttlSecondsAfterFinished: 3600
template:
spec:
restartPolicy: Never # OnFailure or Never
containers:
- name: migrator
image: myapp/migrator:latest
command: ["python", "migrate.py"]
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: db-secret
key: url
---
# Parallel Job
apiVersion: batch/v1
kind: Job
metadata:
name: parallel-processing
spec:
completions: 10 # Total 10 completions
parallelism: 3 # 3 at a time
template:
spec:
restartPolicy: OnFailure
containers:
- name: worker
image: myapp/worker:latest
5.3 CronJob¶
# cronjob.yaml
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 2 * * *" # Daily at 2 AM
timeZone: "Asia/Seoul"
# Concurrency policy
concurrencyPolicy: Forbid # Allow, Forbid, or Replace
# Starting deadline
startingDeadlineSeconds: 300
# Success/failure history
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
# Suspend
suspend: false
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: backup
image: postgres:15
command:
- /bin/sh
- -c
- |
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME > /backup/db_$(date +%Y%m%d).sql
aws s3 cp /backup/db_$(date +%Y%m%d).sql s3://backups/
env:
- name: DB_HOST
value: "postgres"
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-secret
key: username
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: db-secret
key: password
volumeMounts:
- name: backup
mountPath: /backup
volumes:
- name: backup
emptyDir: {}
6. Advanced Scheduling¶
6.1 Node Affinity¶
# node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
affinity:
nodeAffinity:
# Required conditions
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gpu
operator: In
values:
- "true"
- key: kubernetes.io/arch
operator: In
values:
- amd64
# Preferred conditions
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: gpu-type
operator: In
values:
- nvidia-a100
- weight: 50
preference:
matchExpressions:
- key: gpu-type
operator: In
values:
- nvidia-v100
containers:
- name: gpu-app
image: nvidia/cuda:12.0-base
resources:
limits:
nvidia.com/gpu: 1
6.2 Pod Affinity/Anti-Affinity¶
# pod-affinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
replicas: 3
selector:
matchLabels:
app: web
template:
metadata:
labels:
app: web
spec:
affinity:
# Prefer same node as cache Pod
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- cache
topologyKey: kubernetes.io/hostname
# Deploy on different nodes than other Pods of same app
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- web
topologyKey: kubernetes.io/hostname
containers:
- name: web
image: nginx:latest
6.3 Taints and Tolerations¶
# Add Taint to node
kubectl taint nodes node1 dedicated=gpu:NoSchedule
kubectl taint nodes node2 special=true:PreferNoSchedule
kubectl taint nodes node3 critical=true:NoExecute
# Remove Taint
kubectl taint nodes node1 dedicated=gpu:NoSchedule-
# tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
name: gpu-pod
spec:
tolerations:
# Exact match
- key: "dedicated"
operator: "Equal"
value: "gpu"
effect: "NoSchedule"
# Key exists
- key: "special"
operator: "Exists"
effect: "PreferNoSchedule"
# NoExecute + tolerationSeconds
- key: "critical"
operator: "Equal"
value: "true"
effect: "NoExecute"
tolerationSeconds: 3600 # Evict after 1 hour
containers:
- name: app
image: myapp:latest
6.4 Topology Spread Constraints¶
# topology-spread.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: distributed-app
spec:
replicas: 6
selector:
matchLabels:
app: distributed
template:
metadata:
labels:
app: distributed
spec:
topologySpreadConstraints:
# Even distribution across zones
- maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app: distributed
# Even distribution across nodes
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: ScheduleAnyway
labelSelector:
matchLabels:
app: distributed
containers:
- name: app
image: myapp:latest
7. Practice Exercises¶
Exercise 1: Microservices Ingress¶
# Requirements:
# - api.example.com/v1/* β api-v1-service
# - api.example.com/v2/* β api-v2-service
# - TLS enabled, HTTPβHTTPS redirect
# - Rate limiting applied
# Write Ingress
Exercise 2: Redis Cluster StatefulSet¶
# Requirements:
# - 3-node Redis Cluster
# - 1Gi PVC for each node
# - Headless Service for inter-node communication
# - Appropriate resource limits
# Write StatefulSet
Exercise 3: Log Collection DaemonSet¶
# Requirements:
# - Collect /var/log from all nodes
# - Send to Elasticsearch
# - Manage config with ConfigMap
# - Deploy on master nodes too
# Write DaemonSet
Exercise 4: Batch Data Processing Job¶
# Requirements:
# - Process 100 data items (completions: 100)
# - Process 10 at a time (parallelism: 10)
# - Retry 3 times on failure
# - Must complete within 2 hours
# - Delete 24 hours after completion
# Write Job
Next Steps¶
- 09_Helm_Package_Management - Helm charts
- 10_CI_CD_Pipelines - Automated deployment
- 07_Kubernetes_Security - Review security
References¶
β Previous: Kubernetes Security | Next: Helm Package Management β | Table of Contents