Модуль 11 / 19
StatefulSet, DaemonSet, Job и CronJob
Содержание
1. Цели модуля
Вы научитесь выбирать Deployment, StatefulSet, DaemonSet, Job или CronJob, объяснять их гарантии и диагностировать неуспешную batch-задачу.
2. Теория: выбор контроллера
Deployment управляет взаимозаменяемыми stateless Pods. StatefulSet даёт стабильные ordinal names, порядок и связь identity со storage. DaemonSet запускает node-local Pod на каждом подходящем Node.
Job выполняет конечную задачу до заданного числа успешных completions. CronJob по расписанию создаёт Jobs, а не Pods напрямую.
3. Теория: StatefulSet и DaemonSet
StatefulSet требует headless Service для сетевой identity. Stable identity не делает приложение stateful автоматически: нужны подходящие PVC, replication и backup.
DaemonSet применяют для node agents, CNI/CSI, логов и мониторинга. Количество Pods определяется подходящими Nodes, а не replicas.
4. Теория: Job и CronJob
Job управляет retries через backoffLimit, параллелизмом и completions; Indexed mode даёт каждой работе индекс. ttlSecondsAfterFinished очищает завершённые Jobs.
CronJob поддерживает timeZone, concurrencyPolicy и startingDeadlineSeconds. Запуск приблизителен и может быть пропущен или продублирован, поэтому задача должна быть idempotent. TZ/CRON_TZ нельзя писать внутри schedule.
5. Методические указания
- Выбирайте controller по identity и completion semantics
- Не запускайте долгоживущий server через Job
- Делайте batch operations idempotent
- Ограничивайте history и TTL завершённых Jobs
- Проверяйте headless Service и PVC перед StatefulSet
- Для CronJob задавайте timeZone и concurrencyPolicy явно
6. Лабораторная работа: workload controllers
Сохраните объекты как controllers-lab.yaml.
apiVersion: v1
kind: Namespace
metadata: {name: lab-controllers}
---
apiVersion: v1
kind: Service
metadata: {name: database, namespace: lab-controllers}
spec:
clusterIP: None
selector: {app: database}
ports: [{name: peer, port: 8080}]
---
apiVersion: apps/v1
kind: StatefulSet
metadata: {name: database, namespace: lab-controllers}
spec:
serviceName: database
replicas: 2
selector:
matchLabels: {app: database}
template:
metadata:
labels: {app: database}
spec:
containers:
- {name: app, image: "busybox:1.37.0", command: ["sh", "-c", "echo $HOSTNAME; sleep 3600"]}
---
apiVersion: apps/v1
kind: DaemonSet
metadata: {name: node-agent, namespace: lab-controllers}
spec:
selector:
matchLabels: {app: node-agent}
template:
metadata:
labels: {app: node-agent}
spec:
containers:
- {name: agent, image: "busybox:1.37.0", command: ["sh", "-c", "sleep 3600"]}
---
apiVersion: batch/v1
kind: Job
metadata: {name: indexed, namespace: lab-controllers}
spec:
completions: 3
parallelism: 2
completionMode: Indexed
ttlSecondsAfterFinished: 600
template:
spec:
restartPolicy: Never
containers:
- {name: task, image: "busybox:1.37.0", command: ["sh", "-c", "echo index=$JOB_COMPLETION_INDEX"]}
---
apiVersion: batch/v1
kind: CronJob
metadata: {name: report, namespace: lab-controllers}
spec:
schedule: "*/5 * * * *"
timeZone: Etc/UTC
concurrencyPolicy: Forbid
startingDeadlineSeconds: 120
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 1
suspend: true
jobTemplate:
spec:
ttlSecondsAfterFinished: 600
template:
spec:
restartPolicy: Never
containers:
- {name: report, image: "busybox:1.37.0", command: ["date", "-u"]}kubectl apply -f controllers-lab.yaml
kubectl rollout status statefulset/database -n lab-controllers --timeout=120s
kubectl rollout status daemonset/node-agent -n lab-controllers --timeout=120s
kubectl wait job/indexed -n lab-controllers --for=condition=Complete --timeout=120s
kubectl get statefulset,daemonset,job,cronjob,pod -n lab-controllers -o wide
kubectl get pods -n lab-controllers -l app=database
kubectl logs -n lab-controllers -l job-name=indexed --prefix
kubectl create job report-now -n lab-controllers --from=cronjob/report
kubectl wait job/report-now -n lab-controllers --for=condition=Complete --timeout=120s
kubectl logs job/report-now -n lab-controllersКритерий: StatefulSet создаёт database-0/1, DaemonSet имеет Ready на подходящих Nodes, Indexed Job завершает три индекса, ручной Job из CronJob успешен.
7. Диагностика: failed Job
Сохраните failing-job.yaml. Контейнер намеренно завершается с exitCode 42; wait Complete ожидаемо получает timeout.
apiVersion: batch/v1
kind: Job
metadata: {name: failing, namespace: lab-controllers}
spec:
backoffLimit: 2
activeDeadlineSeconds: 60
template:
spec:
restartPolicy: Never
containers:
- {name: task, image: "busybox:1.37.0", command: ["sh", "-c", "echo deliberate failure >&2; exit 42"]}kubectl apply -f failing-job.yaml
kubectl wait job/failing -n lab-controllers --for=condition=Complete --timeout=45s
kubectl get job,pod -n lab-controllers
kubectl get job failing -n lab-controllers -o jsonpath='{range .status.conditions[*]}{.type}{"="}{.status}{" reason="}{.reason}{"\n"}{end}'
kubectl logs -n lab-controllers -l job-name=failing --prefix
kubectl describe job failing -n lab-controllers
kubectl events -n lab-controllers --for job/failing
kubectl delete namespace lab-controllersЦепочка: Job Conditions → failed/succeeded counters → Pods и exitCode → logs → Events → backoffLimit/deadline. Не увеличивайте retries, пока причина детерминирована.
8. Контроль и шпаргалка
- Когда StatefulSet лучше Deployment?
- Почему DaemonSet не имеет replicas?
- Что означает Indexed completion?
- Зачем batch-задаче idempotency?
- Чем suspend CronJob отличается от удаления?
Модуль освоен, если вы обосновываете controller по требованиям и доказываете причину failed Job по status, exitCode и logs.
PDF для работы офлайн
Скачайте оформленную версию модуля для чтения без подключения к сети.