Это многостраничный печатный вид этого раздела. Нажмите что бы печатать.

Вернуться к обычному просмотру страницы.

Ресурсы рабочей нагрузки

Kubernetes предоставляет несколько встроенных API для декларативного управления рабочими нагрузками и их компонентами.

В конечном счете, приложения работают в качестве контейнеров внутри подов, однако управление каждым подом по отдельности требует больших усилий. Например, если под выходит из строя, вам, вероятно, надо будет запустить новый под, чтобы заменить его. Kubernetes может сделать это за вас.

С помощью Kubernetes API можно создавать объект рабочей нагрузки на более высоком уровне абстракции, чем под, а затем уже слой управления Kubernetes будет автоматически управлять подами, руководствуясь спецификацией этого объекта.

Встроенные API для управления рабочими нагрузками:

Деплоймент (Deployment) (и, косвенно, ReplicaSet) — это наиболее распространенный способ запуска приложения в кластере. Deployment хорошо подходит для управления неизменной (stateless) рабочей нагрузкой в кластере, где любой под в деплойменте не содержит изменяемых данных и может быть заменен при необходимости (Deployments — замена устаревшего ресурса ReplicationController API).

StatefulSet позволяет управлять одним или несколькими подами, в которых работает одно и то же приложение, для случаев, когда все эти поды требуют четкой идентичности (т.е. являются stateful). Это отличается от деплоймента, в котором предполагается, что поды могут быть взаимозаменяемыми. Наиболее распространенное использование StatefulSet — возможность установить связь между его подами и их постоянным хранилищем (persistent storage). Например, можно запустить StatefulSet, который связывает каждый под с PersistentVolume. Если один из подов в StatefulSet выходит из строя, Kubernetes создает заменяющий под, подключенный к тому же PersistentVolume.

DaemonSet создает поды, которые предоставляют локальные инструменты для узлов; пример — драйвер, который позволяет контейнерам на узле получить доступ к системе хранения. DaemonSet используется, когда драйвер или сервис должен быть запущен на определенном узле. Каждый под в DaemonSet выполняет роль, аналогичную системному демону на классическом сервере Unix/POSIX. DaemonSet может иметь основополагающее значение для работы кластера, например, для плагина, позволяющего узлу получить доступ к сети кластера. Он может помочь управлять узлом или предоставить менее важные функции, улучшающие работу используемой контейнерной платформы. DaemonSet'ы (и их поды) можно запускать на каждом узле кластера или только на некоторых из них (например, можно установить драйвер ускорителя GPU только на узлах, на которых установлен GPU).

Job и/или CronJob используются, чтобы определять задачи, которые выполняются по отдельному запуску до их завершения, а затем останавливаются. Job представляет собой разовую задачу, тогда как CronJob повторяется по расписанию.

Другие темы в этом разделе:

1 - DaemonSet

DaemonSet определяет Pod'ы, предоставляющие локальные для узла возможности. Они могут быть критически важны для работы кластера, например, сетевой вспомогательный инструмент, или являться частью дополнения.

DaemonSet гарантирует, что на всех (или некоторых) узлах запущена копия Pod'а. При добавлении узлов в кластер Pod'ы автоматически добавляются на них. При удалении узлов из кластера эти Pod'ы удаляются сборщиком мусора. Удаление DaemonSet приведёт к удалению всех созданных им Pod'ов.

Типичные случаи использования DaemonSet:

  • запуск демона кластерного хранилища на каждом узле
  • запуск демона сбора логов на каждом узле
  • запуск демона мониторинга узлов на каждом узле

В простом случае для каждого типа демона используется один DaemonSet, охватывающий все узлы. В более сложных конфигурациях может использоваться несколько DaemonSet для одного типа демона, но с разными флагами и/или разными запросами памяти и CPU для различных типов оборудования.

Написание спецификации DaemonSet

Создание DaemonSet

DaemonSet можно описать в YAML-файле. Например, файл daemonset.yaml ниже описывает DaemonSet, запускающий Docker-образ fluentd-elasticsearch:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-elasticsearch
  namespace: kube-system
  labels:
    k8s-app: fluentd-logging
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      tolerations:
      # these tolerations are to have the daemonset runnable on control plane nodes
      # remove them if your control plane nodes should not run pods
      - key: node-role.kubernetes.io/control-plane
        operator: Exists
        effect: NoSchedule
      - key: node-role.kubernetes.io/master
        operator: Exists
        effect: NoSchedule
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v5.0.1
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
      # it may be desirable to set a high priority class to ensure that a DaemonSet Pod
      # preempts running Pods
      # priorityClassName: important
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log

Создание DaemonSet на основе YAML-файла:

kubectl apply -f https://k8s.io/examples/controllers/daemonset.yaml

Обязательные поля

Как и для любой другой конфигурации Kubernetes, DaemonSet требует наличия полей apiVersion, kind и metadata. Общую информацию о работе с конфигурационными файлами см. в разделах запуск stateless-приложений и управление объектами с помощью kubectl.

Имя объекта DaemonSet должно быть допустимым DNS-именем поддомена.

DaemonSet также требует наличия секции .spec.

Шаблон Pod'а

Поле .spec.template является одним из обязательных полей в .spec.

Поле .spec.template представляет собой шаблон Pod'а. Оно имеет точно такую же схему, как и Pod, за исключением того, что является вложенным и не имеет полей apiVersion и kind.

Помимо обязательных полей для Pod'а, шаблон Pod'а в DaemonSet должен указывать соответствующие метки (см. селектор Pod'ов).

Шаблон Pod'а в DaemonSet должен иметь RestartPolicy, равную Always, или быть не указанным, что по умолчанию означает Always.

Селектор Pod'ов

Поле .spec.selector является селектором Pod'ов. Оно работает так же, как .spec.selector у Job.

Необходимо указать селектор Pod'ов, который соответствует меткам в .spec.template. Также, после создания DaemonSet, его .spec.selector не может быть изменён. Изменение селектора Pod'ов может привести к непреднамеренному осиротению Pod'ов, что может запутать пользователей.

Поле .spec.selector представляет собой объект, состоящий из двух полей:

  • matchLabels — работает так же, как .spec.selector у ReplicationController.
  • matchExpressions — позволяет создавать более сложные селекторы, указывая ключ, список значений и оператор, связывающий ключ и значения.

Когда указаны оба поля, результат объединяется по логическому И (AND).

Поле .spec.selector должно соответствовать .spec.template.metadata.labels. Конфигурация с несовпадающими значениями будет отклонена API.

Запуск Pod'ов на выбранных узлах

Если указано поле .spec.template.spec.nodeSelector, контроллер DaemonSet будет создавать Pod'ы на узлах, соответствующих этому селектору узлов. Аналогично, если указано поле .spec.template.spec.affinity, контроллер DaemonSet будет создавать Pod'ы на узлах, соответствующих этой привязке к узлам (node affinity). Если ни одно из полей не указано, контроллер DaemonSet будет создавать Pod'ы на всех узлах.

Как планируются Pod'ы демонов

DaemonSet может использоваться для обеспечения того, чтобы все подходящие узлы запускали копию Pod'а. Контроллер DaemonSet создаёт Pod для каждого подходящего узла и добавляет поле spec.affinity.nodeAffinity в Pod для соответствия целевому хосту. После создания Pod'а обычно управление берёт на себя планировщик по умолчанию, который привязывает Pod к целевому хосту, устанавливая поле .spec.nodeName. Если новый Pod не помещается на узле, планировщик по умолчанию может вытеснить (evict) некоторые из существующих Pod'ов на основе приоритета нового Pod'а.

Пользователь может указать другой планировщик для Pod'ов DaemonSet, установив поле .spec.template.spec.schedulerName у DaemonSet.

Исходная привязка к узлам, указанная в поле .spec.template.spec.affinity.nodeAffinity (если указана), учитывается контроллером DaemonSet при оценке подходящих узлов, но заменяется в созданном Pod'е на привязку к узлу, соответствующую имени подходящего узла.

nodeAffinity:
  requiredDuringSchedulingIgnoredDuringExecution:
    nodeSelectorTerms:
    - matchFields:
      - key: metadata.name
        operator: In
        values:
        - target-host-name

Ограничения (taints) и допуски (tolerations)

Контроллер DaemonSet автоматически добавляет набор допусков (tolerations) к Pod'ам DaemonSet:

Допуски для Pod'ов DaemonSet
Ключ допуска Эффект Описание
node.kubernetes.io/not-ready NoExecute Pod'ы DaemonSet могут планироваться на узлы, которые не готовы или не могут принимать Pod'ы. Любые Pod'ы DaemonSet, работающие на таких узлах, не будут вытеснены.
node.kubernetes.io/unreachable NoExecute Pod'ы DaemonSet могут планироваться на узлы, недоступные для контроллера узлов. Любые Pod'ы DaemonSet, работающие на таких узлах, не будут вытеснены.
node.kubernetes.io/disk-pressure NoSchedule Pod'ы DaemonSet могут планироваться на узлы с проблемами нехватки дискового пространства.
node.kubernetes.io/memory-pressure NoSchedule Pod'ы DaemonSet могут планироваться на узлы с проблемами нехватки памяти.
node.kubernetes.io/pid-pressure NoSchedule Pod'ы DaemonSet могут планироваться на узлы с проблемами нехватки процессов.
node.kubernetes.io/unschedulable NoSchedule Pod'ы DaemonSet могут планироваться на узлы, помеченные как непланируемые.
node.kubernetes.io/network-unavailable NoSchedule Добавляется только для Pod'ов DaemonSet, запрашивающих сеть хоста, т.е. Pod'ов с spec.hostNetwork: true. Такие Pod'ы DaemonSet могут планироваться на узлы с недоступной сетью.

Вы также можете добавить собственные допуски к Pod'ам DaemonSet, определив их в шаблоне Pod'а DaemonSet.

Поскольку контроллер DaemonSet автоматически устанавливает допуск node.kubernetes.io/unschedulable:NoSchedule, Kubernetes может запускать Pod'ы DaemonSet на узлах, помеченных как непланируемые.

Если вы используете DaemonSet для предоставления важной функции уровня узла, такой как сетевое взаимодействие кластера, полезно, что Kubernetes размещает Pod'ы DaemonSet на узлах до того, как они будут готовы. Например, без этого специального допуска вы можете оказаться в тупиковой ситуации, когда узел не помечен как готовый, потому что сетевой плагин там не запущен, и в то же время сетевой плагин не запущен на этом узле, потому что узел ещё не готов.

Взаимодействие с Pod'ами демонов

Некоторые возможные паттерны взаимодействия с Pod'ами в DaemonSet:

  • Push: Pod'ы в DaemonSet настроены на отправку обновлений в другой сервис, например, в базу данных статистики. У них нет клиентов.
  • IP узла и известный порт: Pod'ы в DaemonSet могут использовать hostPort, чтобы быть доступными по IP-адресам узлов. Клиенты каким-либо образом знают список IP-адресов узлов и знают порт по соглашению.
  • DNS: Создайте headless-сервис с тем же селектором Pod'ов, а затем обнаруживайте DaemonSet'ы, используя ресурс endpoints или получая несколько A-записей из DNS.
  • Service: Создайте сервис с тем же селектором Pod'ов и используйте сервис для доступа к демону на случайном узле. Используйте политику внутреннего трафика сервиса (Service Internal Traffic Policy) для ограничения Pod'ами на том же узле.

Обновление DaemonSet

При изменении меток узлов DaemonSet оперативно добавит Pod'ы на узлы, которые теперь соответствуют условиям, и удалит Pod'ы с узлов, которые больше не соответствуют.

Вы можете изменять Pod'ы, созданные DaemonSet. Однако Pod'ы не позволяют обновлять все поля. Кроме того, контроллер DaemonSet будет использовать исходный шаблон при следующем создании узла (даже с тем же именем).

Вы можете удалить DaemonSet. Если указать --cascade=orphan с kubectl, то Pod'ы останутся на узлах. Если впоследствии создать новый DaemonSet с тем же селектором, новый DaemonSet примет существующие Pod'ы. Если какие-либо Pod'ы требуют замены, DaemonSet заменит их в соответствии со своей updateStrategy.

Вы можете выполнить плавное обновление (rolling update) DaemonSet.

Альтернативы DaemonSet

Init-скрипты

Безусловно, можно запускать процессы-демоны напрямую на узле (например, используя init, upstartd или systemd). Это вполне допустимо. Однако есть несколько преимуществ запуска таких процессов через DaemonSet:

  • Возможность мониторинга и управления логами демонов так же, как и приложений.
  • Один и тот же язык конфигурации и инструменты (например, шаблоны Pod'ов, kubectl) для демонов и приложений.
  • Запуск демонов в контейнерах с ограничениями ресурсов повышает изоляцию между демонами и контейнерами приложений. Однако этого также можно достичь, запуская демоны в контейнере, но не в Pod'е.

Обычные Pod'ы (Bare Pods)

Можно создавать Pod'ы напрямую, указывая конкретный узел для запуска. Однако DaemonSet заменяет Pod'ы, которые были удалены или завершены по любой причине, например, в случае сбоя узла или при разрушительном обслуживании узла, таком как обновление ядра. По этой причине следует использовать DaemonSet вместо создания отдельных Pod'ов.

Статические Pod'ы

Можно создавать Pod'ы, записывая файл в определённый каталог, отслеживаемый Kubelet. Такие Pod'ы называются статическими Pod'ами. В отличие от DaemonSet, статическими Pod'ами нельзя управлять с помощью kubectl или других клиентов Kubernetes API. Статические Pod'ы не зависят от apiserver, что делает их полезными в случаях начальной загрузки кластера. Также статические Pod'ы могут быть объявлены устаревшими в будущем.

Deployment'ы

DaemonSet'ы похожи на Deployment'ы тем, что оба создают Pod'ы, и эти Pod'ы содержат процессы, которые не должны завершаться (например, веб-серверы, серверы хранения).

Используйте Deployment для stateless-сервисов, таких как фронтенды, где масштабирование вверх и вниз количества реплик и развёртывание обновлений важнее, чем контроль того, на каком именно хосте запускается Pod. Используйте DaemonSet, когда важно, чтобы копия Pod'а всегда работала на всех или определённых хостах, если DaemonSet предоставляет функциональность уровня узла, позволяющую другим Pod'ам корректно работать на этом конкретном узле.

Например, сетевые плагины часто включают компонент, работающий как DaemonSet. Компонент DaemonSet обеспечивает работу кластерной сети на узле, где он запущен.

Что дальше

2 - CronJob

CronJob запускает одноразовые задания по повторяющемуся расписанию
СТАТУС ФИЧИ: Kubernetes v1.21 [stable]

CronJob создает задания (Jobs), которые повторяются по расписанию.

CronJob предназначен для выполнения регулярных заданий по расписанию, таких как резервное копирование, создание отчетов, и так далее. Один CronJob объект — это как одна строка файла crontab (cron table) в Unix-системе. Он периодически запускает задание по заданному расписанию, составленному в формате формате Cron.

У CronJob'a есть свои ограничения и особенности. Например, при определенных обстоятельствах один CronJob может создавать несколько параллельных заданий. См. раздел Ограничения ниже.

Когда управляющий слой (control plane) создает новые задания и (косвенно) поды для CronJob'а, поле .metadata.name в CronJob является частью основы для наименования этих подов. Имя CronJob должно быть действительным значением поддомена DNS, но это может привести к неожиданным результатам для имен хостов подов. Для наилучшей совместимости имя должно соответствовать более строгим правилам имен меток DNS. Даже если имя является поддоменом DNS, оно не должно превышать 52 символов. Это связано с тем, что контроллер CronJob автоматически добавляет 11 символов к указанному вами имени и существует ограничение на то, что длина имени задания (Job) не должна превышать 63 символа.

Пример

Этот пример манифеста CronJob печатает текущее время и сообщение hello каждую минуту:

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 более подробно рассматривает этот пример.)

Написание спецификации CronJob'a

Синтаксис расписания

Поле .spec.schedule является обязательным. Значение этого поля соответствует синтаксису Cron:

# ┌───────────── минута (0 - 59)
# │ ┌───────────── час (0 - 23)
# │ │ ┌───────────── день месяца (1 - 31)
# │ │ │ ┌───────────── месяц (1 - 12)
# │ │ │ │ ┌───────────── день недели (0 - 6) (воскресенье - суббота)
# │ │ │ │ │                                   ИЛИ sun, mon, tue, wed, thu, fri, sat
# │ │ │ │ │
# * * * * *

Например, 0 0 13 * 5 указывает, что задание должно запускаться каждую пятницу в полночь, а также 13 числа каждого месяца в полночь.

Формат также включает расширенные значения шагов "Vixie cron". Как объясняется в инструкции для FreeBSD:

Значения шагов можно использовать в сочетании с диапазонами. Если после диапазона указать /<число>, то это означает пропуск значения числа в диапазоне. Например, 0-23/2 можно использовать, чтобы указать выполнение команды каждый второй час (альтернативой в стандарте V7 является 0,2,4,6,8,10,12,14,16,18,20,22). Шаги также разрешены после звездочки, так что если нужно указать "каждые два часа", можно использовать */2.

Помимо стандартного синтаксиса можно также использовать макросы вроде @monthly:

Запись Описание Эквивалент
@yearly (или @annually) Запускается один раз в год в полночь 1 января 0 0 1 1 *
@monthly Запускается раз в месяц в полночь первого дня месяца 0 0 1 * *
@weekly Запускается раз в неделю в полночь в воскресенье утром 0 0 * * 0
@daily (или @midnight) Запускается один раз в день в полночь 0 0 * * *
@hourly Запускается раз в час в начале часа 0 * * * *

Для создания CronJob-расписания можно также использовать такие веб-инструменты, как crontab.guru.

Шаблон задания

Поле .spec.jobTemplate определяет шаблон для заданий, которые создает CronJob, и является обязательным. Он имеет точно такой же вид, как и Job, за исключением того, что является вложенным и не имеет полей apiVersion и kind. Можно указать типичные метаданные для шаблонных заданий (Jobs), такие как метки или аннотации. О том, как написать .spec для Job, см. Написание спецификации Job.

Дедлайн задержки начала задания

Поле .spec.startingDeadlineSeconds является необязательным. В этом поле задается крайний срок (в целых секундах) для запуска задания (Job), если оно по какой-либо причине не успевает к назначенному времени.

Если дедлайн пропущен, CronJob пропускает этот вызов задания (последующие выполнения по-прежнему запланированы). Например, если задание резервного копирования выполняется дважды в день, можно разрешить ему запускаться с опозданием до 8 часов, но не позже, поскольку резервная копия, сделанная позже, не будет полезной: лучше дождаться следующего запуска по расписанию.

Задания, которые не успели выполниться в установленный срок, Kubernetes рассматривает как неудачные. Если не указать startingDeadlineSeconds для CronJob, то задания не будут иметь дедлайн.

Если поле .spec.startingDeadlineSeconds установлено (не является нулевым), контроллер CronJob измеряет время между моментом, когда задание должно быть создано, и реальным временем. Если разница превышает указанный предел, он пропустит этот вызов задания.

Например, если установлено значение 200, задание может быть создано в период до 200 секунд позже фактического расписания.

Политика параллелизма (concurrency policy)

Поле .spec.concurrencyPolicy также является необязательным. Оно определяет, как обращаться с одновременным выполнением заданий, созданных этим CronJob. В этой спецификации может быть указана только одна из следующих политик параллелизма:

  • Allow (по умолчанию): CronJob разрешает одновременное выполнение заданий.
  • Forbid: CronJob не разрешает одновременное выполнение заданий; если пришло время для выполнения нового задания, а предыдущее еще не завершилось, CronJob пропускает новое задание.
  • Replace: Если пришло время для выполнения нового задания, а предыдущее еще не завершилось, CronJob заменит текущее задание на новое.

Заметьте, что принцип параллелизма применяется только к заданиям, созданным одним и тем же Cronjob'ом. Если есть несколько CronJob'ов, их соответствующие задания всегда могут выполняться одновременно.

Остановка выполнения заданий по расписанию

Можно приостановить выполнение CronJob-заданий, присвоив необязательному полю .spec.suspend значение true. По умолчанию это поле имеет значение false.

Эта настройка не влияет на задания, которые уже были запущены CronJob'ом.

Если установить это поле как true, все последующие выполнения будут приостановлены (они остаются запланированными, но CronJob-контроллер не запускает задания для выполнения), пока вы не отмените приостановку CronJob'a.

Лимиты на историю заданий

Поля .spec.successfulJobsHistoryLimit и .spec.failedJobsHistoryLimit являются необязательными. В этих полях указывается, сколько завершенных и неудачных заданий должно быть сохранено в истории. По умолчанию они установлены на 3 и 1 соответственно. Установка предела в 0 будет означать, что никакие задания соответствующего типа не сохранятся после их завершения.

Другой способ автоматической очистки заданий см. в разделе Автоматическая очистка завершенных заданий.

Часовые пояса

СТАТУС ФИЧИ: Kubernetes v1.27 [stable]

Для CronJob'a, в которых не указан часовой пояс, kube-controller-manager интерпретирует расписания относительно своего локального часового пояса.

Можно указать часовой пояс для CronJob'a, присвоив .spec.timeZone имя действительного часового пояса. Например, установка .spec.timeZone: "Etc/UTC" инструктирует Kubernetes интерпретировать расписание относительно всемирного координированного времени.

База данных часовых поясов из стандартной библиотеки Go включена в бинарные файлы и используется в качестве запасного варианта на случай, если внешняя база данных недоступна в системе.

Ограничения CronJob

Неподдерживаемая спецификация TimeZone

Установка часового пояса с помощью переменных CRON_TZ или TZ в .spec.schedule не поддерживается официально (и никогда не поддерживалась).

Начиная с Kubernetes 1.29, если попытаться задать расписание, включающее спецификацию часового пояса TZ или CRON_TZ, Kubernetes не сможет создать ресурс, выдав ошибку валидации. Обновления для CronJobs, уже использующих TZ или CRON_TZ, будут продолжать выдавать предупреждение клиенту.

Модификация задания CronJob

По своей структуре CronJob содержит шаблон для новых заданий. Если изменить существующее задание CronJob, внесенные изменения будут применены к новым заданиям, которые начнут выполняться после завершения модификации. Задания (и их поды), которые уже были запущены, продолжат выполняться без изменений. То есть CronJob не обновляет существующие задания, даже если они остаются запущенными.

Создание заданий

CronJob создает объект задания (Job) примерно один раз за время выполнения своего расписания. Расписание является приблизительным, поскольку есть определенные обстоятельства, при которых могут быть созданы два задания или не создано ни одного. Kubernetes старается избегать таких ситуаций, но не может полностью предотвратить их. Поэтому задания, которые вы определяете, должны быть идемпотентными.

Если в поле startingDeadlineSeconds задано большое значение или оно не определено (по умолчанию), а также при условии, что concurrencyPolicy имеет значение Allow, задания всегда будут выполняться по крайней мере один раз.

Для каждого задания CronJob контроллер проверяет, сколько расписаний он пропустил за время, прошедшее с последнего расписания до настоящего момента. Если пропущено более 100 расписаний, то задание не запускается и фиксируется ошибка.

Cannot determine if job needs to be started. Too many missed start time (> 100). Set or decrease .spec.startingDeadlineSeconds or check clock skew.

Важно отметить, что если поле startingDeadlineSeconds установлено (не равно nil), контроллер считает, сколько пропущенных заданий произошло с момента значения startingDeadlineSeconds до настоящего момента, а не с момента последнего запланированного задания до настоящего момента. Например, если startingDeadlineSeconds равно 200, контроллер подсчитывает, сколько пропущенных заданий произошло за последние 200 секунд.

Задание CronJob считается пропущенным, если оно не было создано в запланированное время. Например, если для concurrencyPolicy установлено значение Forbid, и CronJob пытался быть запланирован, когда предыдущее расписание еще выполнялось, то он будет считаться пропущенным.

Например, предположим, что задание CronJob настроено на планирование нового задания каждую минуту, начиная с 08:30:00, а его поле поле startingDeadlineSeconds не установлено. Если контроллер CronJob не функционирует с 08:29:00 до 10:21:00, задание не будет запущено, так как количество пропущенных заданий, которые не успели выполнить свое расписание, больше 100.

Чтобы подробнее проиллюстрировать эту концепцию, предположим, что задание CronJob настроено на планирование нового задания каждую одну минуту, начиная с 08:30:00, и его параметр startingDeadlineSeconds установлен на 200 секунд. Если контроллер CronJob вдруг не функционирует в течение того же периода, что и в предыдущем примере (с 08:29:00 по 10:21:00), задание все равно начнется в 10:22:00. Это происходит потому, что контроллер в данном случае проверяет, сколько пропущенных запланированных заданий было за последние 200 секунд (т. е. 3 пропущенных расписания), а не с момента последнего запланированного времени до настоящего момента.

CronJob отвечает только за создание заданий (Jobs), соответствующих его расписанию, а задание, в свою очередь, отвечает за управление подами, которые оно представляет.

Что дальше