CronJob: задачи по расписанию
Расписание в UTC, concurrencyPolicy, лимиты истории и другие места, где CronJob неприятно удивляет.
Что вообще такое CronJob
CronJob сидит этажом выше Job. Сам Pod не создаёт. По расписанию запускает новый Job, а уже Job-контроллер создаёт Pod и ждёт его завершения. Двухуровневая конструкция.
Зачем: регулярные задачи. Бэкап раз в час, очистка устаревших записей каждую ночь, синхронизация с внешним API раз в 15 минут. Раньше это был cron на отдельной VM, теперь объект в кластере.
CronJob это batch/v1 (с 1.21, до этого был batch/v1beta1, который
удалили в 1.25). Шедулинг делает kube-controller-manager. У него
внутри тикает таймер, который сверяется со spec каждую минуту и
решает: пора создавать Job или нет.
Минимальный YAML
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello-cron
spec:
schedule: "* * * * *"
successfulJobsHistoryLimit: 2
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
containers:
- name: hello
image: busybox:1.36
command: ["sh", "-c", "echo tick"]
Разбор полей
Расписание считается в UTC, а не по часам пользователя. Запись
0 3 * * * сработает в 03:00 UTC, пока не задан spec.timeZone.
schedule. Обычный пятипольный cron: минуты, часы, день месяца, месяц, день недели.* * * * *это «каждую минуту». Время считается в UTC, поэтому «03:00» в расписании и «03:00» на часах пользователя расходятся. Часовой пояс задаётся полемspec.timeZone(напримерEurope/Moscow): поле появилось в 1.24 и стало стабильным в 1.27. На кластерах постарше пояс не настроить: расписание пересчитывают в UTC руками.jobTemplate. Полный spec обычного Job. Cron его клонирует и применяет на каждый тик.successfulJobsHistoryLimit. Дефолт 3. Сколько успешных Job хранить. Остальные удаляются вместе с Pod. Без лимита через сутки в namespace будет 1440 объектов Job.failedJobsHistoryLimit. То же для упавших, дефолт 1.concurrencyPolicy. Что делать, если предыдущий Job ещё не закончился, а пора запускать следующий:Allow(дефолт). Запустить параллельно. Опасно для бэкапов, можно получить два процесса на одну БД.Forbid. Пропустить запуск, дождаться текущего.Replace. Убить текущий, запустить новый.
startingDeadlineSeconds. Если из-за лагов controller-manager пропустил окно запуска, через сколько секунд считать запуск потерянным. Без него после рестарта controller-manager может выстрелить пачкой просроченных Job.suspend: true. Временно отключить расписание без удаления объекта.
restartPolicy внутри jobTemplate
Только OnFailure или Never, как в обычном Job. Always
запрещён. Та же логика: рестартами рулит контроллер, не kubelet.
Связанные команды
kubectl create cronjob hello --image=busybox --schedule='*/5 * * * *' -- echo hi
kubectl get cronjob
kubectl get jobs --watch
kubectl create job --from=cronjob/hello hello-manual # триггер вручную
kubectl patch cronjob hello -p '{"spec":{"suspend":true}}'
kubectl describe cronjob hello-cron
Что часто ломается
- Забыли
successfulJobsHistoryLimit. Через сутки 1440 объектов в etcd. concurrencyPolicy: Allowна тяжёлой задаче. Предыдущий ещё идёт, новый стартанул, два процесса жрут CPU на одной БД и блокируют друг друга.- Расписание
* * * * *оставили в проде на «потестировать». Каждую минуту бэкап. Уведомления переполняются за день. - После рестарта controller-manager сразу запустилось 50 пропущенных
Job.
startingDeadlineSecondsлечит.
Домашка
Теорию закрепляет задание на своём кластере: 3 шага с проверкой. Кластер поднимается по треку Kubernetes локально, задания лежат в репозитории k8s-practice.
./run.sh start k8s-cronjob # развернуть стартовое состояние
./run.sh verify k8s-cronjob # проверить текущий шаг
Коротко
- CronJob не создаёт Pod: по расписанию он создаёт Job, а Pod создаёт уже Job.
- Расписание считается в UTC, пока не задан
spec.timeZone(стабилен с 1.27). - Без
successfulJobsHistoryLimitиfailedJobsHistoryLimitобъекты копятся в etcd. concurrencyPolicyрешает, что делать с наложением запусков:Allow,Forbid,Replace.startingDeadlineSecondsне даёт выстрелить пачкой пропущенных запусков после сбоя.suspend: trueвыключает расписание, не удаляя объект.
Дрилл · вопросы как на собесе
Проверь себя без подсказок
Сформулируй ответ вслух или письменно, потом раскрой и честно отметь: знал или нет.
Что такое Job и CronJob?
K8S-013Прошли материал до конца? Отметьте урок пройденным.
Прогресс сохранён в этом браузере
Почистишь историю или откроешь с телефона, и отметки пропадут. Оставь почту, они переедут в аккаунт. Пароль придумывать не нужно.
Готово. теперь в аккаунте: прогресс виден с любого устройства. Мой прогресс