Модуль 1.2: Jobs та CronJobs
Складність:
[MEDIUM]— Ключова навичка CKAD зі специфічними паттернамиЧас на виконання: 45–50 хвилин
Передумови: Модуль 1.1 (Образи контейнерів), розуміння Підів
Що ви зможете робити
Розділ «Що ви зможете робити»Після завершення цього модуля ви зможете:
- Створити Jobs та CronJobs з правильними лічильниками завершення, паралелізмом та лімітами повторних спроб
- Налаштувати розклад CronJob, політики конкурентності та ліміти історії
- Діагностувати невдалі Jobs шляхом перевірки логів Підів, подій та поведінки перезапуску
- Порівняти Jobs та CronJobs і обрати правильний ресурс для одноразових та періодичних пакетних навантажень
Чому цей модуль важливий
Розділ «Чому цей модуль важливий»Не кожне навантаження працює вічно. Резервне копіювання виконується одноразово. Звіти генеруються щогодини. Міграції даних завершуються і зупиняються. Це пакетні навантаження, і Kubernetes обробляє їх за допомогою Jobs та CronJobs.
CKAD активно тестує Jobs, оскільки це ключове завдання розробника. Ви побачите питання на кшталт:
- “Створіть Job, що виконується до завершення”
- “Створіть CronJob, що запускається кожні 5 хвилин”
- “Виправте Job, що не працює”
- “Налаштуйте паралельні Jobs”
Аналогія з фабричною зміною
Деплойменти — як постійний персонал фабрики — вони приходять і працюють, поки їх не звільнять. Jobs — як підрядники, найняті для конкретних завдань — вони приходять, виконують роботу і йдуть. CronJobs — як бригади планового обслуговування — вони з’являються у визначений час (щоночі, щопонеділка), виконують свою роботу і відходять.
Jobs: Одноразові завдання
Розділ «Jobs: Одноразові завдання»Job створює один або кілька Підів і гарантує, що вони виконаються до успішного завершення.
Створення Jobs імперативно
Розділ «Створення Jobs імперативно»# Простий Jobk create job backup --image=busybox -- echo "Backup complete"
# Job з командою оболонкиk create job report --image=busybox -- /bin/sh -c "date; echo 'Report generated'"
# Згенерувати YAMLk create job backup --image=busybox --dry-run=client -o yaml -- echo "done" > job.yamlСтруктура YAML для Job
Розділ «Структура YAML для Job»apiVersion: batch/v1kind: Jobmetadata: name: backup-jobspec: template: spec: containers: - name: backup image: busybox command: ["sh", "-c", "echo 'Backing up data' && sleep 10"] restartPolicy: Never # або OnFailure backoffLimit: 4 # Кількість спроб повтору ttlSecondsAfterFinished: 100 # АвтоочищенняКлючові властивості Job
Розділ «Ключові властивості Job»| Властивість | Призначення | За замовчуванням |
|---|---|---|
restartPolicy | Що робити при невдачі | Має бути Never або OnFailure |
backoffLimit | Максимальна кількість повторних спроб | 6 |
activeDeadlineSeconds | Максимальний час виконання Job | Немає (працює нескінченно) |
ttlSecondsAfterFinished | Автовидалення після завершення | Немає (зберігається назавжди) |
completions | Необхідна кількість успішних завершень | 1 |
parallelism | Максимум паралельних Підів | 1 |
restartPolicy пояснення
Розділ «restartPolicy пояснення»# Never: Не перезапускати контейнери, що впали (створити новий Під)restartPolicy: Never# Під падає → Створюється новий Під (до backoffLimit)
# OnFailure: Перезапустити контейнер, що впав, у тому ж ПідіrestartPolicy: OnFailure# Контейнер падає → Той самий Під перезапускає контейнерПаттерни Jobs
Розділ «Паттерни Jobs»Паттерн 1: Одне завершення (за замовчуванням)
Розділ «Паттерн 1: Одне завершення (за замовчуванням)»Запустити один Під, завершити один раз:
apiVersion: batch/v1kind: Jobmetadata: name: single-jobspec: template: spec: containers: - name: worker image: busybox command: ["echo", "Single task done"] restartPolicy: NeverПаттерн 2: Множинні завершення (послідовно)
Розділ «Паттерн 2: Множинні завершення (послідовно)»Виконати завдання N разів, по одному за раз:
apiVersion: batch/v1kind: Jobmetadata: name: sequential-jobspec: completions: 5 # Виконати 5 разів parallelism: 1 # По одному за раз template: spec: containers: - name: worker image: busybox command: ["sh", "-c", "echo Task $JOB_COMPLETION_INDEX"] restartPolicy: NeverПаттерн 3: Паралельна обробка
Розділ «Паттерн 3: Паралельна обробка»Запустити кілька Підів одночасно:
apiVersion: batch/v1kind: Jobmetadata: name: parallel-jobspec: completions: 10 # 10 загальних завершень parallelism: 3 # 3 Піди одночасно template: spec: containers: - name: worker image: busybox command: ["sh", "-c", "echo Processing batch && sleep 5"] restartPolicy: NeverПаттерн 4: Черга роботи (паралелізм без completions)
Розділ «Паттерн 4: Черга роботи (паралелізм без completions)»Обробляти елементи, поки черга не спорожніє:
apiVersion: batch/v1kind: Jobmetadata: name: queue-jobspec: parallelism: 3 # 3 воркери # Без completions: воркери обробляють, поки не завершаться з кодом 0 template: spec: containers: - name: worker image: busybox command: ["sh", "-c", "process-queue && exit 0"] restartPolicy: NeverCronJobs: Заплановані завдання
Розділ «CronJobs: Заплановані завдання»CronJobs запускають Jobs за розкладом.
Створення CronJobs імперативно
Розділ «Створення CronJobs імперативно»# Щохвилиниk create cronjob minute-task --image=busybox --schedule="* * * * *" -- echo "Every minute"
# Щогодини на 30-й хвилиніk create cronjob hourly-task --image=busybox --schedule="30 * * * *" -- date
# Щоденно опівночіk create cronjob daily-cleanup --image=busybox --schedule="0 0 * * *" -- echo "Daily cleanup"
# Згенерувати YAMLk create cronjob backup --image=busybox --schedule="0 2 * * *" --dry-run=client -o yaml -- /backup.sh > cronjob.yamlСтруктура YAML для CronJob
Розділ «Структура YAML для CronJob»apiVersion: batch/v1kind: CronJobmetadata: name: daily-backupspec: schedule: "0 2 * * *" # Щоденно о 2:00 concurrencyPolicy: Forbid # Не перекривати successfulJobsHistoryLimit: 3 # Зберігати останні 3 успішні failedJobsHistoryLimit: 1 # Зберігати останній 1 невдалий startingDeadlineSeconds: 200 # Максимальна затримка запуску jobTemplate: spec: template: spec: containers: - name: backup image: busybox command: ["sh", "-c", "echo 'Backup at $(date)'"] restartPolicy: OnFailureФормат розкладу Cron
Розділ «Формат розкладу Cron»┌───────────── хвилина (0 - 59)│ ┌───────────── година (0 - 23)│ │ ┌───────────── день місяця (1 - 31)│ │ │ ┌───────────── місяць (1 - 12)│ │ │ │ ┌───────────── день тижня (0 - 6) (Неділя = 0)│ │ │ │ │* * * * *Типові розклади
Розділ «Типові розклади»| Розклад | Значення |
|---|---|
* * * * * | Щохвилини |
*/5 * * * * | Кожні 5 хвилин |
0 * * * * | Щогодини (на 0-й хвилині) |
0 */2 * * * | Кожні 2 години |
0 0 * * * | Щоденно опівночі |
0 0 * * 0 | Щотижня в неділю опівночі |
0 0 1 * * | Щомісяця 1-го числа опівночі |
30 4 * * 1-5 | О 4:30 у робочі дні |
Політики CronJob
Розділ «Політики CronJob»concurrencyPolicy
Розділ «concurrencyPolicy»Що відбувається, якщо новий розклад спрацьовує, поки попередній Job ще працює?
spec: concurrencyPolicy: Allow # Запускати одночасно (за замовчуванням) # або concurrencyPolicy: Forbid # Пропустити, якщо попередній ще працює # або concurrencyPolicy: Replace # Зупинити попередній, запустити новий| Політика | Поведінка | Сценарій використання |
|---|---|---|
Allow | Запускати паралельні Jobs | Незалежні завдання |
Forbid | Пропустити, якщо попередній працює | Уникнення конкуренції за ресурси |
Replace | Зупинити попередній, запустити новий | Важливі найновіші дані |
startingDeadlineSeconds
Розділ «startingDeadlineSeconds»Скільки часу Job може бути затриманий, перш ніж його вважатимуть пропущеним:
spec: startingDeadlineSeconds: 100 # Має стартувати протягом 100с від розкладуЯкщо Job не може стартувати протягом цього вікна (проблеми кластера, обмеження ресурсів), він пропускається.
Керування Jobs та CronJobs
Розділ «Керування Jobs та CronJobs»Перевірка статусу
Розділ «Перевірка статусу»# Список Jobsk get jobs
# Список CronJobsk get cronjobs
# Отримати Піди Jobk get pods -l job-name=my-job
# Перевірити статус Jobk describe job my-job
# Спостерігати за завершенням Jobk get job my-job -wПерегляд логів
Розділ «Перегляд логів»# Отримати логи з Підa Jobk logs job/my-job
# Отримати логи з конкретного Підak logs my-job-abc12
# Стежити за логамиk logs -f job/my-jobРучний запуск
Розділ «Ручний запуск»# Створити Job з CronJob негайноk create job manual-backup --from=cronjob/daily-backupОчищення
Розділ «Очищення»# Видалити Jobk delete job my-job
# Видалити CronJob (також видаляє створені ним Jobs)k delete cronjob my-cronjob
# Видалити завершені Jobs старші за TTL# (Автоматично, якщо встановлено ttlSecondsAfterFinished)Усунення проблем з Jobs
Розділ «Усунення проблем з Jobs»Job не завершується
Розділ «Job не завершується»# Перевірити статусk describe job my-job
# Типові проблеми:# - Команда контейнера завершується з ненульовим кодом# - Помилка завантаження образу# - Занадто низькі ліміти ресурсів# - restartPolicy встановлено неправильно
# Перевірити логи Підak logs $(k get pods -l job-name=my-job -o jsonpath='{.items[0].metadata.name}')Job постійно повторюється
Розділ «Job постійно повторюється»# Перевірити backoffLimitk get job my-job -o jsonpath='{.spec.backoffLimit}'
# Якщо досягнуто ліміту, перевірити, чому Піди падаютьk describe pods -l job-name=my-jobCronJob не запускається
Розділ «CronJob не запускається»# Перевірити статус CronJobk describe cronjob my-cronjob
# Перевірити час останнього запускуk get cronjob my-cronjob -o jsonpath='{.status.lastScheduleTime}'
# Перевірити, чи призупиненоk get cronjob my-cronjob -o jsonpath='{.spec.suspend}'
# Відновити, якщо призупиненоk patch cronjob my-cronjob -p '{"spec":{"suspend":false}}'Чи знали ви?
Розділ «Чи знали ви?»-
Jobs відстежують завершення за допомогою індексу завершення. У режимі індексованого завершення кожен Під знає свій індекс через змінну середовища
JOB_COMPLETION_INDEX. Це корисно для обробки шардованих даних. -
CronJobs за замовчуванням використовують UTC. Якщо ви встановите
schedule: "0 9 * * *", він запуститься о 9:00 UTC, а не за вашим місцевим часом. Деякі кластери підтримують анотації часового поясу. -
activeDeadlineSecondsзастосовується до всього часу виконання Job. Якщо Job триватиме довше за це значення, Kubernetes його зупинить — навіть якщо завдання все ще успішно виконуються.
Типові помилки
Розділ «Типові помилки»| Помилка | Чому це шкодить | Рішення |
|---|---|---|
restartPolicy: Always | Недійсне для Jobs | Використовуйте Never або OnFailure |
Забули backoffLimit | Job повторюється нескінченно | Встановіть розумне обмеження |
| Неправильний синтаксис cron | Job ніколи не запускається | Перевірте через crontab.guru |
Без ttlSecondsAfterFinished | Завершені Jobs накопичуються | Встановіть автоочищення |
| Перекриття CronJobs | Конкуренція за ресурси | Використовуйте concurrencyPolicy: Forbid |
Тест
Розділ «Тест»-
Які допустимі значення restartPolicy для Job?
Відповідь
`Never` або `OnFailure`. `Always` не допускається для Jobs, оскільки контейнер ніколи не завершився б. -
Як створити CronJob, що запускається кожні 15 хвилин?
Відповідь
`kubectl create cronjob myj --image=busybox --schedule="*/15 * * * *" -- echo done`*/15означає “кожні 15 хвилин”. -
Job має
parallelism: 3таcompletions: 10. Що відбувається?Відповідь
Job запускає до 3 Підів одночасно, поки 10 Підів не завершаться успішно. Він обробляє пакетами: 3 Піди працюють, коли один завершується — запускається інший, поки не буде 10 завершень. -
Що робить
concurrencyPolicy: Forbid?Відповідь
Якщо CronJob спрацьовує, поки попередній Job ще працює, новий запуск пропускається. Це запобігає перекриванню виконань, які можуть спричинити конкуренцію за ресурси.
Практична вправа
Розділ «Практична вправа»Завдання: Створити систему резервного копіювання з Jobs та CronJobs.
Частина 1: Одноразовий Job
# Створити Job, що симулює резервне копіювання бази данихk create job db-backup --image=busybox -- sh -c "echo 'Backing up database' && sleep 5 && echo 'Backup complete'"
# Спостерігати за завершеннямk get job db-backup -w
# Перевірити логиk logs job/db-backupЧастина 2: Запланований CronJob
# Створити CronJob для щогодинного очищенняk create cronjob hourly-cleanup \ --image=busybox \ --schedule="0 * * * *" \ -- sh -c "echo 'Cleanup at $(date)'"
# Ручний запуск для тестуванняk create job manual-cleanup --from=cronjob/hourly-cleanup
# Перевірити результатиk get jobsk logs job/manual-cleanupЧастина 3: Паралельний Job
# Створити parallel-job.yamlapiVersion: batch/v1kind: Jobmetadata: name: parallel-processspec: completions: 6 parallelism: 2 template: spec: containers: - name: worker image: busybox command: ["sh", "-c", "echo Processing item $JOB_COMPLETION_INDEX && sleep 3"] restartPolicy: Neverk apply -f parallel-job.yamlk get pods -l job-name=parallel-process -wОчищення:
k delete job db-backup parallel-processk delete job manual-cleanupk delete cronjob hourly-cleanupПрактичні вправи
Розділ «Практичні вправи»Вправа 1: Базове створення Job (Ціль: 2 хвилини)
Розділ «Вправа 1: Базове створення Job (Ціль: 2 хвилини)»# Створити Job, який:# - Назва: hello-job# - Запускає busybox# - Виводить "Hello from job"
k create job hello-job --image=busybox -- echo "Hello from job"
# Перевірити завершенняk get job hello-job
# Перевірити логиk logs job/hello-job
# Очищенняk delete job hello-jobВправа 2: CronJob з розкладом (Ціль: 2 хвилини)
Розділ «Вправа 2: CronJob з розкладом (Ціль: 2 хвилини)»# Створити CronJob, який:# - Назва: every-minute# - Запускається щохвилини# - Виводить поточну дату
k create cronjob every-minute --image=busybox --schedule="* * * * *" -- date
# Зачекати 1 хвилину та перевіритиsleep 65k get jobs
# Перевірити логи запущеного Jobk logs job/$(k get jobs -o jsonpath='{.items[0].metadata.name}')
# Очищенняk delete cronjob every-minuteВправа 3: Job з повторними спробами (Ціль: 3 хвилини)
Розділ «Вправа 3: Job з повторними спробами (Ціль: 3 хвилини)»# Створити Job, що зазнає невдачі та повторює спробиcat << 'EOF' | k apply -f -apiVersion: batch/v1kind: Jobmetadata: name: retry-jobspec: backoffLimit: 3 template: spec: containers: - name: fail image: busybox command: ["sh", "-c", "echo 'Trying...' && exit 1"] restartPolicy: NeverEOF
# Спостерігати за повторними спробамиk get pods -l job-name=retry-job -w
# Перевірити статус Jobk describe job retry-job | grep -A5 Conditions
# Очищенняk delete job retry-jobВправа 4: Паралельний Job (Ціль: 4 хвилини)
Розділ «Вправа 4: Паралельний Job (Ціль: 4 хвилини)»# Створити паралельний Jobcat << 'EOF' | k apply -f -apiVersion: batch/v1kind: Jobmetadata: name: parallelspec: completions: 5 parallelism: 2 template: spec: containers: - name: worker image: busybox command: ["sh", "-c", "echo Worker done && sleep 2"] restartPolicy: NeverEOF
# Спостерігати за паралельним виконаннямk get pods -l job-name=parallel -w
# Перевірити, що все завершеноk get job parallel
# Очищенняk delete job parallelВправа 5: CronJob з конкурентністю (Ціль: 3 хвилини)
Розділ «Вправа 5: CronJob з конкурентністю (Ціль: 3 хвилини)»# Створити CronJob, що забороняє перекриттяcat << 'EOF' | k apply -f -apiVersion: batch/v1kind: CronJobmetadata: name: no-overlapspec: schedule: "* * * * *" concurrencyPolicy: Forbid jobTemplate: spec: template: spec: containers: - name: worker image: busybox command: ["sh", "-c", "echo 'Start' && sleep 90 && echo 'Done'"] restartPolicy: NeverEOF
# Перевірити політикуk get cronjob no-overlap -o jsonpath='{.spec.concurrencyPolicy}'
# Зачекати 2 хвилини та переконатися, що працює лише 1 Jobsleep 120k get jobs -l job-name=no-overlap
# Очищенняk delete cronjob no-overlapВправа 6: Повне рішення для резервного копіювання (Ціль: 8 хвилин)
Розділ «Вправа 6: Повне рішення для резервного копіювання (Ціль: 8 хвилин)»Побудуйте повну систему резервного копіювання:
# 1. Створити ConfigMap зі скриптом резервного копіюванняk create configmap backup-script --from-literal=script.sh='#!/bin/shecho "Starting backup at $(date)"echo "Compressing data..."sleep 3echo "Uploading to storage..."sleep 2echo "Backup complete at $(date)"'
# 2. Створити CronJob, що використовує скриптcat << 'EOF' | k apply -f -apiVersion: batch/v1kind: CronJobmetadata: name: backup-systemspec: schedule: "*/5 * * * *" concurrencyPolicy: Forbid successfulJobsHistoryLimit: 3 failedJobsHistoryLimit: 1 jobTemplate: spec: ttlSecondsAfterFinished: 300 template: spec: containers: - name: backup image: busybox command: ["sh", "/scripts/script.sh"] volumeMounts: - name: scripts mountPath: /scripts restartPolicy: OnFailure volumes: - name: scripts configMap: name: backup-scriptEOF
# 3. Тест з ручним запускомk create job test-backup --from=cronjob/backup-system
# 4. Перевірити логиk logs job/test-backup
# 5. Перевірити ліміти історіїk get cronjob backup-system -o jsonpath='{.spec.successfulJobsHistoryLimit}'
# Очищенняk delete cronjob backup-systemk delete job test-backupk delete configmap backup-scriptНаступний модуль
Розділ «Наступний модуль»Модуль 1.3: Під з кількома контейнерами — Паттерни sidecar, init та ambassador.