Deployment и StatefulSet держат Pod запущенными постоянно. Для разовых задач — миграция БД, пакетная обработка, бэкап — нужны Job и CronJob.
[source: kubernetes.io/docs/concepts/workloads/controllers/job/]
Job
Job создаёт один или несколько Pod, выполняющих задачу до завершения. После успешного завершения Pod не перезапускается.
Манифест Job
apiVersion: batch/v1
kind: Job
metadata:
name: data-migration
spec:
backoffLimit: 4
activeDeadlineSeconds: 600
ttlSecondsAfterFinished: 3600
template:
spec:
containers:
- name: migrate
image: myapp:1.0
command: ["./migrate", "--up"]
env:
- name: DB_HOST
value: postgres-service
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
restartPolicy: Never
Параметры Job
restartPolicy
Job поддерживает только две политики перезапуска:
Always нельзя использовать с Job — API Server отклонит.
Never — для сохранения логов упавших Pod. OnFailure — когда Pod overhead нежелателен.
Параллельное выполнение
apiVersion: batch/v1
kind: Job
metadata:
name: batch-process
spec:
completions: 10 # 10 успешных завершений
parallelism: 3 # до 3 Pod одновременно
template:
spec:
containers:
- name: worker
image: batch-processor:1.0
command: ["./process", "--batch"]
restartPolicy: OnFailure
Kubernetes держит 3 Pod параллельно, пока не наберётся 10 успешных завершений.
Автоочистка
Без ttlSecondsAfterFinished завершённые Job и их Pod накапливаются в кластере и потребляют память API Server.
spec:
ttlSecondsAfterFinished: 3600 # удалить Job и его Pod через 1 час
TTL-after-finished controller — GA с K8s 1.23, включён по умолчанию.
Команды kubectl для Job
kubectl apply -f job.yaml
kubectl get jobs
kubectl describe job data-migration
# Логи Job (если один Pod)
kubectl logs job/data-migration
# Логи конкретного Pod Job
kubectl logs <pod-name-from-job>
# Удалить Job и его Pod
kubectl delete job data-migration
CronJob
CronJob создаёт Job по расписанию. Аналог crontab в Linux.
[source: kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/]
Формат расписания
┌───────────── минута (0-59)
│ ┌───────────── час (0-23)
│ │ ┌───────────── день месяца (1-31)
│ │ │ ┌───────────── месяц (1-12)
│ │ │ │ ┌───────────── день недели (0-6, 0=воскресенье)
│ │ │ │ │
* * * * *
Timezone: если .spec.timeZone не задан, CronJob интерпретирует расписание в локальной timezone kube-controller-manager. Поле timeZone — stable с K8s 1.27:
spec:
schedule: "0 2 * * *"
timeZone: "Europe/Moscow"
Манифест CronJob
apiVersion: batch/v1
kind: CronJob
metadata:
name: db-backup
spec:
schedule: "0 2 * * *"
timeZone: "Europe/Moscow"
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 5
startingDeadlineSeconds: 300
jobTemplate:
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 86400
template:
spec:
containers:
- name: backup
image: postgres:16
command:
- sh
- -c
- |
pg_dump -h $DB_HOST -U $DB_USER $DB_NAME | \
gzip > /backup/db-$(date +%Y%m%d-%H%M).sql.gz
env:
- name: DB_HOST
value: postgres-service
- name: DB_USER
valueFrom:
secretKeyRef:
name: db-credentials
key: username
- name: DB_NAME
value: mydb
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: db-credentials
key: password
volumeMounts:
- name: backup-volume
mountPath: /backup
restartPolicy: OnFailure
volumes:
- name: backup-volume
persistentVolumeClaim:
claimName: backup-pvc
Параметры CronJob
concurrencyPolicy
Forbid — для backup и отчётов. Replace — когда важен только последний запуск.
Команды kubectl для CronJob
kubectl apply -f cronjob.yaml
kubectl get cronjobs
kubectl get cj
kubectl describe cronjob db-backup
# Ручной запуск CronJob
kubectl create job manual-backup --from=cronjob/db-backup
# Приостановить CronJob
kubectl patch cronjob db-backup -p '{"spec":{"suspend":true}}'
# Возобновить
kubectl patch cronjob db-backup -p '{"spec":{"suspend":false}}'
# Посмотреть созданные Job
kubectl get jobs -l "batch.kubernetes.io/cronjob-name=db-backup"
Типичные use cases
Когда использовать
Job — разовая задача с детерминированным завершением. Для миграций БД: запускай Job перед обновлением Deployment, проверяй успех, потом деплой.
CronJob — периодические задачи. concurrencyPolicy: Forbid для backup и отчётов. startingDeadlineSeconds — чтобы пропущенный слот не запустил старый Job с опозданием.
ttlSecondsAfterFinished — для Job, где не нужна долгая история выполнения. Без него завершённые Job накапливаются.
Типичные ошибки
restartPolicy: Always в Job. API Server отклонит — Job поддерживает только Never и OnFailure. Часто попадает при копировании шаблона Deployment.
Нет activeDeadlineSeconds. Зависший Job (бесконечный цикл, deadlock при коннекте к БД) будет висеть, создавая новые Pod до backoffLimit. Всегда задавай таймаут.
CronJob с concurrencyPolicy: Allow для backup. Если предыдущий backup не завершился — запустится параллельный pg_dump к одной БД. Используй Forbid.
Не учитывать timezone. Без .spec.timeZone расписание зависит от локальной timezone kube-controller-manager, а в managed-кластере она может отличаться от timezone команды. Для переносимости указывай timeZone: "Europe/Moscow" или Etc/UTC явно.
Дефолтные history limits для частых CronJob. Для CronJob с расписанием каждые 5 минут история (3 успешных + 1 неудачный) накапливает много объектов. Снижай лимиты или повышай ttlSecondsAfterFinished.
backoffLimit: 0 для критических Job. При единственной попытке временная проблема убьёт Job окончательно. Минимум 2-3 для нетривиальных задач.
Альтернативы
Init Container в Deployment — миграция БД перед стартом приложения. Проще Job, но без независимой истории выполнения (глава 02).
Argo Workflows — DAG задач, ветки, повторы, артефакты. Для ML/ETL пайплайнов.
Airflow на Kubernetes — data engineering пайплайны с зависимостями.
Temporal — долгоживущие задачи с гарантиями at-least-once / exactly-once. Для бизнес-процессов сложнее CronJob.