← 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

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.


11: StatefulSet и DaemonSet

13: Resource Management

Job и CronJob | Aleksandr Suprun