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

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

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

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

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

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

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

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

  • Деплоймент (Deployment) и ReplicaSet (замена устаревшего ресурса ReplicationController). Deployment хорошо подходит для управления неизменными (stateless) приложениями в кластере, то есть для случаев, когда любой под в деплойменте не содержит изменяемых данных и может быть заменен при необходимости.
  • StatefulSet позволяет запускать один или несколько связанных подов, которые как-то отслеживают состояние (являются stateful). Например, если ваше приложение записывает постоянные данные, вы можете использовать StatefulSet, который сопоставляет каждый под с PersistentVolume. Ваш код, работающий в подах этого StatefulSet, может копировать данные в другие поды в том же StatefulSet, чтобы повысить общую отказоустойчивость.
  • DaemonSet создает поды, которые предоставляют инструменты, которые доступны локально для узлов. Каждый раз, когда вы добавляете в кластер узел, соответствующий спецификации DaemonSet, слой управления (control plane) планирует (т.е. запускает) под с этим DaemonSet на новом узле. Каждый под в DaemonSet выполняет работу, аналогичную работе системного демона на классическом сервере Unix/POSIX. DaemonSet может иметь основополагающее значение для работы вашего кластера, например, в случае плагина для запуска сети кластера (cluster networking). Этот ресурс может помочь управлять узлом или предоставить дополнительные возможности для используемой контейнерной платформы.
  • Job и CronJob предоставляют различные способы запуска задач, которые выполняются до своего завершения, а затем останавливаются. Job используется для задачи, которая выполняется только один раз. Вы можете использовать CronJob для запуска этого же задания несколько раз по расписанию.

В экосистеме вокруг проекта Kubernetes можно найти сторонние ресурсы для рабочих нагрузок, которые предоставляют дополнительные функции. Используя custom resource definition, вы можете добавить сторонний ресурс рабочей нагрузки, если нужно определенное поведение, не являющееся частью стандартного Kubernetes. Например, если вы хотите запустить группу подов для своего приложения, но хотите свернуть работу в случае, когда не все поды доступны (возможно, для распределенной задачи с высокой пропускной способностью), можно реализовать или установить расширение, которое предоставляет эту функцию.

Что дальше

В дополнение к информации о каждом виде API для управления рабочей нагрузкой вы можете прочитать, как выполнять конкретные задачи:

Чтобы узнать о механизмах отделения кода от конфигурации в Kubernetes, посетите раздел Configuration.

Есть два вспомогательных концепта, которые дают представление о том, как Kubernetes управляет подами для приложений:

  • Сборщик мусора (Garbage collection) вычищает объекты из вашего кластера после удаления ресурса-владельца.
  • Контроллер времени существования после завершения (time-to-live after finished controller) удаляет задания (Jobs) по истечении определенного времени с момента их завершения.

После запуска вашего приложения можно сделать его доступным в интернете с помощью Service или, только в случае веб-приложения, используя Ingress.

1 - Поды

Поды (Pods) — это самые маленькие развертываемые вычислительные единицы, которые можно создавать и которыми можно управлять в Kubernetes.

Под (от англ. «pod», что означает стаю китов или гороховый стручок) — это группа из одного или нескольких контейнеров с общими хранилищами и сетевыми ресурсами, а также спецификация для запуска контейнеров. Содержимое Пода всегда находится в одном месте, имеет совместное расписание и выполняется в общем контексте. Под по своей сути представляется специфическим для приложения "логическим хостом": он содержит один или несколько контейнеров приложений, которые относительно тесно связаны между собой. Приложения вне облачной инфраструктуры, выполняемые на одной физической или виртуальной машине, аналогичны облачным приложениям, выполняемым на одном логическом хосте.

Помимо контейнеров приложений Под может содержать init-контейнеры, которые запускаются при старте Пода. Вы также можете внедрить эфемерные контейнеры для отладки запущенного Пода.

Что такое Под?

Общий контекст Пода - это набор пространств имен Linux, cgroups и, возможно, других аспектов изоляции - всего того, что изолирует и контейнер. Внутри контекста Пода отдельные приложения могут иметь дополнительные субизоляции.

Под похож на набор контейнеров с общими пространствами имен и общими томами файловой системы.

Поды в кластере Kubernetes используются двумя основными способами:

  • Поды, которые запускают один контейнер. Модель "один контейнер на Под" является наиболее распространенным вариантом использования Kubernetes; в этом случае вы можете рассматривать Под как обертку вокруг одного контейнера; Kubernetes управляет Подами, а не непосредственно контейнерами.

  • Поды, которые запускают несколько контейнеров, обязанных работать вместе. Под может инкапсулировать приложение, состоящее из нескольких расположенных рядом контейнеров, которые тесно связаны между собой и нуждаются в совместном использовании ресурсов. Эти расположенные рядом контейнеры образуют единое целое.

    Группировка нескольких совместно расположенных и совместно управляемых контейнеров в одном Поде - это довольно сложный кейс. Этот паттерн следует использовать только в особых случаях, когда ваши контейнеры тесно связаны между собой.

    Запускать несколько контейнеров для обеспечения репликации (устойчивости или производительности) не требуется. Если вам нужно несколько реплик, смотрите раздел Ресурсы рабочей нагрузки.

Использование Подов

Ниже приведен пример Пода, состоящего из контейнера, в котором запущен образ nginx:1.14.2.

apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx:1.14.2
    ports:
    - containerPort: 80

Чтобы создать описанный выше Под, выполните следующую команду:

kubectl apply -f https://k8s.io/examples/pods/simple-pod.yaml

Поды обычно создаются не напрямую, а при создании ресурсов рабочей нагрузки. Дополнительные сведения о том, как использовать Поды с ресурсами рабочей нагрузки, см. в разделе Работа с Подами.

Ресурсы рабочей нагрузки для управления подами

Обычно не нужно создавать Поды напрямую, даже если это одиночный Под. Вместо этого они создаются с помощью ресурсов рабочей нагрузки, таких как Deployment или Job. Если для Подов важно хранить состояние (т.е. они stateful), рассмотрите ресурс StatefulSet.

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

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

Поды изначально предоставляют два вида общих ресурсов для входящих в них контейнеров: сеть и хранилище.

Работа с Подами

Создание отдельных Подов в Kubernetes — даже одиночных Подов — случается редко. Это связано с тем, что Поды разработаны как относительно эфемерные, одноразовые сущности. Когда Под создается (непосредственно вами или косвенно контроллером), новый Под планируется к запуску на одном из узлов кластера. Под остается на этом узле до тех пор, пока Под не завершит выполнение, объект Пода не будет удален, Под не будет вытеснен из-за нехватки ресурсов, или узел не выйдет из строя.

Имя Пода должно быть действительным значением имени поддомена DNS, но это может привести к неожиданным результатам для имени хоста Пода. Для лучшей совместимости имя должно соответствовать более строгим правилам для имен меток DNS.

ОС Пода

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

В поле .spec.os.name следует установить значение windows или linux, чтобы указать ОС, на которой будет работать под. На данный момент Kubernetes поддерживает только эти две операционные системы. В будущем этот список может быть расширен.

В Kubernetes v1.32 значение .spec.os.name не влияет на то, как kube-scheduler выбирает узел для запуска Пода. В любом кластере, где на работающих узлах используются разные операционные системы, необходимо установить правильный лейбл kubernetes.io/os для каждого узла и определить поды с nodeSelector, указывающим на лейбл операционной системы. Планировщик kube-scheduler распределяет поды по узлам, основываясь ещё и на других критериях, поэтому выбор подходящего узла с ОС, которая нужна контейнерам данного пода, не всегда будет успешным. Pod Security Standards также используют это поле, чтобы избежать применения политик, которые не относятся к данной операционной системе.

Поды и контроллеры

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

Вот несколько примеров ресурсов рабочей нагрузки, которые управляют одним или несколькими Подами:

Шаблоны Подов

Контроллеры ресурсов рабочей нагрузки создают Поды из шаблонов Подов и управляют этими Подами в соответствии с вашими потребностями.

PodTemplates - это спецификации для создания Подов, которые включаются в ресурсы рабочей нагрузки, такие как Deployments, Jobs и DaemonSets.

Каждый контроллер для ресурса рабочей нагрузки использует шаблон PodTemplate внутри объекта рабочей нагрузки для создания реальных Подов. PodTemplate является частью желаемого состояния того ресурса рабочей нагрузки, который вы использовали для запуска своего приложения.

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

Приведенный ниже пример представляет собой манифест для простого Job с template, который запускает один контейнер. Контейнер в этом Поде печатает сообщение, затем приостанавливается.

apiVersion: batch/v1
kind: Job
metadata:
  name: hello
spec:
  template:
    # Это шаблон Пода
    spec:
      containers:
      - name: hello
        image: busybox:1.28
        command: ['sh', '-c', 'echo "Hello, Kubernetes!" && sleep 3600']
      restartPolicy: OnFailure
    # Здесь шаблон Пода заканчивается

Изменение шаблона пода или переход на новый шаблон пода не оказывает прямого влияния на уже существующие Поды. Если вы измените pod template для ресурса рабочей нагрузки, этот ресурс должен будет создать замену Подам, использующим обновленный шаблон.

Например, контроллер StatefulSet следит за тем, чтобы запущенные Поды соответствовали текущему pod template для каждого объекта StatefulSet. Если вы отредактируете StatefulSet, чтобы изменить его pod template, StatefulSet начнет создавать новые Поды на основе обновленного шаблона. В конце концов, все старые Поды заменяются новыми, и обновление завершается.

Каждый ресурс рабочей нагрузки реализует свои собственные правила обработки изменений в шаблонах Подов. Если вы хотите узнать больше о StatefulSet, ознакомьтесь с Updating StatefulSets в учебном пособии "StatefulSet Basics".

На Узлах kubelet не знает про шаблоны Подов и связанные с ними обновления Подов, никак не управляет ими; эти подробности для него абстрагированы. Такая абстракция и разделение интересов упрощает семантику системы и делает возможным расширение поведения кластера без изменения существующего кода.

Обновление и замена Пода

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

Kubernetes не мешает управлять Подами напрямую. Можно обновить некоторые поля уже работающего Пода прямо «на месте». Однако операции обновления Пода, такие как patch и replace, имеют некоторые ограничения:

  • Большинство метаданных о Поде неизменяемы. Например, вы не можете изменить поля namespace, name, uid или creationTimestamp; поле generation уникально. Оно принимает только те обновления, которые увеличивают текущее значение поля.

  • Если установлено значение metadata.deletionTimestamp, то в список metadata.finalizers не может быть добавлена новая запись.

  • Обновления Пода не могут изменять поля, кроме spec.containers[*].image, spec.initContainers[*].image, spec.activeDeadlineSeconds или spec.tolerations. Для spec.tolerations можно только добавлять новые записи.

  • При обновлении поля spec.activeDeadlineSeconds допускается два типа обновлений:

    1. установка положительного значения для неназначенного поля;
    2. обновление поля с положительного числа на меньшее неотрицательное число.

Совместное использование ресурсов и коммуникация

Поды позволяют обмениваться данными и взаимодействовать между входящими в них контейнерами.

Хранение в Подах

Под может определять набор общих томов хранения. Все контейнеры в Поде могут получить доступ к общим томам, что позволяет им обмениваться данными. Тома также позволяют сохранять данные в Поде в случае необходимости перезапуска одного из контейнеров. Дополнительные сведения о том, как Kubernetes реализует общее хранилище и делает его доступным для Подов, см. в разделе Storage.

Сеть в Подах

Каждому Поду назначается уникальный IP-адрес для каждого семейства адресов. Каждый контейнер в Поде разделяет сетевое пространство имен, включая IP-адрес и сетевые порты. Внутри Пода (и только в нем) контейнеры, входящие в Под, могут взаимодействовать друг с другом, используя localhost. Когда контейнеры в Поде общаются с сущностями за пределами Пода, они должны координировать использование общих сетевых ресурсов (например, портов). Внутри Пода контейнеры имеют общий IP-адрес и порт, и могут найти друг друга через localhost. Контейнеры в Поде также могут взаимодействовать друг с другом, используя стандартные межпроцессные взаимодействия, такие как семафоры SystemV или общая память POSIX. Контейнеры в разных Подах имеют разные IP-адреса и не могут взаимодействовать по IPC на уровне ОС без специальной настройки. Контейнеры, которые хотят взаимодействовать с контейнером, запущенным в другом Поде, могут использовать IP-сети для коммуникации.

Контейнеры в Поде воспринимают системное имя хоста как то же самое, что и сконфигурированный name для Пода. Подробнее об этом в разделе Сеть в кластере.

Привилегированный режим для контейнеров

Любой контейнер в поде может работать в привилегированном режиме, чтобы использовать административные возможности операционной системы, которые иначе были бы недоступны. Это доступно как для Windows, так и для Linux.

Привилегированные контейнеры в Linux

В Linux любой контейнер в Поде может включить привилегированный режим с помощью флага privileged (Linux) в контексте безопасности спецификации контейнера. Это полезно для контейнеров, которые хотят использовать возможности администрирования операционной системы, такие как работа с сетевым стеком или доступ к аппаратным устройствам.

Привилегированные контейнеры в Windows

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

В Windows вы можете создать Windows HostProcess pod, установив флаг windowsOptions.hostProcess в контексте безопасности спецификации пода. Все контейнеры в этих подах должны работать как контейнеры Windows HostProcess. HostProcess-поды запускаются непосредственно на хосте и могут использоваться для выполнения административных задач, как это делается с привилегированными контейнерами Linux.

Статические Поды

Статические Поды управляются непосредственно демоном kubelet на определенном узле, без наблюдения со стороны API-сервера. В то время как большинство Подов управляются управляющим слоем (Control Plane) (например, Deployment), для статических Подов kubelet непосредственно контролирует каждый статический Под (и перезапускает его в случае сбоя).

Статические Поды всегда привязаны к одному Kubelet на определенном узле. Основное применение статических Подов - запуск самодостаточного управляющего слоя (Control Plane): другими словами, использование kubelet для контроля отдельных компонентов управляющего слоя.

Kubelet автоматически пытается создать зеркальный Под на API-сервере Kubernetes для каждого статического Пода. Это означает, что запущенные на узле Поды видны на API-сервере, но управлять ими оттуда нельзя. Дополнительную информацию см. в руководстве Create static Pods.

Поды с несколькими контейнерами

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

Поды в кластере Kubernetes используются двумя основными способами:

  • Поды, которые запускают один контейнер. Модель "один контейнер на Под" является наиболее распространенным вариантом использования Kubernetes; в этом случае вы можете рассматривать Под как обертку вокруг одного контейнера; Kubernetes управляет Подами, а не непосредственно контейнерами.
  • Поды, которые запускают несколько контейнеров, обязанных работать вместе. Под может инкапсулировать приложение, состоящее из нескольких расположенных рядом контейнеров, которые тесно связаны между собой и нуждаются в совместном использовании ресурсов. Эти совместно расположенные контейнеры образуют единую целостную единицу обслуживания - например, один контейнер обслуживает данные, хранящиеся в общем томе, а отдельный sidecar-контейнер обновляет эти файлы. Под объединяет эти контейнеры, ресурсы хранения и эфемерный сетевой идентификатор в единое целое.

Например, у вас может быть контейнер, выполняющий роль веб-сервера для файлов на общем томе, и отдельный sidecar-контейнер, который обновляет эти файлы из удаленного источника, как показано на следующей схеме:

Pod creation diagram

В некоторых Подах есть init-контейнеры, а также app-контейнеры. По умолчанию init-контейнеры запускаются и завершаются до запуска app-контейнеров.

У вас также могут быть sidecar-контейнеры, которые реализуют вспомогательные сервисы для основного приложения Пода (например, service mesh).

СТАТУС ФИЧИ: Kubernetes v1.29 [beta]

Feature gate SidecarContainers включен по умолчанию и позволяет указать restartPolicy: Always для init-контейнеров. Установка политики перезапуска Always гарантирует, что контейнеры, для которых вы ее задали, будут рассматриваться как sidecar-контейнеры, которые будут работать в течение всего времени существования Пода. Контейнеры, которые вы явно определили как sidecar-контейнеры, запускаются раньше Пода основного приложения и остаются запущенными до тех пор, пока Под не будет выключен.

Probes контейнера

Probe - это диагностика, периодически выполняемая kubelet для контейнера. Для проведения диагностики kubelet может вызывать различные действия:

  • ExecAction (выполняется с помощью иcполняемой среды контейнеров)
  • TCPSocketAction (проверку производит kubelet)
  • HTTPGetAction (проверку производит kubelet)

Подробнее о probes вы можете прочитать в документации Pod Lifecycle.

Что дальше

  • Ознакомьтесь с жизненным циклом Пода.
  • Ознакомьтесь с RuntimeClass и с тем, как его использовать для настройки различных Подов с различными конфигурациями исполняемой среды контейнеров.
  • Ознакомьтесь с PodDisruptionBudget и с тем, как с его помощью можно управлять доступностью приложений во время сбоев.
  • Под - это ресурс верхнего уровня в Kubernetes REST API. Определение объекта Pod подробно описывает данный ресурс.
  • The Distributed System Toolkit: Patterns for Composite Containers объясняет общие компоновки для Подов с более чем одним контейнером.
  • Ознакомьтесь с Pod topology spread constraints.

Чтобы понять, почему Kubernetes оборачивает общий API Пода в другие ресурсы (такие как StatefulSets или Deployments), вы можете прочитать о технологиях, предшествовавших Kubernetes, включая:

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

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 повторяется по расписанию.

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

2.1 - 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), соответствующих его расписанию, а задание, в свою очередь, отвечает за управление подами, которые оно представляет.

Что дальше