Закрепление компонентов за узлами#

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

../../../_images/day0-model-green.svg ../../../_images/day0-ws-green.svg ../../../_images/day0-topology-green.svg ../../../_images/day0-tls-green.svg ../../../_images/day0-offline-blue.svg ../../../_images/day0-conf-white.svg ../../../_images/day0-conf-dark.svg

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

Закрепление компонентов необходимо в следующих случаях:

  • образы загружены не на все рабочие узлы, например каждый узел получает только образы тех компонентов, которые на нем работают;

  • отдельные компоненты платформы необходимо выделить на собственные узлы.

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

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

Примечание

Инструкция не описывает закрепление переходных узлов (AutomationControllerMeshIngress), а также расчет дискового пространства узлов, импорт образов при нехватке места, доставку контента в Private Automation Hub без импортера и обновление версии платформы.

Порядок действий#

Для закрепления компонентов за узлами выполните следующие действия:

  1. Назначьте роли рабочим узлам с помощью меток.

  2. Загрузите на каждый узел образы его ролей.

  3. Установите операторы с закреплением за узлами.

  4. Создайте секреты, как описано в инструкции по подготовке манифестов.

  5. Примените манифест приложения с селекторами узлов.

  6. После развертывания платформы закрепите поды заданий.

  7. Проверьте размещение подов.

Операторы необходимо устанавливать только после загрузки образов, так как под без локального образа не стартует и переходит в состояние ImagePullBackOff или ErrImagePull.

Роли и метки узлов#

Роль определяет, какие поды платформы работают на узле. Инструкция различает следующие роли:

Роль

Поды на узле

gateway

Шлюз платформы и оператор aa-operator.

controller

Поды web и task Automation Controller, задание миграции его базы данных и оператор ac-operator.

hub

Поды api, content, web, worker и Redis Private Automation Hub, оператор pah-operator.

eda

Поды Event-Driven Automation, собственные PostgreSQL и Redis Event-Driven Automation, оператор eda-operator.

db

Общие PostgreSQL и Redis платформы для шлюза, Automation Controller и Private Automation Hub.

dashboard

Под Automation Dashboard, его собственные PostgreSQL и Redis, оператор dashboard-operator.

Один узел может нести несколько ролей, а одну роль могут нести несколько узлов. Например, в кластере из четырех рабочих узлов роли можно распределить так: первый узел – controller, второй – gateway и hub, третий – eda и db, четвертый – dashboard.

Роль узла задает метка вида aa.astra/<role>=true. Название метки произвольное, однако оно должно совпадать в метках узлов, в манифестах операторов и в манифесте приложения. Примеры далее содержат метки aa.astra/gateway, aa.astra/controller, aa.astra/hub, aa.astra/eda, aa.astra/db и aa.astra/dashboard.

Назначьте роли узлам, например:

kubectl label node worker-1.example.com aa.astra/controller=true
kubectl label node worker-2.example.com aa.astra/gateway=true aa.astra/hub=true
kubectl label node worker-3.example.com aa.astra/eda=true aa.astra/db=true
kubectl label node worker-4.example.com aa.astra/dashboard=true

Проверьте назначенные метки:

kubectl get nodes -L aa.astra/gateway,aa.astra/controller,aa.astra/hub,aa.astra/eda,aa.astra/db,aa.astra/dashboard

В столбце каждой метки значение true должно стоять у узлов соответствующей роли.

Образы для узлов каждой роли#

На каждый узел необходимо загрузить образы всех его ролей из каталога images/ комплекта поставки. Если одну роль несут несколько узлов, образы роли необходимы каждому из них.

Роль

Образы

Примечания

gateway

aa, aa-proxy, aa-operator, kube-rbac-proxy

Под шлюза состоит из контейнеров api (образ aa) и proxy (образ aa-proxy).

controller

ac, aa-control-ee, redis, ubi18, ac-operator, kube-rbac-proxy

Образ redis необходим, так как поды web и task содержат контейнер Redis. Образ aa-control-ee используют контейнеры пода task, его же содержит параметр control_plane_ee_image манифеста приложения.

hub

pah, nginx, redis, ubi18, pah-operator, kube-rbac-proxy

У Private Automation Hub собственный Redis. Под web использует образ nginx. Базы данных Private Automation Hub хранит общая PostgreSQL платформы на узле роли db.

eda

eda, eda-ui, postgresql, redis, eda-operator, kube-rbac-proxy

У Event-Driven Automation собственные PostgreSQL и Redis, которые создает eda-operator. Образ eda-ui используют контейнеры nginx в подах api и event-stream.

db

postgresql, redis

Общие PostgreSQL и Redis платформы обслуживают шлюз, Automation Controller и Private Automation Hub.

dashboard

automation-dashboard, dashboard-operator, postgresql, redis

У Automation Dashboard собственные PostgreSQL и Redis. Под оператора dashboard-operator содержит один контейнер, поэтому образ kube-rbac-proxy роли не требуется.

Образ kube-rbac-proxy необходим на каждом узле, где работает оператор aa-operator, ac-operator, pah-operator или eda-operator, так как под каждого из этих операторов содержит контейнер kube-rbac-proxy. Образ ubi18 входит в набор образов операторов Automation Controller и Private Automation Hub: ac-operator указывает его для init-контейнера постоянного тома проектов, а pah-operator – для init-контейнера подписи GPG. В базовой топологии поды платформы этот образ не используют. Загрузить его на узлы ролей controller и hub рекомендуется, чтобы конфигурации с этими init-контейнерами не остались без образа.

Предупреждение

Селекторы манифеста приложения не закрепляют под импортера контента Private Automation Hub (параметр offline_content_loader). Оператор pah-operator создает этот под объектом Job без селектора узлов, правил affinity и допусков tolerations, поэтому параметр hub.node_selector на него не действует. Планировщик предпочитает узлы, на которых образ уже загружен, однако это предпочтение не гарантирует размещение. Поэтому при включенном импортере образ k8s-hub-content-importer необходимо загрузить на все рабочие узлы, на которых планировщик может разместить этот под. Этот образ – самый большой в комплекте поставки.

Сценарий tools/load-containerd-images.yml загружает все образы каталога images/ на все узлы инвентаря. Для загрузки только образов роли скопируйте на узел файлы нужных образов и импортируйте каждый из них в containerd:

sudo ctr -n k8s.io images import <image_name>_<version>.tar

Здесь:

  • <image_name> – название образа из таблицы выше;

  • <version> – версия Astra Automation, например 2.1.

Проверьте состав образов на узле:

sudo ctr -n k8s.io images ls -q | grep '/aa/'

В выводе должны присутствовать все образы ролей узла.

Закрепление операторов#

Каждый оператор работает в поде, созданном объектом Deployment из манифеста каталога operators/ комплекта поставки. В этих объектах селектор узлов не задан, поэтому команда kubectl apply -f operators/ из инструкции по развертыванию размещает операторы на любых узлах. Объект Deployment находится в одном файле с определениями собственных ресурсов (CRD) и объектами управления доступом, поэтому манифест оператора необходимо изменить до применения, добавив в Deployment параметр nodeSelector.

Соответствие операторов ролям:

Файл манифеста

Объект Deployment

Метка узла

aa-operator-deploy.yaml

aa-operator-aa-manager

aa.astra/gateway

ac-operator-deploy.yaml

ac-operator-ac-manager

aa.astra/controller

pah-operator-deploy.yaml

pah-operator-pah-manager

aa.astra/hub

eda-operator-deploy.yaml

eda-operator-eda-manager

aa.astra/eda

dashboard-operator-deploy.yaml

dashboard-operator-dashboard-manager

aa.astra/dashboard

Если Automation Dashboard не развертывают, роль dashboard и ее оператор пропускают.

Для установки операторов с закреплением выполните следующие действия:

  1. В каталоге комплекта поставки создайте каталог для измененных манифестов и скопируйте в него манифесты пяти операторов:

    mkdir operators-pinned
    cp operators/aa-operator-deploy.yaml operators/ac-operator-deploy.yaml \
       operators/pah-operator-deploy.yaml operators/eda-operator-deploy.yaml \
       operators/dashboard-operator-deploy.yaml operators-pinned/
    

    Исходные манифесты в каталоге operators/ остаются без изменений.

  2. В каждом скопированном файле найдите объект с kind: Deployment и добавьте в его раздел spec.template.spec параметр nodeSelector с меткой роли оператора. Например, для aa-operator-deploy.yaml:

    kind: Deployment
    metadata:
      name: aa-operator-aa-manager
    spec:
      template:
        spec:
          nodeSelector:
            aa.astra/gateway: "true"
    

    Здесь приведены только поля, которые определяют место вставки. Параметр nodeSelector необходимо добавить на одном уровне с параметром containers, остальное содержимое объекта остается прежним. Значение "true" необходимо заключить в кавычки, так как значение метки – строка.

  3. Убедитесь, что селектор добавлен во все пять файлов:

    grep -A1 'nodeSelector:' operators-pinned/*.yaml
    

    Ожидаемый результат: команда выводит для каждого файла строку nodeSelector: и следующую за ней метку роли.

  4. Примените измененные манифесты:

    kubectl apply -f operators-pinned/
    
  5. Проверьте, что селекторы попали в объекты Deployment и что поды операторов работают на узлах своих ролей:

    kubectl -n astra-automation get deployments \
       -o custom-columns=NAME:.metadata.name,NODE_SELECTOR:.spec.template.spec.nodeSelector
    kubectl -n astra-automation get pods -o wide
    

    Поды операторов aa-operator, ac-operator, pah-operator и eda-operator должны находиться в состоянии 2/2 Running, а под dashboard-operator – в состоянии 1/1 Running, так как он содержит один контейнер. Столбец NODE должен содержать узлы соответствующих ролей.

Селекторы в манифесте приложения#

Для размещения компонентов платформы предназначены параметры node_selector в манифесте AstraAutomation. Оператор aa-operator передает их в ресурсы компонентов, а операторы компонентов – в объекты Deployment и StatefulSet. Блок spec.dashboard целиком становится разделом spec отдельного ресурса Dashboard (dashboard.astra-automation.ru/v1alpha1), который создает aa-operator.

Параметр

Тип значения

Что закрепляет

spec.api.node_selector

Словарь

Под шлюза платформы.

spec.database.node_selector

Словарь

Общую PostgreSQL платформы.

spec.redis.node_selector

Словарь

Общий Redis платформы.

spec.controller.node_selector

Строка YAML

Поды Automation Controller.

spec.controller.web_node_selector

Строка YAML

Под web Automation Controller.

spec.controller.task_node_selector

Строка YAML

Под task Automation Controller.

spec.hub.node_selector

Строка YAML

Все поды Private Automation Hub, включая его Redis, кроме пода импортера контента.

spec.eda.<component>.node_selector

Словарь

Компонент Event-Driven Automation. Селектор необходимо задавать отдельно для каждого компонента: api, ui, event_stream, default_worker, activation_worker, worker, scheduler, redis и database.

spec.dashboard.dashboard.node_selector

Словарь

Под Automation Dashboard. Число реплик задает параметр spec.dashboard.dashboard.replicas.

spec.dashboard.database.node_selector

Словарь

PostgreSQL Automation Dashboard.

spec.dashboard.redis.node_selector

Словарь

Redis Automation Dashboard.

Предупреждение

У Automation Controller и Private Automation Hub селектор задают строкой YAML в блочном скаляре |, а у шлюза, общих PostgreSQL и Redis, компонентов Event-Driven Automation и Automation Dashboard – словарем:

controller:
  node_selector: |
    aa.astra/controller: "true"
api:
  node_selector:
    aa.astra/gateway: "true"

Ошибку в типе значения обнаруживают разные проверки:

  • Строку вместо словаря в параметрах api, database и redis сервер API Kubernetes отвергает при применении манифеста, например:

    The AstraAutomation "aa-demo" is invalid: spec.api.node_selector: Invalid value: "string": spec.api.node_selector in body must be of type object: "string"
    
  • Словарь вместо строки в блоках controller и hub сервер API принимает, так как в определении ресурса AstraAutomation блоки controller, hub, eda и dashboard допускают произвольные поля (x-kubernetes-preserve-unknown-fields). Примерно через две минуты оператор aa-operator добавляет ресурсу AstraAutomation условие Failure со значением True и сообщением unknown playbook failure. Оператор прерывает согласование: селекторы компонентов остаются прежними, а дочерние ресурсы дальше по цепочке оператор не обновляет.

Если у ресурса AstraAutomation появилось условие Failure, проверьте тип значения пробным изменением ресурса компонента на сервере, например для Automation Controller:

kubectl -n astra-automation patch acs ac-demo --type merge \
   -p '{"spec":{"node_selector":{"aa.astra/controller":"true"}}}' --dry-run=server

При неверном типе значения команда выводит причину: spec.node_selector in body must be of type string: "object".

Пример манифеста приложения для базовой топологии без доступа в интернет с закреплением всех компонентов:

---
apiVersion: aa.astra-automation.ru/v1alpha1
kind: AstraAutomation
metadata:
  name: aa-demo
  namespace: astra-automation
spec:
  image_pull_policy: IfNotPresent
  # Шлюз платформы: словарь
  api:
    replicas: 1
    node_selector:
      aa.astra/gateway: "true"
  # Общие PostgreSQL и Redis платформы: словари
  database:
    node_selector:
      aa.astra/db: "true"
  redis:
    node_selector:
      aa.astra/db: "true"
  # Automation Controller: строки YAML
  controller:
    disabled: false
    name: ac-demo
    replicas: 1
    image_pull_policy: IfNotPresent
    ee_pull_credentials_secret: "ac-ee-pull-secret"
    default_ee_image: "aa-demo.example.com/aa-2.1/aa-full-ee:latest"
    control_plane_execution_environment: "aa-demo.example.com/aa-2.1/aa-control-ee:latest"
    control_plane_ee_image: registry.astra.ru/aa/aa-control-ee:2.1
    node_selector: |
      aa.astra/controller: "true"
    task_node_selector: |
      aa.astra/controller: "true"
    web_node_selector: |
      aa.astra/controller: "true"
  # Private Automation Hub: строка YAML, действует на все поды Hub
  hub:
    disabled: false
    name: pah-demo
    image_pull_policy: IfNotPresent
    storage_type: File
    file_storage_access_mode: ReadWriteMany
    file_storage_size: "40Gi"
    file_storage_storage_class: longhorn
    offline_content_loader:
      enabled: true
      image_name: registry.astra.ru/aa/k8s-hub-content-importer:2.1
      namespace: aa-2.1
    node_selector: |
      aa.astra/hub: "true"
    api:
      replicas: 1
    content:
      replicas: 1
    web:
      replicas: 1
    worker:
      replicas: 1
    redis:
      replicas: 1
  # Event-Driven Automation: словарь у каждого компонента
  eda:
    disabled: false
    name: eda-demo
    image_pull_policy: IfNotPresent
    default_de_image: "aa-demo.example.com/aa-2.1/aa-full-de:latest"
    api:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    ui:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    event_stream:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    default_worker:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    activation_worker:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    worker:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    scheduler:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    redis:
      replicas: 1
      node_selector:
        aa.astra/eda: "true"
    database:
      node_selector:
        aa.astra/eda: "true"
  # Automation Dashboard: словарь у каждого компонента
  dashboard:
    ingress_type: ingress
    ingress_class_name: nginx
    dashboard:
      replicas: 1
      node_selector:
        aa.astra/dashboard: "true"
    database:
      node_selector:
        aa.astra/dashboard: "true"
    redis:
      node_selector:
        aa.astra/dashboard: "true"
  ingress_type: Ingress
  ingress_class_name: nginx
#  ingress_tls_secret: aa-tls-secret
#  public_base_url: https://aa-demo.example.com
#  hostname: aa-demo.example.com

По сравнению с исходным манифестом пример содержит следующие изменения:

  • селектор узлов у каждого компонента;

  • блок dashboard с селекторами узлов для самого Automation Dashboard, его PostgreSQL и Redis;

  • явное число реплик у каждого компонента (см. Число реплик);

  • параметр image_pull_policy: IfNotPresent на уровне приложения и в блоках компонентов, при котором под использует образ, уже загруженный на узел;

  • файловое хранилище Private Automation Hub вместо S3: параметры storage_type: File, file_storage_access_mode, file_storage_size и file_storage_storage_class без параметра object_storage_s3_secret (см. переход на файловое хранилище).

Блок dashboard не содержит параметр hostname, так как интерфейс Automation Dashboard доступен по пути /dashboard на хосте платформы. Секрет из параметра ee_pull_credentials_secret необходимо создать в формате, описанном в разделе Секрет для доступа к образам среды исполнения. Остальные параметры, включая параметры публикации через Ingress, необходимо заполнять так же, как в исходном манифесте. Примените манифест, как описано в инструкции по развертыванию.

Число реплик#

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

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

Для распределения реплик компонента по нескольким узлам выполните следующие действия:

  1. Назначьте метку роли нескольким узлам.

  2. Загрузите образы роли на каждый из этих узлов.

  3. Задайте в манифесте приложения нужное число реплик компонента.

Закрепление подов заданий#

Группа контейнеров default создает для каждого задания Automation Controller отдельный под. Селекторы манифеста приложения на эти поды не действуют, поэтому без дополнительной настройки планировщик размещает под задания на любом рабочем узле. Узел, на котором работает под задания, загружает из Private Automation Hub образ среды исполнения этого задания.

Для закрепления подов заданий за узлами выполните следующие действия:

  1. Откройте окно Группы исполняющих узлов (Instance Groups).

  2. В строке группы контейнеров default нажмите кнопку перехода в окно изменения данных о группе.

  3. Включите настройку Настроить спецификацию пода (Customize pod spec).

  4. В поле Переопределение спецификации пода (Pod spec override) добавьте в раздел spec параметр nodeSelector с меткой узлов для заданий, например:

    spec:
      nodeSelector:
        aa.astra/controller: "true"
    
  5. Сохраните изменения.

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

Для заданий можно использовать узлы роли controller или выделить им отдельную роль с собственной меткой. Спецификацию пода можно также изменить через API в поле pod_spec_override группы контейнеров: PATCH /api/controller/v2/instance_groups/<id>/.

Важно

Под задания загружает образ среды исполнения из Private Automation Hub через Ingress, поэтому containerd на узлах заданий должен доверять сертификату Ingress. Без настроенного доверия к сертификату корпоративного или собственного удостоверяющего центра containerd прерывает загрузку образа с ошибкой x509: certificate signed by unknown authority. Для настройки доверия на каждом узле заданий создайте каталог /etc/containerd/certs.d/<ingress_fqdn>/ с файлами hosts.toml и ca.crt и укажите этот каталог в параметре config_path файла /etc/containerd/config.toml. Порядок действий приведен в разделе Способ 2. Отдельный файл hosts.toml, другие способы – в разделе Доверие containerd на рабочих узлах Kubernetes.

Проверка результата#

Проверьте размещение подов платформы:

kubectl -n astra-automation get pods -o wide

Пример вывода для четырех рабочих узлов с ролями из примера выше (часть столбцов опущена):

NAME                                                    READY   STATUS      NODE
aa-demo-dashboard-5b9df95c69-p8whv                      2/2     Running     worker-4.example.com
aa-demo-dashboard-postgres-15-0                         1/1     Running     worker-4.example.com
aa-demo-dashboard-redis-5d64ddcbbc-ngwxc                1/1     Running     worker-4.example.com
aa-demo-gateway-6bfb554c9-fzn2m                         2/2     Running     worker-2.example.com
aa-demo-postgres-15-0                                   1/1     Running     worker-3.example.com
aa-demo-redis-0                                         1/1     Running     worker-3.example.com
aa-operator-aa-manager-6d7d4799d8-zxjt2                 2/2     Running     worker-2.example.com
ac-demo-migration-3.1.1-h6b7p                           0/1     Completed   worker-1.example.com
ac-demo-task-7fcf6b647-r9smk                            4/4     Running     worker-1.example.com
ac-demo-web-7f797cbf94-p9jf6                            3/3     Running     worker-1.example.com
ac-operator-ac-manager-5fb5b566d4-bsxdm                 2/2     Running     worker-1.example.com
dashboard-operator-dashboard-manager-56989856cf-vlt9t   1/1     Running     worker-4.example.com
eda-demo-activation-worker-8669d8c7ff-k4vhj             1/1     Running     worker-3.example.com
eda-demo-api-7d5d77bb89-7j86g                           3/3     Running     worker-3.example.com
eda-demo-default-worker-69fcf77b45-4whdj                1/1     Running     worker-3.example.com
eda-demo-event-stream-5684b9d554-8lns2                  2/2     Running     worker-3.example.com
eda-demo-postgres-15-0                                  1/1     Running     worker-3.example.com
eda-demo-redis-77b785cb78-rm8hc                         1/1     Running     worker-3.example.com
eda-demo-scheduler-6fcf645b64-nrxjr                     1/1     Running     worker-3.example.com
eda-operator-eda-manager-5c9cb75df8-bl7rv               2/2     Running     worker-3.example.com
pah-demo-api-75bc8bd5fb-qv564                           1/1     Running     worker-2.example.com
pah-demo-content-c8cd8ff8f-t2np8                        1/1     Running     worker-2.example.com
pah-demo-importer-6fbfe27cfa27-fkfhs                    0/1     Completed   worker-2.example.com
pah-demo-redis-7c5b8dcfbb-xtszd                         1/1     Running     worker-2.example.com
pah-demo-web-6bc9c6497f-rf949                           1/1     Running     worker-2.example.com
pah-demo-worker-77cf99449f-6rz7p                        1/1     Running     worker-2.example.com
pah-operator-pah-manager-7fb69df6c-tjjxw                2/2     Running     worker-2.example.com

Каждый под должен находиться на узле своей роли. Отдельные поды для компонентов ui и worker Event-Driven Automation в выводе отсутствуют. Под импортера контента Private Automation Hub в примере оказался на узле роли hub, так как образ импортера загружен только на этот узел, однако инструкция закрепление этого пода не гарантирует.

Проверьте селекторы в объектах платформы:

kubectl -n astra-automation get deployments,statefulsets \
   -o custom-columns=NAME:.metadata.name,NODE_SELECTOR:.spec.template.spec.nodeSelector

У каждого объекта столбец NODE_SELECTOR должен содержать метку роли компонента.

Для проверки подов заданий запустите любое задание и определите узел, на котором создан его под:

kubectl get pods -A -o wide -w | grep automation-job

Под задания должен появиться на узле с меткой, указанной в спецификации пода группы контейнеров default.

Если под находится в состоянии ImagePullBackOff или ErrImagePull, определите узел и образ командой kubectl -n astra-automation describe pod <pod_name>. Затем проверьте метки этого узла и загрузите на него недостающий образ.