Це багатосторінковий друкований вигляд цього розділу. Натисність щоб друкувати.
Запуск Job
- 1: Виконання автоматизованих завдань за допомогою CronJob
- 2: Груба паралельна обробка за допомогою черги роботи
- 3: Тонка паралельна обробка за допомогою черги роботи
- 4: Індексоване завдання (Job) для паралельної обробки з фіксованим призначенням роботи
- 5: Завдання (Job) з комунікацією Pod-Pod
- 6: Паралельна обробка з розширенням
- 7: Обробка повторюваних і неповторюваних помилок Pod за допомогою політики збоїв Pod
1 - Виконання автоматизованих завдань за допомогою CronJob
Ця сторінка показує, як виконувати автоматизовані завдання за допомогою обʼєкта Kubernetes CronJob.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Створення CronJob
Для роботи з CronJob потрібен файл конфігурації. Нижче подано маніфест для CronJob, який запускає просте демонстраційне завдання кожну хвилину:
apiVersion: batch/v1
kind: CronJob
metadata:
name: hello
spec:
schedule: "* * * * *"
jobTemplate:
spec:
template:
spec:
containers:
- name: hello
image: busybox:1.28
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- date; echo Hello from the Kubernetes cluster
restartPolicy: OnFailure
Запустіть приклад CronJob за допомогою цієї команди:
kubectl create -f https://k8s.io/examples/application/job/cronjob.yaml
Вивід буде подібний до цього:
cronjob.batch/hello created
Після створення CronJob отримайте його статус за допомогою цієї команди:
kubectl get cronjob hello
Вивід буде подібний до цього:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 <none> 10s
Як видно з результатів команди, CronJob ще не планував або не запускав жодних завдань. Спостерігайте (watch) за створенням завдання протягом хвилини:
kubectl get jobs --watch
Вивід буде подібний до цього:
NAME COMPLETIONS DURATION AGE
hello-4111706356 0/1 0s
hello-4111706356 0/1 0s 0s
hello-4111706356 1/1 5s 5s
Тепер ви бачите одне запущене завдання, заплановане cron job "hello". Ви можете припинити спостереження за завданням і переглянути cron job ще раз, щоб побачити, що він запланував завдання:
kubectl get cronjob hello
Вивід буде подібний до цього:
NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE
hello */1 * * * * False 0 50s 75s
Ви повинні побачити, що cron job hello
успішно запланував завдання в час, вказаний у LAST SCHEDULE
. Наразі немає активних завдань, що означає, що завдання завершилось або зазнало невдачі.
Тепер знайдіть Podʼи, які створило останнє заплановане завдання, та перегляньте стандартний вивід одного з них.
Примітка:
Назва завдання відрізняється від назви Pod.# Замініть "hello-4111706356" на назву завдання у вашій системі
pods=$(kubectl get pods --selector=job-name=hello-4111706356 --output=jsonpath={.items[*].metadata.name})
Покажіть лог Pod:
kubectl logs $pods
Вивід буде подібний до цього:
Fri Feb 22 11:02:09 UTC 2019
Hello from the Kubernetes cluster
Видалення CronJob
Коли вам більше не потрібно cron job, видаліть його за допомогою kubectl delete cronjob <cronjob name>
:
kubectl delete cronjob hello
Видалення cron job призводить до видалення всіх створених ним завдань і Podʼів і припинення створення додаткових завдань. Докладніше про видалення завдань читайте в збиранні сміття.
2 - Груба паралельна обробка за допомогою черги роботи
У цьому прикладі ви запустите Job Kubernetes з кількома паралельними робочими процесами.
У цьому прикладі, при створенні кожного Pod, він бере одиницю роботи з черги завдань, завершує її, видаляє її з черги та завершує роботу.
Ось огляд кроків у цьому прикладі:
- Запустіть службу черги повідомлень. У цьому прикладі ви використовуєте RabbitMQ, але ви можете використовувати іншу. На практиці ви налаштовували б службу черги повідомлень один раз і використовували б її для багатьох робочих завдань.
- Створіть чергу та заповніть її повідомленнями. Кожне повідомлення являє собою одне завдання для виконання. У цьому прикладі повідомлення — це ціле число, на якому ми будемо виконувати тривалі обчислення.
- Запустіть Job, що працює над завданнями з черги. Job створює декілька Podʼів. Кожен Pod бере одне завдання з черги повідомлень, обробляє його та завершує роботу.
Перш ніж ви розпочнете
Ви вже маєте бути знайомі з основним, не-паралельним використанням Job.
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Вам знадобиться реєстр образів контейнерів, куди ви можете завантажувати образи для запуску у своєму кластері.
Цей приклад завдання також передбачає, що у вас вже встановлений Docker локально.
Запуск служби черги повідомлень
У цьому прикладі використовується RabbitMQ, проте ви можете адаптувати приклад для використання іншої служби повідомлень типу AMQP.
На практиці ви можете налаштувати службу черги повідомлень один раз у кластері та використовувати її для багатьох завдань, а також для служб з тривалим виконанням.
Запустіть RabbitMQ таким чином:
# Створіть Service для використання StatefulSet
kubectl create -f https://kubernetes.io/examples/application/job/rabbitmq/rabbitmq-service.yaml
service "rabbitmq-service" created
kubectl create -f https://kubernetes.io/examples/application/job/rabbitmq/rabbitmq-statefulset.yaml
statefulset "rabbitmq" created
Тестування служби черги повідомлень
Тепер ми можемо спробувати доступ до черги повідомлень. Ми створимо тимчасовий інтерактивний Pod, встановимо деякі інструменти на ньому, і спробуємо працювати з чергами.
Спочатку створіть тимчасовий інтерактивний Pod.
# Створіть тимчасовий інтерактивний контейнер
kubectl run -i --tty temp --image ubuntu:22.04
Waiting for pod default/temp-loe07 to be running, status is Pending, pod ready: false
... [ previous line repeats several times .. hit return when it stops ] ...
Зверніть увагу, що ваше імʼя Pod та запрошення командного рядка будуть відрізнятися.
Далі встановіть amqp-tools
, щоб працювати з чергами повідомлень. Наступні команди показують, що вам потрібно запустити в середовищі інтерактивної оболонки у цьому Pod:
apt-get update && apt-get install -y curl ca-certificates amqp-tools python3 dnsutils
Пізніше ви створите образ контейнера, який включає ці пакети.
Далі перевірте, що ви можете виявити Service для RabbitMQ:
# Виконайте ці команди всередині Pod
# Зауважте, що для служби rabbitmq-service існує DNS-ім\я, яке надається Kubernetes:
nslookup rabbitmq-service
Server: 10.0.0.10
Address: 10.0.0.10#53
Name: rabbitmq-service.default.svc.cluster.local
Address: 10.0.147.152
(адреси IP будуть відрізнятися)
Якщо надбудова kube-dns не налаштована правильно, попередній крок може не працювати для вас. Ви також можете знайти IP-адресу для цього Service у змінній середовища:
# виконайте цю перевірку всередині Pod
env | grep RABBITMQ_SERVICE | grep HOST
RABBITMQ_SERVICE_SERVICE_HOST=10.0.147.152
(IP-адреса буде відрізнятися)
Далі перевірте, що ви можете створити чергу, і публікувати та отримувати повідомлення.
# Виконайте ці команди всередині Pod
# У наступному рядку rabbitmq-service - це імʼя хоста, за яким можна звертатися до rabbitmq-service.
# 5672 - це стандартний порт для rabbitmq.
export BROKER_URL=amqp://guest:guest@rabbitmq-service:5672
# Якщо ви не могли отримати доступ до "rabbitmq-service" на попередньому кроці,
# використовуйте цю команду натомість:
BROKER_URL=amqp://guest:guest@$RABBITMQ_SERVICE_SERVICE_HOST:5672
# Тепер створіть чергу:
/usr/bin/amqp-declare-queue --url=$BROKER_URL -q foo -d
foo
Опублікуйте одне повідомлення в черзі:
/usr/bin/amqp-publish --url=$BROKER_URL -r foo -p -b Hello
# І отримайте його назад.
/usr/bin/amqp-consume --url=$BROKER_URL -q foo -c 1 cat && echo 1>&2
Hello
У останній команді інструмент amqp-consume
взяв одне повідомлення (-c 1
) з черги, і передав це повідомлення на стандартний ввід довільної команди. У цьому випадку програма cat
виводить символи, зчитані зі стандартного вводу, а echo додає символ нового рядка, щоб приклад був читабельним.
Заповнення черги завданнями
Тепер заповніть чергу деякими симульованими завданнями. У цьому прикладі завдання — це рядки, які потрібно надрукувати.
На практиці вміст повідомлень може бути таким:
- назви файлів, які потрібно обробити
- додаткові прапорці для програми
- діапазони ключів у таблиці бази даних
- параметри конфігурації для симуляції
- номери кадрів сцени для рендерингу
Якщо є великі дані, які потрібно лише для читання всіма Podʼами Job, зазвичай це розміщують на спільній файловій системі, наприклад NFS, і монтується це на всі Podʼи тільки для читання, або напишіть програму в Pod так, щоб вона могла нативно читати дані з кластерної файлової системи (наприклад: HDFS).
У цьому прикладі ви створите чергу та заповните її, використовуючи інструменти командного рядка AMQP. На практиці ви можете написати програму для заповнення черги, використовуючи бібліотеку клієнтів AMQP.
# Виконайте це на вашому компʼютері, а не в Pod
/usr/bin/amqp-declare-queue --url=$BROKER_URL -q job1 -d
job1
Додайте елементи до черги:
for f in apple banana cherry date fig grape lemon melon
do
/usr/bin/amqp-publish --url=$BROKER_URL -r job1 -p -b $f
done
Ви додали 8 повідомлень у чергу.
Створення образу контейнера
Тепер ви готові створити образ, який ви будете запускати як Job.
Job буде використовувати утиліту amqp-consume
для читання повідомлення з черги та виконання реальної роботи. Ось дуже простий приклад програми:
#!/usr/bin/env python
# Просто виводить стандартний вивід і очікує протягом 10 секунд.
import sys
import time
print("Processing " + sys.stdin.readlines()[0])
time.sleep(10)
Дайте скрипту дозвіл на виконання:
chmod +x worker.py
Тепер створіть образ. Створіть тимчасову теку, перейдіть в неї, завантажте Dockerfile, і worker.py. У будь-якому випадку, створіть образ за допомогою цієї команди:
docker build -t job-wq-1 .
Для Docker Hub позначте ваш образ застосунка вашим імʼям користувача і завантажте його на Hub за допомогою таких команд. Замініть <username>
на ваше імʼя користувача Hub.
docker tag job-wq-1 <username>/job-wq-1
docker push <username>/job-wq-1
Якщо ви використовуєте альтернативний реєстр образів контейнерів, позначте образ і завантажте його туди замість цього.
Визначення Job
Ось маніфест для Job. Вам потрібно зробити копію маніфеста Job (назвіть його ./job.yaml
), і змініть імʼя образу контейнера, щоб відповідало імені, яке ви використовували.
apiVersion: batch/v1
kind: Job
metadata:
name: job-wq-1
spec:
completions: 8
parallelism: 2
template:
metadata:
name: job-wq-1
spec:
containers:
- name: c
image: gcr.io/<project>/job-wq-1
env:
- name: BROKER_URL
value: amqp://guest:guest@rabbitmq-service:5672
- name: QUEUE
value: job1
restartPolicy: OnFailure
У цьому прикладі кожен Pod працює над одним елементом з черги, а потім виходить. Таким чином, кількість завершень завдання відповідає кількості виконаних робочих елементів. Тому у прикладі маніфесту .spec.completions
встановлено на 8
.
Запуск Job
Тепер запустіть завдання:
# це передбачає, що ви вже завантажили та відредагували маніфест
kubectl apply -f ./job.yaml
Ви можете зачекати, доки завдання успішно виконається, використовуючи тайм-аут:
# Перевірка для умови що імена нечутливі до регістру
kubectl wait --for=condition=complete --timeout=300s job/job-wq-1
Далі перевірте стан завдання:
kubectl describe jobs/job-wq-1
Name: job-wq-1
Namespace: default
Selector: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
job-name=job-wq-1
Annotations: <none>
Parallelism: 2
Completions: 8
Start Time: Wed, 06 Sep 2022 16:42:02 +0000
Pods Statuses: 0 Running / 8 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=41d75705-92df-11e7-b85e-fa163ee3c11f
job-name=job-wq-1
Containers:
c:
Image: container-registry.example/causal-jigsaw-637/job-wq-1
Port:
Environment:
BROKER_URL: amqp://guest:guest@rabbitmq-service:5672
QUEUE: job1
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
───────── ──────── ───── ──── ───────────── ────── ────── ───────
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-hcobb
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-weytj
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-qaam5
27s 27s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-b67sr
26s 26s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-xe5hj
15s 15s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-w2zqe
14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-d6ppa
14s 14s 1 {job } Normal SuccessfulCreate Created pod: job-wq-1-p17e0
Усі Podʼи для цього завдання успішно виконалися! У вас вийшло.
Альтернативи
Цей підхід має перевагу у тому, що вам не потрібно змінювати вашу "робочу" програму, щоб вона була обізнана, що є черга роботи. Ви можете включити незмінену робочу програму у свій контейнерний образ.
Використання цього підходу передбачає запуск сервісу черги повідомлень. Якщо запуск сервісу черги є не зручним, ви можете розглянути один з інших шаблонів завдань.
Цей підхід створює Pod для кожного робочого елемента. Якщо ваші робочі елементи займають лише декілька секунд, створення Podʼа для кожного робочого елемента може додати багато накладних витрат. Розгляньте інший дизайн, наприклад, у прикладі тонкої паралельної черги робочих елементів, що виконує кілька робочих елементів на кожному Pod.
У цьому прикладі ви використовували утиліту amqp-consume
для читання повідомлення з черги та запуску реальної програми. Це має перевагу у тому, що вам не потрібно модифікувати свою програму, щоб вона була обізнана про існування черги. У прикладі тонкої паралельної черги робочих елементів показано, як спілкуватися з чергою робочих елементів за допомогою клієнтської бібліотеки.
Обмеження
Якщо кількість завершень встановлена меншою, ніж кількість елементів у черзі, то не всі елементи будуть оброблені.
Якщо кількість завершень встановлена більшою, ніж кількість елементів у черзі, то завдання не буде здаватися завершеним, навіть якщо всі елементи у черзі були оброблені. Воно буде запускати додаткові Podʼи, які будуть блокуватися, чекаючи на повідомлення. Вам потрібно буде створити свій власний механізм для виявлення наявності роботи для виконання і вимірювати розмір черги, встановлюючи кількість завершень відповідно.
Існують малоймовірні перегони для цього патерну. Якщо контейнер був завершений між часом, коли повідомлення було підтверджено командою amqp-consume
, і часом, коли контейнер вийшов з успішним завершенням, або якщо вузол зазнає збою, перш ніж kubelet зможе розмістити успіх Podʼа назад до сервера API, то завдання не буде здаватися завершеним, навіть якщо всі елементи
у черзі були оброблені.
3 - Тонка паралельна обробка за допомогою черги роботи
In цьому прикладі ви запустите Job Kubernetes, яке виконує декілька паралельних завдань як робочі процеси, кожен з яких працює як окремий Pod.
У цьому прикладі, при створенні кожного Podʼа, він бере одиницю роботи з черги завдань, обробляє її та повторює цей процес до досягнення кінця черги.
Ось загальний огляд кроків у цьому прикладі:
- Запустіть службу зберігання, щоб зберігати чергу завдань. У цьому прикладі ви використаєте Redis для зберігання робочих елементів. У попередньому прикладі, ви використали RabbitMQ. У цьому прикладі ви будете використовувати Redis та власну бібліотеку клієнтів черг завдань; це тому, що AMQP не надає зручний спосіб клієнтам виявити, коли скінчиться черга робочих елементів з обмеженою довжиною. На практиці ви налаштуєте сховище, таке як Redis, один раз і повторно використовуватимете його для черг робочих завдань багатьох завдань та іншого.
- Створіть чергу та заповніть її повідомленнями. Кожне повідомлення представляє одне завдання, яке потрібно виконати. У цьому прикладі повідомленням є ціле число, над яким ми виконаємо тривалі обчислення.
- Запустіть завдання, яке працює над завданнями з черги. Завдання запускає декілька Podʼів. Кожний Pod бере одне завдання з черги повідомлень, обробляє його та повторює цей процес до досягнення кінця черги.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Вам знадобиться реєстр контейнерних образів, де ви можете завантажувати образи для запуску у вашому кластері. У прикладі використовується Docker Hub, але ви можете адаптувати його до іншого реєстру контейнерних образів.
Цей приклад передбачає, що у вас встановлено Docker локально. Ви будете використовувати Docker для створення контейнерних образів.
Ви маєти бути знайомі з базовим, не-паралельним використанням Job.
Запуск Redis
У цьому прикладі, для спрощення, ви запустите один екземпляр Redis. Дивіться Приклад Redis для прикладу розгортання Redis масштабовано та надійно.
Ви також можете завантажити наступні файли безпосередньо:
Для запуску одного екземпляра Redis вам потрібно створити Pod Redis та Service Redis:
kubectl apply -f https://k8s.io/examples/application/job/redis/redis-pod.yaml
kubectl apply -f https://k8s.io/examples/application/job/redis/redis-service.yaml
Заповнення черги завданнями
Тепер заповнімо чергу деякими "задачами". У цьому прикладі завданнями є рядки, які потрібно вивести.
Запустіть тимчасовий інтерактивний Pod для використання Redis CLI.
kubectl run -i --tty temp --image redis --command "/bin/sh"
Waiting for pod default/redis2-c7h78 to be running, status is Pending, pod ready: false
Hit enter for command prompt
Тепер натисніть Enter, запустіть Redis CLI та створіть список з деякими елементами роботи в ньому.
redis-cli -h redis
redis:6379> rpush job2 "apple"
(integer) 1
redis:6379> rpush job2 "banana"
(integer) 2
redis:6379> rpush job2 "cherry"
(integer) 3
redis:6379> rpush job2 "date"
(integer) 4
redis:6379> rpush job2 "fig"
(integer) 5
redis:6379> rpush job2 "grape"
(integer) 6
redis:6379> rpush job2 "lemon"
(integer) 7
redis:6379> rpush job2 "melon"
(integer) 8
redis:6379> rpush job2 "orange"
(integer) 9
redis:6379> lrange job2 0 -1
1) "apple"
2) "banana"
3) "cherry"
4) "date"
5) "fig"
6) "grape"
7) "lemon"
8) "melon"
9) "orange"
Отже, список з ключем job2
буде чергою роботи.
Примітка: якщо у вас неправильно налаштовано Kube DNS, вам може знадобитися змінити перший крок вищезазначеного блоку на redis-cli -h $REDIS_SERVICE_HOST
.
Створення образу контейнера
Тепер ви готові створити образ, який буде обробляти завдання в цій черзі.
Ви будете використовувати робочу програму на Python з клієнтом Redis для читання повідомлень з черги повідомлень.
Надається проста бібліотека клієнтів черги роботи Redis, яка називається rediswq.py
(Завантажити).
Програма "робітник" в кожному Pod Job використовує бібліотеку клієнтів черги роботи, щоб отримати роботу. Ось вона:
#!/usr/bin/env python
import time
import rediswq
host="redis"
# Якщо у вас немає працюючого Kube-DNS, розкоментуйте наступні два рядки.
# import os
# host = os.getenv("REDIS_SERVICE_HOST")
q = rediswq.RedisWQ(name="job2", host=host)
print("Worker with sessionID: " + q.sessionID())
print("Initial queue state: empty=" + str(q.empty()))
while not q.empty():
item = q.lease(lease_secs=10, block=True, timeout=2)
if item is not None:
itemstr = item.decode("utf-8")
print("Working on " + itemstr)
time.sleep(10) # Put your actual work here instead of sleep.
q.complete(item)
else:
print("Waiting for work")
print("Queue empty, exiting")
Ви також можете завантажити файли worker.py
, rediswq.py
та Dockerfile
, а потім побудувати контейнерний образ. Ось приклад використання Docker для побудови образу:
docker build -t job-wq-2 .
Збереження образу в реєстрі
Для Docker Hub, позначте свій образ програми імʼям користувача та завантажте його до Hub за допомогою наступних команд. Замість <username>
вкажіть своє імʼя користувача Hub.
docker tag job-wq-2 <username>/job-wq-2
docker push <username>/job-wq-2
Вам потрібно завантажити в публічний репозиторій або налаштувати кластер для доступу до вашого приватного репозиторію.
Визначення завдання
Ось маніфест для створення Job:
apiVersion: batch/v1
kind: Job
metadata:
name: job-wq-2
spec:
parallelism: 2
template:
metadata:
name: job-wq-2
spec:
containers:
- name: c
image: gcr.io/myproject/job-wq-2
restartPolicy: OnFailure
Примітка:
Не забудьте відредагувати маніфест, змінившиgcr.io/myproject
на свій власний шлях.У цьому прикладі кожний Pod працює з кількома елементами черги, а потім виходить, коли елементи закінчуються. Оскільки самі робочі процеси виявляють порожнечу робочої черги, а контролер завдань не володіє інформацією про робочу чергу, він покладається на робочі процеси, щоб сигналізувати, коли вони закінчили роботу. Робочі процеси сигналізують, що черга порожня, вийшовши з успіхом. Таким чином, як тільки будь-який робочий процес виходить з успіхом, контролер знає, що робота виконана, і що Podʼи скоро вийдуть. Тому вам потрібно залишити лічильник завершення завдання невизначеним. Контролер завдань зачекає, доки інші Podʼи завершаться також.
Запуск завдання
Отже, зараз запустіть завдання:
# передбачається, що ви вже завантажили та відредагували маніфест
kubectl apply -f ./job.yaml
Тепер зачекайте трохи, а потім перевірте стан завдання:
kubectl describe jobs/job-wq-2
Name: job-wq-2
Namespace: default
Selector: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
job-name=job-wq-2
Annotations: <none>
Parallelism: 2
Completions: <unset>
Start Time: Mon, 11 Jan 2022 17:07:59 +0000
Pods Statuses: 1 Running / 0 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=b1c7e4e3-92e1-11e7-b85e-fa163ee3c11f
job-name=job-wq-2
Containers:
c:
Image: container-registry.example/exampleproject/job-wq-2
Port:
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
FirstSeen LastSeen Count From SubobjectPath Type Reason Message
--------- -------- ----- ---- ------------- -------- ------ -------
33s 33s 1 {job-controller } Normal SuccessfulCreate Created pod: job-wq-2-lglf8
Ви можете зачекати, поки завдання завершиться успішно, з тайм-аутом:
# Перевірка умови назви нечутлива до регістру
kubectl wait --for=condition=complete --timeout=300s job/job-wq-2
kubectl logs pods/job-wq-2-7r7b2
Worker with sessionID: bbd72d0a-9e5c-4dd6-abf6-416cc267991f
Initial queue state: empty=False
Working on banana
Working on date
Working on lemon
Як бачите, один з Podʼів для цього завдання працював над кількома робочими одиницями.
Альтернативи
Якщо запуск служби черги або модифікація ваших контейнерів для використання робочої черги є незручними, ви можете розглянути один з інших шаблонів завдань.
Якщо у вас є постійний потік фонової обробки, яку потрібно виконувати, то розгляньте запуск ваших фонових робітників за допомогою ReplicaSet, і розгляньте використання бібліотеки фонової обробки, такої як https://github.com/resque/resque.
4 - Індексоване завдання (Job) для паралельної обробки з фіксованим призначенням роботи
Kubernetes v1.24 [stable]
У цьому прикладі ви запустите Job Kubernetes, яке використовує кілька паралельних робочих процесів. Кожен робочий процес — це різний контейнер, що працює у власному Podʼі. Podʼи мають індексний номер, який автоматично встановлює панель управління, що дозволяє кожному Podʼу визначити, над якою частиною загального завдання працювати.
Індекс Podʼа доступний в анотації batch.kubernetes.io/job-completion-index
у вигляді рядка, який представляє його десяткове значення. Щоб контейнеризований процес завдання отримав цей індекс, можна опублікувати значення анотації за допомогою механізму downward API. Для зручності панель управління автоматично встановлює downward API для експонування індексу в змінну середовища JOB_COMPLETION_INDEX
.
Нижче наведено огляд кроків у цьому прикладі:
- Визначте маніфест завдання з використанням індексованого завершення. Downward API дозволяє передавати індекс Podʼа як змінну середовища або файл до контейнера.
- Запустіть
Indexed
завдання на основі цього маніфесту.
Перш ніж ви розпочнете
Ви маєти бути знайомі з базовим, не-паралельним використанням Job.
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Версія вашого Kubernetes сервера має бути не старішою ніж v1.21. Для перевірки версії введітьkubectl version
.Оберіть підхід
Щоб отримати доступ до робочого елемента з програми робочого процесу, у вас є кілька варіантів:
- Прочитайте змінну середовища
JOB_COMPLETION_INDEX
. Job контролер автоматично повʼязує цю змінну з анотацією, що містить індекс завершення. - Прочитайте файл, який містить індекс завершення.
- Припускаючи, що ви не можете змінити програму, ви можете обгорнути її сценарієм, який читає індекс за допомогою будь-якого з методів вище і перетворює його в щось, що програма може використовувати як вхід.
У цьому прикладі уявіть, що ви вибрали третій варіант, і ви хочете запустити rev утиліту. Ця програма приймає файл як аргумент і виводить зміст у зворотньому порядку.
rev data.txt
Ви будете використовувати інструмент rev
з контейнерного образу busybox
.
Оскільки це лише приклад, кожен Pod робить лише невеликий шматок роботи (реверсування короткого рядка). У реальному навантаженні ви, наприклад, можете створити Job, що представляє задачу рендерингу 60 секунд відео на основі даних про сцену. Кожен робочий елемент в завданні відеорендерингу буде створювати певний кадр цього відеокліпу. Індексоване завершення означатиме, що кожен Pod у Job знає, який кадр рендерити та опублікувати, рахуючи кадри від початку кліпу.
Визначте Indexed Job
Ось приклад маніфесту Job, який використовує режим завершення Indexed
:
apiVersion: batch/v1
kind: Job
metadata:
name: 'indexed-job'
spec:
completions: 5
parallelism: 3
completionMode: Indexed
template:
spec:
restartPolicy: Never
initContainers:
- name: 'input'
image: 'docker.io/library/bash'
command:
- "bash"
- "-c"
- |
items=(foo bar baz qux xyz)
echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt
volumeMounts:
- mountPath: /input
name: input
containers:
- name: 'worker'
image: 'docker.io/library/busybox'
command:
- "rev"
- "/input/data.txt"
volumeMounts:
- mountPath: /input
name: input
volumes:
- name: input
emptyDir: {}
У вищенаведеному прикладі ви використовуєте вбудовану змінну середовища JOB_COMPLETION_INDEX
, яку встановлює контролер завдань для всіх контейнерів. Контейнер ініціалізації відображає індекс на статичне значення та записує його в файл, який спільно використовується з контейнером, що виконує робочий процес через том emptyDir. Додатково ви можете визначити свою власну змінну середовища через downward API для публікації індексу в контейнерах. Ви також можете вибрати завантаження списку значень з ConfigMap як змінної середовища або файлу.
У іншому варіанті ви можете безпосередньо використовувати downward API для передачі значення анотації як файлу тому, як показано у наступному прикладі:
apiVersion: batch/v1
kind: Job
metadata:
name: 'indexed-job'
spec:
completions: 5
parallelism: 3
completionMode: Indexed
template:
spec:
restartPolicy: Never
containers:
- name: 'worker'
image: 'docker.io/library/busybox'
command:
- "rev"
- "/input/data.txt"
volumeMounts:
- mountPath: /input
name: input
volumes:
- name: input
downwardAPI:
items:
- path: "data.txt"
fieldRef:
fieldPath: metadata.annotations['batch.kubernetes.io/job-completion-index']
Запуск Job
Тепер запустіть Job:
# Це використовує перший підхід (покладаючись на $JOB_COMPLETION_INDEX)
kubectl apply -f https://kubernetes.io/examples/application/job/indexed-job.yaml
При створенні цього Завдання панель управління створює серію Podʼів, по одному для кожного вказаного індексу. Значення .spec.parallelism
визначає, скільки може працювати одночасно, в той час, як .spec.completions
визначає, скільки Podʼів створює Job в цілому.
Оскільки .spec.parallelism
менше, ніж .spec.completions
, панель управління чекає, поки деякі з перших Podʼів завершаться, перш ніж запустити ще.
Ви можете зачекати, поки Завдання завершиться успішно, з тайм-аутом:
# Перевірка умови назви нечутлива до регістру
kubectl wait --for=condition=complete --timeout=300s job/indexed-job
Тепер опишіть Завдання та переконайтеся, що воно виконалося успішно.
kubectl describe jobs/indexed-job
Вивід схожий на:
Name: indexed-job
Namespace: default
Selector: controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
Labels: controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
job-name=indexed-job
Annotations: <none>
Parallelism: 3
Completions: 5
Start Time: Thu, 11 Mar 2021 15:47:34 +0000
Pods Statuses: 2 Running / 3 Succeeded / 0 Failed
Completed Indexes: 0-2
Pod Template:
Labels: controller-uid=bf865e04-0b67-483b-9a90-74cfc4c3e756
job-name=indexed-job
Init Containers:
input:
Image: docker.io/library/bash
Port: <none>
Host Port: <none>
Command:
bash
-c
items=(foo bar baz qux xyz)
echo ${items[$JOB_COMPLETION_INDEX]} > /input/data.txt
Environment: <none>
Mounts:
/input from input (rw)
Containers:
worker:
Image: docker.io/library/busybox
Port: <none>
Host Port: <none>
Command:
rev
/input/data.txt
Environment: <none>
Mounts:
/input from input (rw)
Volumes:
input:
Type: EmptyDir (тимчасова тека, яка поділяє життя Podʼа)
Medium:
SizeLimit: <unset>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 4s job-controller Created pod: indexed-job-njkjj
Normal SuccessfulCreate 4s job-controller Created pod: indexed-job-9kd4h
Normal SuccessfulCreate 4s job-controller Created pod: indexed-job-qjwsz
Normal SuccessfulCreate 1s job-controller Created pod: indexed-job-fdhq5
Normal SuccessfulCreate 1s job-controller Created pod: indexed-job-ncslj
У цьому прикладі ви запускаєте Job з власними значеннями для кожного індексу. Ви можете оглянути вивід одного з Podʼів:
kubectl logs indexed-job-fdhq5 # Змініть це, щоб відповідати імені Podʼа з цього Завдання ```
Вивід схожий на:
xuq
5 - Завдання (Job) з комунікацією Pod-Pod
У цьому прикладі ви запустите Job в Indexed completion mode, налаштований таким чином, щоб Podʼи, створені Job, могли комунікувати один з одним, використовуючи назви хостів Podʼів, а не IP-адреси Podʼів.
Podʼи в межах Job можуть потребувати комунікації між собою. Робоче навантаження користувача, що виконується в кожному Podʼі, може звертатися до сервера API Kubernetes для отримання IP-адрес інших Podʼів, але набагато простіше покладатися на вбудований DNS-резолвер Kubernetes.
Job в Indexed completion mode автоматично встановлюють назви хостів Podʼів у форматі
${jobName}-${completionIndex}
. Ви можете використовувати цей формат для детермінованого створення назв хостів Podʼів та забезпечення комунікації між Podʼами без необхідності створювати клієнтське з’єднання з панеллю управління Kubernetes для отримання назв хостів/IP-адрес Podʼів через API-запити.
Ця конфігурація корисна для випадків, коли необхідна мережева взаємодія Podʼів, але ви не хочете залежати від мережевого з’єднання з сервером API Kubernetes.
Перш ніж ви розпочнете
Ви повинні вже бути знайомі з основами використання Job.
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Версія вашого Kubernetes сервера має бути не старішою ніж v1.21. Для перевірки версії введітьkubectl version
.Примітка:
Якщо ви використовуєте MiniKube або подібний інструмент, можливо, вам потрібно буде вжити додаткових заходів, щоб переконатись, що ви використовуєте DNS.Запуск роботи з комунікацією між Podʼами
Щоб увімкнути комунікацію між Podʼами з використанням назв хостів Podʼів у Job, ви повинні зробити наступне:
Налаштуйте headless Service з дійсним селектором міток для Podʼів, створених вашим Job. Headless Service має бути в тому ж просторі імен, що й Job. Один із простих способів зробити це — використати селектор
job-name: <your-job-name>
, оскільки міткаjob-name
буде додана Kubernetes автоматично. Ця конфігурація активує систему DNS для створення записів назв хостів Podʼів, що виконують ваш обʼєкт Job.Налаштуйте headless Service як піддомен для Podʼів Job, включивши наступне значення у ваш шаблон специфікації Job:
subdomain: <headless-svc-name>
Приклад
Нижче наведено робочий приклад Job з увімкненою комунікацією між Podʼами через назви хостів Podʼів. Job завершується лише після того, як усі Podʼи успішно пінгують один одного за допомогою назв хостів.
Примітка:
У Bash-скрипті, що виконується на кожному Podʼі у прикладі нижче, назви хостів Podʼів можуть мати префікс простору імен, якщо Pod повинен бути доступний ззовні простору імен.
apiVersion: v1
kind: Service
metadata:
name: headless-svc
spec:
clusterIP: None # clusterIP має бути None для створення headless service
selector:
job-name: example-job # має відповідати імені Job
---
apiVersion: batch/v1
kind: Job
metadata:
name: example-job
spec:
completions: 3
parallelism: 3
completionMode: Indexed
template:
spec:
subdomain: headless-svc # має відповідати імені Service
restartPolicy: Never
containers:
- name: example-workload
image: bash:latest
command:
- bash
- -c
- |
for i in 0 1 2
do
gotStatus="-1"
wantStatus="0"
while [ $gotStatus -ne $wantStatus ]
do
ping -c 1 example-job-${i}.headless-svc > /dev/null 2>&1
gotStatus=$?
if [ $gotStatus -ne $wantStatus ]; then
echo "Failed to ping pod example-job-${i}.headless-svc, retrying in 1 second..."
sleep 1
fi
done
echo "Successfully pinged pod: example-job-${i}.headless-svc"
done
Після застосування наведеного вище прикладу, Podʼи зможуть звертатись один до одного в мережі, використовуючи: <pod-hostname>.<headless-service-name>
. Ви повинні побачити вихідні дані, подібні до наступних:
kubectl logs example-job-0-qws42
Failed to ping pod example-job-0.headless-svc, retrying in 1 second...
Successfully pinged pod: example-job-0.headless-svc
Successfully pinged pod: example-job-1.headless-svc
Successfully pinged pod: example-job-2.headless-svc
Примітка:
Майте на увазі, що формат імені<pod-hostname>.<headless-service-name>
, використаний у цьому прикладі, не працюватиме з політикою DNS, встановленою на None
або Default
. Ви можете дізнатися більше про політику DNS для Podʼів тут.6 - Паралельна обробка з розширенням
Це завдання демонструє запуск кількох Jobs на основі загального шаблону. Ви можете використовувати цей підхід для обробки пакетних завдань паралельно.
У цьому прикладі є лише три елементи: apple, banana та cherry. Приклади Job обробляють кожен елемент, виводячи рядок, а потім очікуючи дії користувача.
Див. використання Job у реальних навантаженнях, щоб дізнатися, як цей підхід вписується у більш реалістичні випадки використання.
Перш ніж ви розпочнете
Вам слід бути знайомим з базовим, не-паралельним використанням Job.
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Для базового шаблонування вам потрібна утиліта командного рядка sed
.
Для виконання розширеного прикладу шаблонування вам потрібен встановлений Python та бібліотека шаблонів Jinja2 для Python.
Після налаштування Python ви можете встановити Jinja2, виконавши:
pip install --user jinja2
Створення Job на основі шаблону
Спочатку завантажте наступний шаблон Job у файл з назвою job-tmpl.yaml
. Ось що ви завантажите:
apiVersion: batch/v1
kind: Job
metadata:
name: process-item-$ITEM
labels:
jobgroup: jobexample
spec:
template:
metadata:
name: jobexample
labels:
jobgroup: jobexample
spec:
containers:
- name: c
image: busybox:1.28
command: ["sh", "-c", "echo Processing item $ITEM && sleep 5"]
restartPolicy: Never
# Використайте curl для завантаження job-tmpl.yaml
curl -L -s -O https://k8s.io/examples/application/job/job-tmpl.yaml
Завантажений вами файл ще не є валідним маніфестом Kubernetes. Замість цього цей шаблон є YAML-представленням об’єкта Job з деякими заповнювачами, які потрібно замінити перед використанням. Синтаксис $ITEM
не має значення для Kubernetes.
Створення маніфестів з шаблону
Наступний код використовує sed
для заміни $ITEM
на значення змінної з циклу, зберігаючи результат в тимчасову теку jobs
:
# Розмноження шаблону на кілька файлів, по одному для коженого процесу
mkdir -p ./jobs
for item in apple banana cherry
do
cat job-tmpl.yaml | sed "s/\$ITEM/$i/g" > ./jobs/job-$i.yaml
done
На виході ви маєте отримати три файли:
job-apple.yaml
job-banana.yaml
job-cherry.yaml
Створення Завдань (Job) з маніфестів
Далі, створіть всі три Job, використовуючи файли, які ви створили:
kubectl apply -f ./jobs
Вивід буде подібний до цього:
job.batch/process-item-apple created
job.batch/process-item-banana created
job.batch/process-item-cherry created
Тепер ви можете перевірити стан Job:
kubectl get jobs -l jobgroup=jobexample
Вивід буде подібний до цього:
NAME COMPLETIONS DURATION AGE
process-item-apple 1/1 14s 22s
process-item-banana 1/1 12s 21s
process-item-cherry 1/1 12s 20s
Використання опції -l
для kubectl
вибирає лише Job, які є частиною цієї групи Job (в системі можуть бути інші не Завдання (Job)).
Ви також можете перевірити стан Podʼів, використовуючи той самий селектор міток:
kubectl get pods -l jobgroup=jobexample
Вивід буде подібний до цього:
NAME READY STATUS RESTARTS AGE
process-item-apple-kixwv 0/1 Completed 0 4m
process-item-banana-wrsf7 0/1 Completed 0 4m
process-item-cherry-dnfu9 0/1 Completed 0 4m
Ви можете використати цю одну команду для перевірки виводу всіх Job одночасно:
kubectl logs -f -l jobgroup=jobexample
Вивід має бути таким:
Processing item apple
Processing item banana
Processing item cherry
Очищення
# Видаліть створені Job
# Ваш кластер автомтично видаляє пов’язані з Job Pod
kubectl delete jobs -l jobgroup=jobexample
Використання розширених параметрів шаблонів
В першому прикладі, кожен екземпляр шаблону мав один параметр, цей параметр тако використовувався в назві Job. Однак, назви обмежені набором символів, які можна використовувати.
Ось трохи складніший шаблон Jinja, для створення маніфестів та обʼєктів на їх основі, з кількома параметрами для кожного Завдання (Job).
В першій частині завдання скористайтесь однорядковим скриптом Python для перетворення шаблонів в набір маніфестів.
Спочатку скопіюйте та вставте наступний шаблон обʼєкта Job у файл з назвою job.yaml.jinja2
:
{% set params = [{ "name": "apple", "url": "http://dbpedia.org/resource/Apple", },
{ "name": "banana", "url": "http://dbpedia.org/resource/Banana", },
{ "name": "cherry", "url": "http://dbpedia.org/resource/Cherry" }]
%}
{% for p in params %}
{% set name = p["name"] %}
{% set url = p["url"] %}
---
apiVersion: batch/v1
kind: Job
metadata:
name: jobexample-{{ name }}
labels:
jobgroup: jobexample
spec:
template:
metadata:
name: jobexample
labels:
jobgroup: jobexample
spec:
containers:
- name: c
image: busybox:1.28
command: ["sh", "-c", "echo Processing URL {{ url }} && sleep 5"]
restartPolicy: Never
{% endfor %}
Наведений шаблон визначає два параметри для кожного обʼєкта Job за допомогою списку словників Python (рядки 1-4). Цикл for
генерує один маніфест Job для кожного набору параметрів (інші рядки).
Цей приклад використовує можливості YAML. Один файл YAML може містити кілька документів (у цьому випадку маніфестів Kubernetes), розділених рядком ---
.
Ви можете передати вивід безпосередньо до kubectl
, щоб створити Jobs.
Далі використовуйте цю однорядковий скрипт Python для розширення шаблону:
alias render_template='python -c "from jinja2 import Template; import sys; print(Template(sys.stdin.read()).render());"'
Використовуйте render_template
для конвертації параметрів та шаблону в один файл YAML, що містить маніфести Kubernetes:
# Це вимагає визначеного раніше аліасу
cat job.yaml.jinja2 | render_template > jobs.yaml
Ви можете переглянути jobs.yaml
, щоб переконатися, що скрипт render_template
працює правильно.
Коли ви переконаєтесь, що render_template
працює так, як ви задумали, ви можете передати його вивід до kubectl
:
cat job.yaml.jinja2 | render_template | kubectl apply -f -
Kubernetes прийме та запустить створені вами Jobs.
Очищення
# Видалення створених вами Jobs
# Ваш кластер автоматично очищає їхні Pods
kubectl delete job -l jobgroup=jobexample
Використання Jobs у реальних робочих навантаженнях
У реальному випадку використання кожен Job виконує деяку суттєву обчислювальну задачу, наприклад, рендеринг кадру фільму або обробку діапазону рядків у базі даних. Якщо ви рендерите відео, ви будете встановлювати $ITEM
на номер кадру. Якщо ви обробляєте рядки з таблиці бази даних, ви будете встановлювати $ITEM
для представлення діапазону рядків бази даних, які потрібно обробити.
У завданні ви виконували команду для збирання виводу з Podʼів, отримуючи їхні логи. У реальному випадку використання кожен Pod для Job записує свій вивід у надійне сховище перед завершенням. Ви можете використовувати PersistentVolume для кожного Job або зовнішню службу зберігання даних. Наприклад, якщо ви рендерите кадри для відео, використовуйте HTTP PUT
щоб включити дані обробленого кадру до URL, використовуючи різні URL для кожного кадру.
Мітки на Job та Podʼах
Після створення Job, Kubernetes автоматично додає додаткові мітки, які вирізняють Podʼи одного Job від Podʼів іншого Job.
У цьому прикладі кожен Job та його шаблон Pod мають мітку: jobgroup=jobexample
.
Сам Kubernetes не звертає уваги на мітки з іменем jobgroup
. Встановлення мітки для всіх Job, які ви створюєте за шаблоном, робить зручним керування всіма цими Jobs одночасно. У першому прикладі ви використовували шаблон для створення кількох Job. Шаблон гарантує, що кожен Pod також отримує ту саму мітку, тому ви можете перевірити всі Podʼи для цих шаблонних Job за допомогою однієї команди.
Примітка:
Ключ міткиjobgroup
не є особливим чи зарезервованим. Ви можете обрати свою власну схему міток. Існують рекомендовані мітки, які ви можете використовувати, якщо бажаєте.Альтернативи
Якщо ви плануєте створити велику кількість обʼєктів Job, ви можете виявити, що:
- Навіть використовуючи мітки, керування такою кількістю Job є громіздким.
- Якщо ви створюєте багато Job одночасно, ви можете створити високе навантаження на панель управління Kubernetes. Крім того, сервер API Kubernetes може обмежити швидкість запитів, тимчасово відхиляючи ваші запити зі статусом 429.
- Ви обмежені квотою ресурсів на Job: сервер API постійно відхиляє деякі ваші запити, коли ви створюєте велику кількість роботи за один раз.
Існують інші шаблони роботи з Job, які ви можете використовувати для обробки значного обсягу роботи без створення великої кількості обʼєктів Job.
Ви також можете розглянути можливість написання власного контролера, щоб автоматично керувати обʼєктами Job.
7 - Обробка повторюваних і неповторюваних помилок Pod за допомогою політики збоїв Pod
Kubernetes v1.31 [stable]
(стандартно увімкнено: true)Цей документ показує, як використовувати політику збоїв Pod, у поєднанні з типовою політикою відмови Podʼа, для покращення контролю над обробкою збоїв на рівні контейнера або Pod у Job.
Визначення політики збоїв Pod може допомогти вам:
- краще використовувати обчислювальні ресурси, уникаючи непотрібних повторних запусків Pod.
- уникати збоїв Job через збої Pod (такі як випередження, виселення ініційоване API або виселення на основі taint).
Перш ніж ви розпочнете
Ви повинні вже бути знайомі з основним використанням Job.
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Версія вашого Kubernetes сервера має бути не старішою ніж v1.25. Для перевірки версії введітьkubectl version
.Використання політики збоїв Pod для уникнення непотрібних повторних запусків Pod
В наступному прикладі ви можете навчитися використовувати політику збоїв Pod, щоб уникати непотрібних перезапусків Pod, коли збій Pod вказує на неповторювану помилку програмного забезпечення.
Спочатку створіть Job на основі конфігурації:
apiVersion: batch/v1
kind: Job
metadata:
name: job-pod-failure-policy-failjob
spec:
completions: 8
parallelism: 2
template:
spec:
restartPolicy: Never
containers:
- name: main
image: docker.io/library/bash:5
command: ["bash"]
args:
- -c
- echo "Hello world! I'm going to exit with 42 to simulate a software bug." && sleep 30 && exit 42
backoffLimit: 6
podFailurePolicy:
rules:
- action: FailJob
onExitCodes:
containerName: main
operator: In
values: [42]
виконавши команду:
kubectl create -f job-pod-failure-policy-failjob.yaml
Через приблизно 30 секунд весь Job повинен завершитися. Перевірте статус Job, виконавши команду:
kubectl get jobs -l job-name=job-pod-failure-policy-failjob -o yaml
У статусі Job відображаються такі умови:
- Умова
FailureTarget
: має полеreason
, встановлене вPodFailurePolicy
, і полеmessage
з додатковою інформацією про завершення, наприклад,Container main for pod default/job-pod-failure-policy-failjob-8ckj8 failed with exit code 42 matching FailJob rule at index 0
. Контролер Job додає цю умову, як тільки Job вважається невдалим. Для отримання деталей дивіться Завершення Job Podʼів. - Умова
Failed
: те ж саме значення дляreason
іmessage
, що й в умовиFailureTarget
. Контролер Job додає цю умову після того, як усі Podʼи Job завершено.
Для порівняння, якщо політика збоїв Pod була вимкнена, це б зайняло 6 спроб повторного запуску Pod, на що треба щонайменше 2 хвилини.
Прибирання
Видаліть створений Job:
kubectl delete jobs/job-pod-failure-policy-failjob
Кластер автоматично очищає Pod.
Використання політики збоїв Pod для ігнорування розладів Pod
На наступному прикладі ви можете навчитися використовувати політику збоїв Pod, щоб ігнорувати розлади Pod, які збільшують лічильник повторних спроб Pod до межі .spec.backoffLimit
.
Увага:
Час має значення для цього прикладу, тому вам слід прочитати про кроки перед їх виконанням. Щоб викликати розлад Podʼа, важливо запустити очищення вузла, поки Pod працює на ньому (протягом 90 секунд після розміщення Pod).Створіть Job на основі конфігурації:
apiVersion: batch/v1 kind: Job metadata: name: job-pod-failure-policy-ignore spec: completions: 4 parallelism: 2 template: spec: restartPolicy: Never containers: - name: main image: docker.io/library/bash:5 command: ["bash"] args: - -c - echo "Hello world! I'm going to exit with 0 (success)." && sleep 90 && exit 0 backoffLimit: 0 podFailurePolicy: rules: - action: Ignore onPodConditions: - type: DisruptionTarget
виконавши команду:
kubectl create -f job-pod-failure-policy-ignore.yaml
Виконайте цю команду, щоб перевірити
nodeName
, на якому розміщено Pod:nodeName=$(kubectl get pods -l job-name=job-pod-failure-policy-ignore -o jsonpath='{.items[0].spec.nodeName}')
Запустить очищення вузла, щоб виселити Pod до завершення його роботи (протягом 90 секунд):
kubectl drain nodes/$nodeName --ignore-daemonsets --grace-period=0
Перевірте
.status.failed
, щоб переконатися, що лічильник для Job не збільшено:kubectl get jobs -l job-name=job-pod-failure-policy-ignore -o yaml
Зніміть блокування з вузла:
kubectl uncordon nodes/$nodeName
Job відновиться і завершиться успішно.
Для порівняння, якщо політика збоїв Pod була вимкнена, розлад Pod призведе до завершення всього Job (оскільки .spec.backoffLimit
встановлено на 0).
Прибирання
Видаліть створений Job:
kubectl delete jobs/job-pod-failure-policy-ignore
Кластер автоматично очищає Pod.
Використання політики збоїв Pod для уникнення непотрібних повторних запусків Pod на основі власних умов Pod
В наступному прикладі ви можете навчитися використовувати політику збоїв Pod, щоб уникати непотрібних перезапусків Pod на основі власних умов Pod.
Примітка:
Наведений нижче приклад працює з версії 1.27, оскільки він базується на переході видалених Pod з фазиPending
до термінальної фази (див. Фази Pod).Спочатку створіть Job на основі конфігурації:
apiVersion: batch/v1 kind: Job metadata: name: job-pod-failure-policy-config-issue spec: completions: 8 parallelism: 2 template: spec: restartPolicy: Never containers: - name: main image: "non-existing-repo/non-existing-image:example" backoffLimit: 6 podFailurePolicy: rules: - action: FailJob onPodConditions: - type: ConfigIssue
виконавши команду:
kubectl create -f job-pod-failure-policy-config-issue.yaml
Зверніть увагу, що образ налаштоване неправильно, оскільки його не існує.
Перевірте статус Pod Job, виконавши команду:
kubectl get pods -l job-name=job-pod-failure-policy-config-issue -o yaml
Ви побачите результат, подібний до цього:
containerStatuses: - image: non-existing-repo/non-existing-image:example ... state: waiting: message: Back-off pulling image "non-existing-repo/non-existing-image:example" reason: ImagePullBackOff ... phase: Pending
Зверніть увагу, що Pod залишається у фазі
Pending
, оскільки йому не вдається завантажити неправильно налаштований образ. Це, в принципі, може бути тимчасовою проблемою, і образ може бути завантажений. Однак у цьому випадку образу не існує, тому ми вказуємо на цей факт за допомогою власної умови.Додайте власну умову. Спочатку підготуйте патч, виконавши команду:
cat <<EOF > patch.yaml status: conditions: - type: ConfigIssue status: "True" reason: "NonExistingImage" lastTransitionTime: "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" EOF
По-друге, виберіть один із Pod, створених Job, виконавши команду:
podName=$(kubectl get pods -l job-name=job-pod-failure-policy-config-issue -o jsonpath='{.items[0].metadata.name}')
Потім застосуйте патч до одного з Pod, виконавши наступну команду:
kubectl patch pod $podName --subresource=status --patch-file=patch.yaml
Якщо патч успішно застосовано, ви отримаєте повідомлення такого типу:
pod/job-pod-failure-policy-config-issue-k6pvp patched
Видаліть Pod для переходу його до фази
Failed
, виконавши команду:kubectl delete pods/$podName
Перевірте статус Job, виконавши:
kubectl get jobs -l job-name=job-pod-failure-policy-config-issue -o yaml
У статусі Job перегляньте умову
Failed
з полемreason
, рівнимPodFailurePolicy
. Додатково, полеmessage
містить більш детальну інформацію про завершення завдання, таку як:Pod default/job-pod-failure-policy-config-issue-k6pvp має умову ConfigIssue, яка відповідає правилу FailJob за індексом 0
.
Примітка:
В операційному середовищі кроки 3 та 4 повинні бути автоматизовані контролером, наданим користувачем.Очищення
Видаліть створене вами завдання:
kubectl delete jobs/job-pod-failure-policy-config-issue
Кластер автоматично очищує поди.
Альтернативи
Ви можете покладатись виключно на політику відмови Pod backoff, вказавши поле .spec.backoffLimit
завдання. Однак у багатьох ситуаціях важко знайти баланс між встановленням низького значення для .spec.backoffLimit
для уникнення непотрібних повторних спроб виконання Podʼів, але достатньо великого, щоб забезпечити, що Job не буде припинено через втручання у роботу Podʼів.