Объект NCI (NodeConfigItem)

Обзор

NodeConfigItem (NCI) — кластерный кастомный ресурс Kubernetes, который описывает переиспользуемый шаблон конфигурации Linux-узлов. В NCI администратор задаёт, что нужно настроить на узлах, на какие узлы распространить конфигурацию и с каким приоритетом объединять её с другими NCI.

NCI используется для декларативного управления настройками ОС и компонентов Kubernetes на узлах: NTP, containerd, sysctl, пакетами, репозиториями, файлами, пользователями, systemd-юнитами, kubelet, kube-apiserver и другими разделами. Настройка NCI в графическом интерфейсе, поля форм и расширенные примеры манифестов описаны на странице Конфигурация узлов (NCI).

NCI не применяется к узлу напрямую. Модуль shturval-node-config выбирает подходящие объекты NCI по селекторам, записывает их имена в NodeConfig (NC) конкретных узлов, а демон std (shturvald) на узле объединяет конфигурацию, применяет её и отражает результат в статусе NodeConfig.

Когда использовать NCI

Используйте NCI, когда нужно:

  • единообразно настроить группу узлов по лейблам, например все Worker-узлы или только узлы с GPU;
  • подключить репозитории пакетов или приватные registry для containerd;
  • установить, удалить или заблокировать пакеты ОС;
  • создать файлы, директории, локальных пользователей и SSH-ключи;
  • настроить sysctl, systemd-юниты, NTP, сертификаты, параметры ядра, SELinux, swap или iptables;
  • управлять параметрами kubelet и kube-apiserver на выбранных узлах;
  • разделить базовую конфигурацию и специализированные overrides через priority.

Для просмотра статуса применения конкретного NCI на узле используйте страницу узла или статус соответствующего NodeConfig.

Идентификация ресурса

Параметр Значение
API group node.shturval.tech
API version v1beta2
Kind NodeConfigItem
Plural nodeconfigitems
Short name nci
Scope Cluster
Finalizer node.shturval.tech/finalizer
Webhook Mutating webhook /mutate-node-shturval-tech-nodeconfig для create/update

Общий обзор API-групп и кастомных ресурсов платформы см. в разделе Кастомные ресурсы в платформе.

Жизненный цикл

  1. Администратор создаёт или изменяет NodeConfigItem.
  2. Mutating webhook добавляет служебные аннотации username и updatedDate для внешнего пользователя. Сервисный аккаунт оператора пропускается без мутации.
  3. NodeConfigItemReconciler выбирает NodeConfig, labels которых соответствуют spec.nodeconfigselector.
  4. Имя NCI добавляется в NodeConfig.spec.nodeconfigitems каждого выбранного узла.
  5. Демон std на узле читает локальный init NCI и кеш NCI из кластера, сохраняет кеш в /etc/std/caches/<name>.json, объединяет конфигурации в /etc/std/merged.json и применяет результат.
  6. Результат применения записывается в NodeConfig.status.ncistate.
  7. NodeConfigItem.status показывает агрегированную картину: какие NodeConfig выбраны, какие уже обновлены и готов ли NCI в целом.

Связь NCI, NodeConfig, дрейна и перезагрузки подробно описана в жизненном цикле модуля shturval-node-config.

Структура

Минимальный пример:

apiVersion: node.shturval.tech/v1beta2
kind: NodeConfigItem
metadata:
  name: nodeconfigitem-sample
spec:
  nodeconfigselector:
    kubernetes.io/os: linux
  priority: 100
  files:
    - path: /etc/shturval/test
      type: directory
      mode: "0600"

metadata.name — имя NCI. После создания имя объекта не изменяется. Чтобы заменить NCI с другим именем, создайте новый объект и удалите старый, учитывая ограничения удаления и rollback.

Поля spec

JSON-поле Тип Обязательное Назначение
nodeconfigselector map[string]string Да Выбирает NodeConfig по labels.
priority uint Нет Приоритет merge. Чем больше значение, тем выше приоритет.
kubeversion string Нет Целевая версия Kubernetes для upgrade.
repositories []Repo Нет Подключение или удаление репозиториев пакетов ОС.
packages []Package Нет Установка, удаление и блокировка пакетов ОС.
files []File Нет Создание и изменение файлов и директорий.
ntp *NTP Нет NTP-серверы и часовой пояс.
certificates []Certificate Нет Доверенные сертификаты ОС.
runtimecfg *ContainerRuntimeConfig Нет Конфигурация containerd: registry, hosts.toml, config.toml.
kernelarguments []KernelArgument Нет Параметры загрузчика ядра.
kernelmodules []KernelModule Нет Автозагрузка и blacklist модулей ядра.
sysctl *Sysctl Нет Параметры sysctl в формате ключ-значение.
systemdunits []SystemdUnitConfig Нет Запуск, остановка и автозагрузка systemd-юнитов.
users []User Нет Локальные Linux-пользователи, группы и SSH-ключи.
swap *Swap Нет Включение или отключение swap.
iptables *Iptables Нет Flush iptables.
selinux *Selinux Нет Режим SELinux.
kubecerts *KubeCerts Нет Период ротации системных сертификатов Kubernetes.
kubelet *Kubelet Нет Подмножество параметров kubelet.
kubeapi *KubeAPI Нет Параметры kube-apiserver на Control Plane узлах.

Полный перечень полей форм и примеров для разделов spec см. на странице Конфигурация узлов (NCI).

Селектор узлов

spec.nodeconfigselector — обязательная карта key: value. Контроллер выбирает те NodeConfig, у которых есть все labels, указанные в селекторе NCI, с теми же значениями. Формат близок к nodeSelector Kubernetes.

Пример выбора всех Linux Worker-узлов:

spec:
  nodeconfigselector:
    kubernetes.io/os: linux
    node-role.kubernetes.io/worker: ""

Если селектор соответствует нескольким узлам, один NCI будет добавлен в NodeConfig.spec.nodeconfigitems каждого подходящего узла. Для выбора узлов используйте стандартные labels Kubernetes или пользовательские labels. Примеры настройки labels есть на странице Конфигурация узлов (NCI).

Приоритет и merge

На одном узле может быть несколько NCI. Перед применением демон объединяет их в итоговую конфигурацию /etc/std/merged.json.

Алгоритм merge:

  1. NCI сортируются по возрастанию spec.priority.
  2. При равном priority раньше идёт NCI с более ранним CreationTimestamp.
  3. Если timestamp совпадает, порядок определяется именем.
  4. Merge выполняется от меньшего приоритета к большему, поэтому NCI с большим priority перезаписывает конфликтующие значения.

Практический вывод: базовые NCI задавайте с меньшим приоритетом, а специализированные overrides — с большим. При одинаковом priority позже созданный NCI может переопределить конфликтующие значения ранее созданного NCI; если время создания совпало, последним станет NCI с лексикографически большим именем.

nodeconfigselector и priority не попадают в итоговую конфигурацию узла. Они используются только для выбора узлов и порядка объединения.

Статус NodeConfigItem

NodeConfigItem.status управляется оператором и показывает агрегированный результат распределения NCI по выбранным узлам.

JSON-поле Тип Описание
selectednodeconfigs []string Имена NodeConfig, выбранных по nodeconfigselector.
updatednodeconfigs []string Имена NodeConfig, где соответствующий NCI имеет состояние applied.
ready bool true, если все выбранные NodeConfig обновлены и список выбранных не пуст.
applied string Строка вида <updated>/<selected>, например 3/3.

NodeConfigItem.status.ready означает, что NCI доведён до состояния applied в NodeConfig.status.ncistate. Это не самостоятельный rollback-механизм и не отдельная проверка каждого файла, пакета или параметра вне логики агента. Для диагностики конкретного узла смотрите NodeConfig.status.ncistate; его поля описаны в справочнике NodeConfig (NC).

Порядок применения на узле

После merge демон применяет разделы конфигурации в фиксированном порядке:

  1. swap
  2. selinux
  3. iptables
  4. users
  5. files
  6. kubeapi
  7. sysctl
  8. kernelarguments
  9. kubecerts
  10. certificates
  11. repositories
  12. packages
  13. runtime
  14. kernelmodules
  15. systemdunits
  16. ntp
  17. kubelet

kubeversion применяется отдельной логикой Kubernetes upgrade: сначала NCI добавляется только на bootstrap/init node, после его обновления — на остальные выбранные узлы.

Основные разделы конфигурации

Репозитории и пакеты

repositories управляет сетевыми репозиториями пакетов ОС. Репозиторий идентифицируется по address; state: present подключает репозиторий, state: absent удаляет его из конфигурации пакетного менеджера.

packages устанавливает, удаляет и блокирует пакеты. Пакет идентифицируется по name; для удаления используйте state: absent, для запрета автообновления — setlock: true.

spec:
  repositories:
    - name: internal
      state: present
      address: https://repo.example.com/os
      keyurl: https://repo.example.com/RPM-GPG-KEY
      checkgpg: true
      checkssl: true
  packages:
    - name: nginx
      state: present
      setlock: true
    - name: old-agent
      state: absent
      ignorelock: true

Файлы, сертификаты и пользователи

files создаёт или изменяет файлы и директории. Идентификатор merge — пара path и type. Удаление файлов и директорий через NCI не предусмотрено.

certificates добавляет доверенные сертификаты ОС. Для удаления сертификата используйте exist: false.

users создаёт или изменяет Linux-пользователей, группы и SSH-ключи. SSH-ключи объединяются и дедуплицируются. Поля для удаления пользователя или группы через NCI нет.

spec:
  files:
    - path: /etc/shturval/config.env
      type: file
      mode: "0640"
      owner: root
      group: root
      content: |
                ENABLED=true
  certificates:
    - name: corp-ca
      url: https://ca.example.com:443
      exist: true
  users:
    - username: admin
      homedir: /home/admin
      shell: /bin/bash
      group: admin
      sshkeys:
        - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAExample admin@example

Container Runtime

runtimecfg управляет containerd: registry hosts, config.toml, sandbox image, cgroup driver и произвольными секциями. Для настройки приватных registry используйте runtimecfg.registries[].license; это YAML-поле записывается как Authorization header в hosts.toml. Подробный сценарий подключения приватного registry см. в разделе Настройка приватного реестра.

spec:
  runtimecfg:
    registries:
      - name: registry.example.com
        host: https://registry.example.com
        capabilities: [pull, resolve]
        license: "Basic dXNlcjpwYXNzd29yZA=="
        insecure: false

Для HTTP registry обязательно указывайте insecure: true:

spec:
  runtimecfg:
    registries:
      - name: registry.local
        host: http://registry.local:5000
        capabilities: [pull, resolve]
        insecure: true

Для настройки config.toml используйте runtimecfg.configSections, а не deprecated-поля pauseimage и cgroupdriver:

spec:
  runtimecfg:
    configSections:
      - path: 'plugins."io.containerd.grpc.v1.cri"'
        params:
          - key: sandbox_image
            value: registry.k8s.io/pause:3.10
      - path: 'plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options'
        params:
          - key: SystemdCgroup
            value: true

Секции и параметры configSections можно удалять через exist: false, но root section с path: "" удалить нельзя. Для удаления лишних registry-директорий, отсутствующих в spec, используйте runtimecfg.removeunused: true.

Sysctl, systemd и настройки ОС

sysctl задаёт параметры ядра в формате строковых значений. Они сохраняются в /etc/sysctl.d/9999-shturval-items.conf.

systemdunits запускает, останавливает, включает или отключает автозапуск systemd-юнитов. Если active или enabled не заданы, значение трактуется как true.

kernelarguments управляет параметрами загрузчика ядра; для удаления параметра используйте exist: false. kernelmodules включает автозагрузку модулей или помещает их в blacklist. При одновременном autoload: true и blacklist: true blacklist имеет приоритет.

spec:
  sysctl:
    param:
      net.ipv4.ip_forward: "1"
      vm.max_map_count: "262144"
  systemdunits:
    - name: chronyd.service
      active: true
      enabled: true
  kernelmodules:
    - name: br_netfilter
      autoload: true
    - name: nouveau
      autoload: false
      blacklist: true

ntp задаёт NTP-серверы и timezone. Для применения NTP-настроек на узле должен быть установлен и включён сервис ntpd или chronyd; пример установки сервиса через packages и systemdunits приведён на странице Конфигурация узлов (NCI).

Kubernetes-компоненты

kubecerts задаёт период ротации системных сертификатов Kubernetes. Значение rotationperiod должно быть от 7 до 365 дней, значение по умолчанию — 30.

kubeapi управляет отдельными параметрами kube-apiserver: Admission Plugins, Feature Gates, OIDC, Audit Policy, requests/limits, priority и шифрованием Secrets. Применяйте этот раздел к Control Plane узлам.

spec:
  nodeconfigselector:
    node-role.kubernetes.io/control-plane: ""
  kubeapi:
    admissionplugins:
      AlwaysPullImages: true
      PodSecurityPolicy: false

kubelet содержит подмножество параметров KubeletConfiguration: CPU и memory policies, reservedSystemCPUs, systemReserved, maxPods, featureGates, TLS, частоты синхронизации, registry pull limits и другие поля. Для сценариев CPU Pinning см. Резервирование CPU для etcd.

spec:
  kubelet:
    cpuManagerPolicy: static
    memoryManagerPolicy: Static
    topologyManagerPolicy: single-numa-node
    reservedSystemCPUs: "0-1"
    maxPods: 100

Ограничения и важное поведение

Удаление NCI не откатывает изменения

NCI не является rollback-механизмом. Если NCI удалён или перестал подходить по selector, оператор убирает его имя из NodeConfig, но уже применённые изменения ОС остаются на узле: созданные пользователи, файлы, репозитории, пакеты, runtime-настройки и другие элементы не откатываются автоматически.

Чтобы изменить состояние, создайте новый NCI или измените существующий NCI с нужными параметрами. При конфликте используйте более высокий priority. Если изменение требует перезагрузки, её координирует shturval-node-config; ручное управление описано в разделе Защитить узлы от автоматического перезапуска.

Удаление доступно только через явные команды

Подтверждённые способы описать целевое состояние «объекта не должно быть»:

  • packages[].state: absent;
  • runtimecfg.removeunused: true для лишних registry-директорий.

Не найдено подтверждённой команды удаления для Linux-пользователя или группы через users, файла или директории через files, systemd unit-файла через systemdunits и произвольной registry-записи без removeunused.

Пустые строки часто не очищают значения

В merge для repositories, packages, files, users, kernelmodules и runtime registries многие строковые поля обновляются только если новое значение непустое. Поэтому пустой строкой обычно нельзя очистить ранее заданное значение через более приоритетный NCI.

Валидация не покрывает все ошибки

Основная валидация задана OpenAPI-схемой CRD. Отдельные бизнес-ограничения могут проявиться только при применении на узле, например:

  • некорректный runtimecfg.configSections.path;
  • попытка удалить root section containerd;
  • HTTP registry без insecure: true;
  • конфликт kubelet-полей, например maxParallelImagePulls вместе с serializeImagePulls: true.

Просмотр и диагностика

# Список всех NCI в кластере
kubectl get nodeconfigitem
kubectl get nci

# Краткий вывод с приоритетом, applied/ready и selector
kubectl get nodeconfigitem -o wide

# Полный манифест NCI
kubectl get nodeconfigitem <nci-name> -o yaml

# Список NodeConfig, где видно применение на уровне узлов
kubectl get nodeconfig

# Статус конкретного узла
kubectl get nodeconfig <node-name> -o yaml

Для общей диагностики оператора и демона используйте раздел Диагностика модуля shturval-node-config. В интерфейсе список NCI и отношение применённых узлов к выбранным отображаются на странице Конфигурация узлов (NCI), а состояние применения NCI на конкретном узле — на странице узла.

Быстрая памятка

  • Используйте apiVersion: node.shturval.tech/v1beta2.
  • Всегда задавайте spec.nodeconfigselector: это обязательное поле выбора узлов.
  • Разделяйте базовую и специализированную конфигурацию по priority.
  • Для containerd предпочитайте runtimecfg.configSections, а не deprecated pauseimage и cgroupdriver.
  • Для private registry используйте YAML-поле license, а не authorization.
  • Для HTTP registry указывайте insecure: true.
  • Не рассчитывайте, что удаление NCI откатит изменения на узле.
  • Для удаления используйте только явные команды state: absent, exist: false или removeunused: true, если они поддержаны соответствующим разделом.
  • Для диагностики конкретного узла смотрите NodeConfig.status.ncistate, а не только kubectl get nci.