← Back to notes

Job и
CronJob


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

ПараметрОписаниеПо умолчанию
backoffLimitКоличество повторных попыток при ошибке6
completionsСколько раз Job должен успешно завершиться1
parallelismСколько Pod работают одновременно1
activeDeadlineSecondsМаксимальное время выполнения (включая повторы)нет
ttlSecondsAfterFinishedУдалить Job через N секунд после завершениянет

restartPolicy

Job поддерживает только две политики перезапуска:

ЗначениеПоведение
NeverПри ошибке Pod не перезапускается — создаётся новый Pod (до backoffLimit)
OnFailureПри ошибке контейнер перезапускается в том же Pod

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=воскресенье)
    
* * * * *
РасписаниеОписание
*/5 * * * *Каждые 5 минут
0 * * * *Каждый час
0 2 * * *Ежедневно в 2:00
0 0 * * 0Каждое воскресенье в полночь
0 3 1 * *1-го числа каждого месяца в 3:00
@dailyЕжедневно в полночь (синтаксис shorthand)

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Что делать, если предыдущий Job ещё не завершён
successfulJobsHistoryLimitСколько успешных Job хранить (по умолчанию 3)
failedJobsHistoryLimitСколько неудачных Job хранить (по умолчанию 1)
startingDeadlineSecondsМаксимальная задержка запуска (если пропущен слот)
suspendПриостановить создание новых Job (true/false)
timeZoneTimezone для расписания (stable с 1.27)

concurrencyPolicy

ЗначениеПоведение
Allow (по умолчанию)Разрешить параллельный запуск нескольких Job
ForbidПропустить новый Job, если предыдущий ещё работает
ReplaceОстановить текущий Job и запустить новый

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 с parallelism
Резервное копированиеCronJob
Генерация отчётовCronJob
Очистка устаревших данныхCronJob
Ротация логовCronJob
Прогрев кешаJob (после деплоя)

Когда использовать

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.


11: StatefulSet и DaemonSet

13: Resource Management

Job и CronJob | Aleksandr Suprun