Установка KeyStack LCM¶
LCM (Lifecycle Manager) поддерживает два варианта установки:
single-node — на одном узле;
multi-node — в режиме высокой доступности на трёх Control-узлах, образующих Kubernetes-кластер на базе k0s. Этот режим обеспечивает отказоустойчивость самой системы управления жизненным циклом платформы.
В процессе установки поддерживается возможность задать в качестве хранилища данных сторонний CSI-драйвер. С требованиями к стороннему CSI можно ознакомиться в разделе Хранилище данных LCM.
Требования к инфраструктуре¶
Перед началом установки убедитесь, что инфраструктура подготовлена в соответствии со следующими требованиями:
Серверы
Для развёртывания в режиме высокой доступности требуется три LCM-сервера. Минимальные требования к каждому:
CPU — не менее 32 ядер.
RAM — не менее 64 ГБ.
Два SSD-диска (системный и дополнительный), не менее 240 ГБ каждый.
Диски
На каждом LCM-сервере требуется наличие следующих дисков:
sda— системный диск с заранее установленной ОС.sdb— дополнительный диск без разделов; по умолчанию задействуется встроенным CSI (Ceph OSD).Предупреждение
Дополнительный диск не должен быть локальным и не должен использовать Ceph в качестве бэкенда.
Сеть
Должны быть настроены сетевые интерфейсы: IP-адреса, маски подсети, маршруты на каждом сервере.
В DNS должны быть зарегистрированы следующие записи:
vault.<lcm_name>.vm.lab.itkey.comnexus.<lcm_name>.vm.lab.itkey.comdocker.<lcm_name>.vm.lab.itkey.com(указывает наnexus_vip)netbox.<lcm_name>.vm.lab.itkey.comgitlab.<lcm_name>.vm.lab.itkey.comgrafana.<lcm_name>.vm.lab.itkey.comdocs.<lcm_name>.vm.lab.itkey.coms3.<lcm_name>.vm.lab.itkey.comvmauth.<lcm_name>.vm.lab.itkey.com(указывает наgrafana_vip)<lcm_name>-lcm-01.vm.lab.itkey.com<lcm_name>-lcm-02.vm.lab.itkey.com<lcm_name>-lcm-03.vm.lab.itkey.com
В сети должны быть зарезервированы следующие VIP-адреса (их значения потребуются при настройке lcm-config.yaml):
mgt_vip_addressvault_vipnexus_vipnetbox_vipgitlab_vipgrafana_vipdocs_vips3_vip
Пользователь и доступ по SSH
Требуется наличие непривилегированного пользователя (например,
kolla) на каждом сервере.На первом LCM-узле должна быть сгенерирована SSH-ключевая пара; публичный ключ — добавлен в
~/.ssh/authorized_keysна втором и третьем узлах.Пользователю должно быть предоставлено право выполнять команды от суперпользователя без пароля (
NOPASSWDв sudoers).
Синхронизация времени
На всех серверах должна быть настроена синхронизация времени (NTP). Расхождение времени между узлами может привести к нестабильной работе Kubernetes и Ceph.
Swap
Swap должен быть отключён на всех серверах, поскольку этого требует Kubernetes:
$ sudo swapoff -a
$ sudo sed -i '/swap/d' /etc/fstab
Серверы
Для развёртывания в режиме single-node требуется один LCM-сервер. Минимальные требования:
CPU — не менее 32 ядер.
RAM — не менее 64 ГБ.
Два SSD-диска (системный и дополнительный), не менее 240 ГБ каждый.
Диски
Требуется наличие следующих дисков:
sda— системный диск с заранее установленной ОС.sdb— дополнительный диск без разделов; по умолчанию задействуется встроенным CSI (NFS Driver).Предупреждение
Дополнительный диск не должен быть локальным и не должен использовать Ceph в качестве бэкенда.
Сеть
Должны быть настроены сетевые интерфейсы: IP-адрес, маска подсети, маршруты.
В DNS должны быть зарегистрированы следующие записи:
vault.<lcm_name>.vm.lab.itkey.comnexus.<lcm_name>.vm.lab.itkey.comdocker.<lcm_name>.vm.lab.itkey.com(указывает наnexus_vip)netbox.<lcm_name>.vm.lab.itkey.comgitlab.<lcm_name>.vm.lab.itkey.comgrafana.<lcm_name>.vm.lab.itkey.comdocs.<lcm_name>.vm.lab.itkey.coms3.<lcm_name>.vm.lab.itkey.comvmauth.<lcm_name>.vm.lab.itkey.com(указывает наgrafana_vip)<lcm_name>-lcm-01.vm.lab.itkey.com
В сети должны быть зарезервированы следующие VIP-адреса (их значения потребуются при настройке lcm-config.yaml):
mgt_vip_addressvault_vipnexus_vipnetbox_vipgitlab_vipgrafana_vipdocs_vips3_vip
Пользователь и доступ по SSH
Требуется наличие непривилегированного пользователя (например,
kolla).Должен быть настроен SSH-доступ по ключу для пользователя.
Пользователю должно быть предоставлено право выполнять команды от суперпользователя без пароля (
NOPASSWDв sudoers).
Синхронизация времени
На сервере должна быть настроена синхронизация времени (NTP).
Swap
Swap должен быть отключён, поскольку этого требует Kubernetes:
$ sudo swapoff -a
$ sudo sed -i '/swap/d' /etc/fstab
Установка инсталлятора¶
Установка выполняется на первом LCM-узле.
Примечание
Все команды выполняются от имени непривилегированного пользователя (например, kolla). Не распаковывайте дистрибутив в домашнюю директорию — как правило, там недостаточно свободного места.
Подключитесь по SSH к первому LCM-узлу.
Скопируйте на него дистрибутив KeyStack любым удобным способом.
Распакуйте дистрибутив платформы:
$ tar -xf installer-k0s-ks2026.2-sberlinux-offline $ cd installer $ tar -xf lcm-k0s-ks2026.2.tar.gz
Откройте файл конфигурации:
$ vi lcm-k0s/lcm-config.yaml
Настройте параметры установки.
Предупреждение
Параметры, перечисленные ниже, необходимо задать корректно до запуска этапов установки k0s кластера и инфраструктуры. Способов устранить ошибку в значении любого из них без полного повторного развёртывания нет — в этом случае потребуется полная переустановка платформы с чистой установкой ОС на каждом узле (ручная очистка артефактов k0s и Ceph нецелесообразна).
Основные параметры:
ssh_username— имя непривилегированного пользователя, от которого выполняется установка.control_plane— список FQDN узлов control plane кластера k0s (LCM-узлов). Имена узлов должны быть зарегистрированы в DNS — инсталлятор использует их для определения IP-адресов при формировании конфигурации.domain_name— доменная зона LCM, в которой регистрируются все сервисы LCM. Зона не привязана к конкретному региону: один экземпляр LCM может обслуживать несколько регионов.loadbalancer_ip_range— диапазон адресов MetalLB, из которого выделяются VIP-адреса сервисов LCM. Должен входить в управляющую подсеть и включать все зарезервированные VIP-адреса.mgt_vip_address— VIP-адрес управления Kubernetes (k0s).vault_loadbalancer_ip— VIP-адрес сервиса Vault (используется приinstall_vault: true).nexus_loadbalancer_ip,netbox_loadbalancer_ip,gitlab_loadbalancer_ip,grafana_loadbalancer_ip,docs_loadbalancer_ip,s3_loadbalancer_ip— VIP-адреса соответствующих сервисов LCM. Каждый адрес должен входить вloadbalancer_ip_rangeи быть зарегистрирован в DNS в зонеdomain_name.keepalived_passwd— пароль для keepalived (максимум 8 символов).install_ironic— управление сервисом Ironic для работы с Baremetal-узлами. При первичной установке укажитеfalse. Ironic можно включить позже — см. раздел Включение сервиса Ironic (опционально).
Если планируется использование стороннего CSI-драйвера вместо встроенного хранилища, дополнительно задайте следующие параметры:
enable_user_csi— возможность использования стороннего CSI-драйвера вместо встроенного хранилища. Задайте в данном параметре значение"true".user_csi_storage_class— имя StorageClass стороннего CSI. Все компоненты LCM (GitLab, NetBox, Nexus3, Garage) будут использовать это имя при создании томов хранилища. StorageClass должен поддерживать режимы доступа ReadWriteMany (RWX) и ReadWriteOnce (RWO) и быть установлен как StorageClass по умолчанию в кластере.user_csi_namespace— namespace, в котором развёрнут CSI-драйвер. Указанный namespace автоматически добавляется в исключения политик Kyverno, что позволяет подам CSI запрашивать привилегированный доступ к узлу. Убедитесь, что значение задано корректно, иначе поды CSI-драйвера будут заблокированы политиками Kyverno с ошибкой следующего вида:cannot set allowPrivilegeEscalation to false and privileged to true.
Установка самого CSI-драйвера в этом случае будет выполняться после этапа установки инфраструктуры.
Пример конфигурации:
# Настройка K0s ssh_username: "kolla" control_plane: - "<lcm_name>-lcm-01.vm.lab.itkey.com" - "<lcm_name>-lcm-02.vm.lab.itkey.com" - "<lcm_name>-lcm-03.vm.lab.itkey.com" mgt_vip_address: "<mgt_vip_address>" ... # Сеть и DNS domain_name: "<lcm_name>.vm.lab.itkey.com" loadbalancer_ip_range: "<loadbalancer_ip_range>" vault_loadbalancer_ip: "<vault_vip>" vault_fqdn: "vault.<lcm_name>.vm.lab.itkey.com" nexus_loadbalancer_ip: "<nexus_vip>" nexus_fqdn: "nexus.<lcm_name>.vm.lab.itkey.com" docker_fqdn: "docker.<lcm_name>.vm.lab.itkey.com" netbox_loadbalancer_ip: "<netbox_vip>" netbox_fqdn: "netbox.<lcm_name>.vm.lab.itkey.com" gitlab_loadbalancer_ip: "<gitlab_vip>" gitlab_fqdn: "gitlab.<lcm_name>.vm.lab.itkey.com" grafana_loadbalancer_ip: "<grafana_vip>" grafana_fqdn: "grafana.<lcm_name>.vm.lab.itkey.com" vmauth_fqdn: "vmauth.<lcm_name>.vm.lab.itkey.com" s3_loadbalancer_ip: "<s3_vip>" s3_fqdn: "s3.<lcm_name>.vm.lab.itkey.com" docs_loadbalancer_ip: "<docs_vip>" docs_fqdn: "docs.<lcm_name>.vm.lab.itkey.com"
# Настройка K0s ssh_username: "kolla" control_plane: - "<lcm_name>-lcm-01.vm.lab.itkey.com" nfs_server_ip: "<lcm-01-ip-address>" nfs_server_share: "/mnt/NFS_EXPORT/k0s" ... # Сеть и DNS domain_name: "<lcm_name>.vm.lab.itkey.com" loadbalancer_ip_range: "<loadbalancer_ip_range>" vault_loadbalancer_ip: "<vault_vip>" vault_fqdn: "vault.<lcm_name>.vm.lab.itkey.com" nexus_loadbalancer_ip: "<nexus_vip>" nexus_fqdn: "nexus.<lcm_name>.vm.lab.itkey.com" docker_fqdn: "docker.<lcm_name>.vm.lab.itkey.com" netbox_loadbalancer_ip: "<netbox_vip>" netbox_fqdn: "netbox.<lcm_name>.vm.lab.itkey.com" gitlab_loadbalancer_ip: "<gitlab_vip>" gitlab_fqdn: "gitlab.<lcm_name>.vm.lab.itkey.com" grafana_loadbalancer_ip: "<grafana_vip>" grafana_fqdn: "grafana.<lcm_name>.vm.lab.itkey.com" vmauth_fqdn: "vmauth.<lcm_name>.vm.lab.itkey.com" s3_loadbalancer_ip: "<s3_vip>" s3_fqdn: "s3.<lcm_name>.vm.lab.itkey.com" docs_loadbalancer_ip: "<docs_vip>" docs_fqdn: "docs.<lcm_name>.vm.lab.itkey.com"
Остальные параметры (размеры томов, настройки мониторинга) можно оставить по умолчанию или настроить согласно требованиям.
Примечание
В файле
lcm-config.yamlдоступны дополнительные параметры для настройки мониторинга и сервиса Ironic:Мониторинг: параметры для настройки Grafana, Prometheus и алертинга можно найти в секции мониторинга файла конфигурации. По умолчанию включён базовый мониторинг компонентов LCM.
Ironic: после первичной установки платформы сервис Ironic можно активировать (см. раздел Включение сервиса Ironic (опционально)). Ironic необходим для управления Baremetal-узлами через IPMI/Redfish.
Сохраните и закройте файл.
Запустите установку:
$ ./installer.sh lcm-k0s/lcm-config.yaml
Скрипт установит необходимые пакеты в систему и выполнит настройку ОС. На этом этапе применяются все необходимые настройки ядра и устанавливаются системные зависимости.
Примечание
Изменение настроек SELinux требует перезагрузки узлов после выполнения данного шага.
Настройка NFS (Single-node)¶
Примечание
Данный этап выполняется только для single-node при использовании встроенного хранилища (NFS CSI Driver). При использовании стороннего CSI-драйвера пропустите этот шаг.
Проверьте, что операционная система установлена на диск
sda, а дискsdbне содержит разделов:$ lsblkОжидаемый вывод:
Если пустым оказался диск
sda, замените значение переменнойDISKв скрипте сsdbнаsda.Выполните скрипт настройки NFS:
#!/usr/bin/env bash set -e DISK="/dev/sdb" sudo parted $DISK --script mklabel gpt sudo parted $DISK --script mkpart primary ext4 0% 100% sudo partprobe $DISK sudo mkfs.ext4 -F ${DISK}1 sudo mkdir -p /mnt/NFS_EXPORT UUID=$(sudo blkid -s UUID -o value ${DISK}1) grep -q "$UUID" /etc/fstab || echo "UUID=$UUID /mnt/NFS_EXPORT ext4 defaults 0 0" | sudo tee -a /etc/fstab >/dev/null sudo mount -a sudo mkdir -p /mnt/NFS_EXPORT/k0s sudo chown -R nobody:nobody /mnt/NFS_EXPORT/k0s sudo chmod 777 /mnt/NFS_EXPORT/k0s grep -q "/mnt/NFS_EXPORT/k0s" /etc/exports || echo "/mnt/NFS_EXPORT/k0s *(rw,sync,no_subtree_check,no_root_squash)" | sudo tee -a /etc/exports >/dev/null sudo exportfs -ra sudo systemctl enable --now rpcbind sudo systemctl enable --now nfs-server
Подключение к внешнему Vault (опционально)¶
По умолчанию (install_vault: true) LCM развёртывает встроенный Vault, а cert-manager выпускает TLS-сертификаты сервисов через внутренний центр сертификации. Дополнительная настройка не требуется.
При необходимости LCM можно подключить к внешнему Vault (или совместимому secrets manager). В этом режиме внешний Vault используется как хранилище секретов и, опционально, как backend центра сертификации для cert-manager. Задайте install_vault: false и настройте параметры подключения в lcm-config.yaml до запуска этапов установки.
Единственный поддерживаемый метод аутентификации — AppRole. Идентификатор роли задаётся в конфигурации, а secret-id передаётся через переменную окружения при запуске этапа установки инфраструктуры (см. ниже).
install_vault: false
vault_addr: "https://vault.example.com" # HTTPS-эндпоинт внешнего Vault
vault_namespace: "" # namespace Vault Enterprise / SecMan; пусто — root
vault_app_role_id: "<role-id>" # role-id AppRole
vault_ca_bundle_file: "vault-server-ca.pem" # CA, подписавший TLS-сертификат Vault; PEM рядом с lcm-config.yaml
Где:
vault_addr— URL HTTPS-эндпоинта внешнего Vault.vault_namespace— namespace Vault Enterprise или secrets manager (заголовокX-Vault-Namespace); пусто — root namespace.vault_app_role_id— идентификатор AppRole; secret-id передаётся отдельно черезVAULT_SECRET_ID.vault_ca_bundle_file— файл с CA, которым подписан TLS-сертификат HTTPS-эндпоинта Vault (PEM, в одном каталоге сlcm-config.yaml). Заполняется и для публичного CA.
Получить CA-сертификат сервера Vault:
$ openssl s_client -showcerts -connect <vault-host>:443 </dev/null 2>/dev/null \
| sed -n '/BEGIN CERTIFICATE/,/END CERTIFICATE/p' \
| awk '/BEGIN CERTIFICATE/{n++} n>1' > vault-server-ca.pem
Хранение секретов¶
Внешний Vault используется как KV-хранилище секретов региона. Задайте mount и префикс пути:
vault_engine: "secret_v2" # mount KV v2
vault_prefix: "deployments/gitlab.example.com" # префикс пути; по умолчанию deployments/<gitlab_fqdn>
Выпуск TLS-сертификатов через Vault PKI¶
При install_vault: false cert-manager может выпускать TLS-сертификаты сервисов через PKI-движок внешнего Vault. Включите vault_pki_enabled и укажите mount, роль и корневой CA:
vault_pki_enabled: true
vault_pki: "pki_int" # mount pki, где выписываются сертификаты
vault_role_pki: "cert-manager" # роль pki, выписывающая сертификаты
vault_pki_ca_bundle_file: "vault-pki-ca.pem" # корневой CA Vault PKI (PEM рядом с lcm-config.yaml)
Чтобы получить корневой CA Vault PKI, используйте следующие команды:
$ curl -sf --cacert vault-server-ca.pem \
https://<vault-host>/v1/pki_int/ca_chain -o vault-pki-ca.pem
Флаг -f завершает curl с ошибкой при HTTP-ответе 4xx/5xx, а --cacert проверяет TLS-соединение с Vault.
$ curl -sf --cacert vault-server-ca.pem \
-H "X-Vault-Namespace: <vault-namespace>" \
https://<vault-host>/v1/pki_int/ca_chain -o vault-pki-ca.pem
Флаг -f завершает curl с ошибкой при HTTP-ответе 4xx/5xx, а --cacert проверяет TLS-соединение с Vault. Заголовок X-Vault-Namespace указывает пространство имён, в котором размещён PKI-движок.
Проверьте, что в файл записана валидная цепочка сертификатов. Эндпоинт ca_chain может вернуть несколько сертификатов (промежуточный и корневой), поэтому выведите все:
$ openssl crl2pkcs7 -nocrl -certfile vault-pki-ca.pem | openssl pkcs7 -print_certs -noout
Параметры генерируемых сертификатов (ключ и subject) задаются отдельно:
vault_pki_key_algorithm: "RSA"
vault_pki_key_encoding: "PKCS1"
vault_pki_key_size: 2048
vault_pki_subject_organization: "<организация>"
vault_pki_subject_organizational_unit: "<подразделение>"
vault_pki_subject_street: "<адрес>"
vault_pki_subject_country: "<код страны>"
Здесь:
vault_pki_key_algorithm,vault_pki_key_encoding,vault_pki_key_size— алгоритм, кодировка и длина ключа сертификата.vault_pki_subject_organization,vault_pki_subject_organizational_unit,vault_pki_subject_street,vault_pki_subject_country— поля subject (O, OU, STREET, C) выпускаемого сертификата.
Важно
Значения ключа и subject должны быть разрешены ролью Vault PKI (vault_role_pki). Если роль ограничивает эти параметры, cert-manager не сможет выписать сертификат.
Передача secret-id при установке¶
Secret-id AppRole не хранится в lcm-config.yaml. Его необходимо передать через переменную окружения VAULT_SECRET_ID при запуске задачи установки инфраструктуры:
$ VAULT_SECRET_ID=<secret-id> task k8s-install-infra-multi-node
$ VAULT_SECRET_ID=<secret-id> task k8s-install-infra-single-node
Важно
Это команда этапа установки инфраструктуры, который выполняется после этапа установки k0s кластера. Не запускайте её до выполнения задачи k0s-install-multi-node (или k0s-install-single-node для single-node) — установка инфраструктуры требует уже развёрнутого Kubernetes-кластера. Приведённая здесь команда показывает только способ передачи secret-id; выполняйте её в порядке, описанном в разделе Этап установки инфраструктуры.
cert-manager создаст из secret-id Kubernetes-секрет vault-approle в namespace cert-manager и будет использовать его для аутентификации во внешнем Vault.
Этап установки k0s кластера¶
На первом этапе устанавливается Kubernetes-кластер. В режиме multi-node при использовании встроенного хранилища дополнительно развёртывается система хранения данных Ceph.
Для первичной установки или переустановки этапа выполните:
$ cd lcm-k0s $ task k0s-install-multi-node
$ cd lcm-k0s $ task k0s-install-single-node
Для переустановки этапа в случае необходимости повторите выполнение команды.
Проверьте состояние узлов кластера. Должен отобразиться список узлов в статусе
Ready:$ kubectl get nodes NAME STATUS ROLES AGE VERSION <lcm_name>-lcm-01.vm.lab.itkey.com Ready control-plane 7m14s v1.35.3+k0s.0 <lcm_name>-lcm-02.vm.lab.itkey.com Ready control-plane 6m41s v1.35.3+k0s.0 <lcm_name>-lcm-03.vm.lab.itkey.com Ready control-plane 6m41s v1.35.3+k0s.0
$ kubectl get nodes NAME STATUS ROLES AGE VERSION <lcm_name>-lcm-01.vm.lab.itkey.com Ready control-plane 7m14s v1.35.3+k0s.0
Этап установки инфраструктуры¶
Запустите установку инфраструктуры:
$ task k8s-install-infra-multi-node
$ task k8s-install-infra-single-node
Для переустановки этапа в случае необходимости повторите выполнение команды.
Примечание
При подключении к внешнему Vault (
install_vault: false) передайте secret-id AppRole через переменнуюVAULT_SECRET_ID, напримерVAULT_SECRET_ID=<secret-id> task k8s-install-infra-multi-node. Подробнее — в разделе Подключение к внешнему Vault (опционально).Проверьте успешное завершение установки:
Проверьте состояние OSD-дисков Ceph. Должны отобразиться три пода в статусе
Running:$ kubectl get pod -l app.kubernetes.io/name=ceph-osd -n ceph-cluster NAME READY STATUS RESTARTS AGE rook-ceph-osd-0-6cb69b89b6-2n5fc 2/2 Running 0 60s rook-ceph-osd-1-cf7476bcf-vnlj6 2/2 Running 0 60s rook-ceph-osd-2-54884b7c48-2s746 2/2 Running 0 59s
Если отображается
No resources found in ceph-cluster namespace., ожидайте сборки кластера. Скорость сборки зависит от скорости дисков — в среднем процесс занимает около 15 минут. Дождитесь появления необходимого статуса, прежде чем переходить к следующему шагу.Проверьте состояние кластера Ceph. Должен отобразиться кластер в фазе
Readyсо статусом здоровьяHEALTH_WARN:$ kubectl get -n ceph-cluster cephclusters.ceph.rook.io NAME DATADIRHOSTPATH MONCOUNT AGE PHASE MESSAGE HEALTH EXTERNAL FSID ceph-cluster /var/lib/rook 3 8m43s Ready Cluster created successfully HEALTH_WARN c597b53f-6c23-4b33-8d24-3e750e2a0f5b
В single-node окружении Rook-Ceph не устанавливается — вместо него используется NFS CSI Driver. Убедитесь, что NFS-сервер доступен по адресу, указанному в
nfs_server_ip.$ showmount -e <lcm-01-ip-address> Export list for <lcm-01-ip-address>: /mnt/NFS_EXPORT/k0s *
Установка пользовательского CSI (опционально)¶
Примечание
Данный этап выполняется только при enable_user_csi: "true" в lcm-config.yaml. Параметры конфигурации стороннего CSI (enable_user_csi, user_csi_storage_class, user_csi_namespace) должны быть заданы заранее — до запуска этапов установки.
Убедитесь, что namespace, в котором будет развёрнут CSI-драйвер, задан в параметре
user_csi_namespaceвlcm-config.yaml. Этот namespace автоматически добавляется в исключения политик Kyverno, поскольку подам CSI-драйвера обычно требуется привилегированный доступ к узлу (host-доступ). Если значение задано некорректно, поды CSI-драйвера будут заблокированы политиками Kyverno с ошибкой следующего вида:cannot set allowPrivilegeEscalation to false and privileged to true.Установите CSI-драйвер согласно документации выбранного драйвера.
Важно
В k0s путь к данным kubelet —
/var/lib/k0s/kubelet, а не стандартный/var/lib/kubelet. Укажите этот путь в соответствующем параметре при установке CSI-драйвера (обычноkubeletDirили аналогичный).Создайте StorageClass с именем, совпадающим со значением
user_csi_storage_classизlcm-config.yaml. Этот единый StorageClass используется helm-чартами всех компонентов LCM (GitLab, NetBox, Nexus3, Garage) при создании томов хранилища, поэтому отдельные StorageClass для каждого компонента создавать не требуется. StorageClass должен удовлетворять следующим требованиям:имя совпадает со значением
user_csi_storage_class;поддерживает режимы доступа ReadWriteMany (RWX) и ReadWriteOnce (RWO);
установлен как StorageClass по умолчанию в кластере (аннотация
storageclass.kubernetes.io/is-default-class: "true").
Пример конфигурации:
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: <user_csi_storage_class> annotations: storageclass.kubernetes.io/is-default-class: "true" provisioner: <имя драйвера> # из документации CSI-драйвера reclaimPolicy: Delete volumeBindingMode: WaitForFirstConsumer
Этап установки приложений¶
Подключение к Active Directory¶
Для интеграции ролевой модели KeyStack с централизованным каталогом организации выполните настройку подключения к Active Directory или LDAP-серверу. Подробные сведения о ролевой модели и принципах её работы описаны в разделе Ролевая модель KeyStack.
Для корректной интеграции требуется:
LDAP-сервер с поддержкой TLS (LDAPS).
Доступ к серверу исключительно по DNS-имени (для корректной проверки TLS-сертификатов).
Корневой сертификат центра сертификации в формате PEM.
Учётная запись для привязки (bind) с правами чтения каталога.
Создайте файл с корневым сертификатом. Файл должен быть в формате PEM, иметь имя, указанное в параметре
ldap_ca_cert_file, и находиться в том же каталоге, что иlcm-config.yaml. Если корневой CA выдаёт сертификаты через промежуточные центры, поместите в файл всю цепочку (корневой и промежуточные сертификаты, каждый в блокеBEGIN/END CERTIFICATE):$ cat <<-EOF > ~/installer/lcm-k0s/ldap-root-cert.crt -----BEGIN CERTIFICATE----- <содержимое промежуточного сертификата> -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- <содержимое корневого сертификата> -----END CERTIFICATE----- EOF $ chmod 600 ~/installer/lcm-k0s/ldap-root-cert.crt
Проверьте, что в файл записаны все сертификаты цепочки, а не только первый:
$ openssl crl2pkcs7 -nocrl -certfile ~/installer/lcm-k0s/ldap-root-cert.crt | openssl pkcs7 -print_certs -noout
Убедитесь, что этой цепочкой проверяется TLS-сертификат вашего сервера LDAP (значения берутся из
ldap_hostиldap_port):$ openssl s_client -connect <ldap_host>:<ldap_port> -servername <ldap_host> \ -CAfile ~/installer/lcm-k0s/ldap-root-cert.crt -verify_return_error </dev/null 2>/dev/null \ | grep "Verify return code"
Команда должна вывести
Verify return code: 0 (ok). Любой другой код означает, что цепочка не проверяет сертификат сервера (неполная цепочка, не тот CA) или имяldap_hostотсутствует в SAN сертификата.Откройте файл конфигурации:
$ vi ~/installer/lcm-k0s/lcm-config.yaml
Настройте блок Active Directory:
# Active Directory ldap_enable: "true" ldap_host: "dc-01.domain.loc" ldap_port: 636 ldap_ca_cert_file: "ldap-root-cert.crt" ldap_bind_dn: "CN=test,CN=Users,DC=domain,DC=loc" ldap_user_search_basedn: "CN=Users,DC=domain,DC=loc" ldap_group_search_basedn: "CN=Users,DC=domain,DC=loc" ldap_reader_group_dn: "CN=Администраторы домена,CN=Users,DC=domain,DC=loc" ldap_auditor_group_dn: "CN=Администраторы домена,CN=Users,DC=domain,DC=loc" ldap_admin_group_dn: "CN=Администраторы домена,CN=Users,DC=domain,DC=loc"
Здесь:
ldap_enable— включение интеграции с LDAP ("true"или"false").ldap_host— FQDN сервера Active Directory. В SAN сертификата должно быть указано это имя.ldap_port— порт LDAP.ldap_ca_cert_file— имя файла с корневым сертификатом ЦА в формате PEM.ldap_bind_dn— DN учётной записи для привязки к LDAP.ldap_user_search_basedn— базовый DN для поиска пользователей.ldap_group_search_basedn— базовый DN для поиска групп.ldap_reader_group_dn,ldap_auditor_group_dn,ldap_admin_group_dn— DN групп AD, соответствующих ролям KeyStack.
Создайте Kubernetes-секреты для привязки к LDAP. Способ зависит от того, включена ли автоматическая ротация паролей (см. Автоматическая ротация паролей LDAP (опционально)):
Введите пароль от LDAP в окружение:
$ export ldap_bind_password='<пароль учётной записи привязки>'
Задайте режим установки в переменной
MODE(multi-nodeилиsingle-node— в соответствии с выбранным режимом) и создайте секреты.Секрет для NetBox:
$ export MODE=multi-node $ export netbox_namespace=$(helmfile -e "${MODE}" -l name=netbox list --output json | yq -p json '.[0].namespace') $ kubectl create namespace "${netbox_namespace}" --dry-run=client -o yaml | kubectl apply -f - $ kubectl create -n "${netbox_namespace}" secret generic netbox-ldap \ --from-literal=email_password='' \ --from-literal=secret_key=$(openssl rand -base64 48 | tr -d '\n') \ --from-literal=ldap_bind_password="${ldap_bind_password}" \ --from-literal=ldap_bind_dn='<DN учётной записи привязки>'
Секрет для GitLab:
$ export gitlab_namespace=$(helmfile -e "${MODE}" -l name=gitlab list --output json | yq -p json '.[0].namespace') $ kubectl create namespace "${gitlab_namespace}" --dry-run=client -o yaml | kubectl apply -f - $ kubectl create -n "${gitlab_namespace}" secret generic gitlab-ldap \ --from-literal=ldap_bind_password="${ldap_bind_password}" \ --from-literal=bind_dn='<DN учётной записи привязки>'
Важно
Ключ
bind_dnв секретеgitlab-ldapобязателен: GitLab читает DN привязки из секрета, и без этого ключа под не запустится.Секреты
netbox-ldapиgitlab-ldapвручную не создаются — пароль и DN синхронизируются из Vault приhelmfile applyи периодически ротируются CronJob. Предварительно убедитесь, что:используется внешний Vault (
install_vault: false);в Vault настроен LDAP Secrets Engine (mount
vault_ldap) с двумя static-role на каждое приложение —<mask>-1и<mask>-2;в namespace
cert-managerесть секретvault-approleс ключомsecret-id. Приvault_pki_enabled: trueон создаётся автоматически, при другом значении необходимо создать его вручную:$ kubectl create secret generic vault-approle \ --from-literal=secret-id=<secret-id> -n cert-manager
Затем задайте параметры ротации в
lcm-config.yaml— см. Автоматическая ротация паролей LDAP (опционально).
Подробная информация о ролях KeyStack и их привилегиях описана в разделах Настройка интеграции с LDAP/AD и Описание ролевой модели.
Автоматическая ротация паролей LDAP (опционально)¶
При enable_lcm_ad_passwords_rotation: true LCM синхронизирует пароли учётных записей привязки GitLab и NetBox из внешнего Vault и периодически ротирует их с помощью CronJob. Функция работает только с внешним Vault (install_vault: false); при install_vault: true ротация отключается.
Для каждого приложения в Vault LDAP Secrets Engine должны существовать две static-role с именами <mask>-1 и <mask>-2 (рабочая и резервная). CronJob проверяет TTL неактивной роли и при достижении порога ротирует её пароль, после чего helmfile переключает приложение на обновлённую учётную запись.
Настройте блок в lcm-config.yaml:
enable_lcm_ad_passwords_rotation: true
lcm_exp_threshold_days: 30 # ротировать, если до истечения TTL роли осталось меньше порога (дней)
lcm_pass_rotation_job_sch: "0 7 * * *" # cron-расписание CronJob (ежедневно в 07:00)
vault_secman: false # true → SecMan (endpoint creds/), false → Vault (endpoint static-cred/)
vault_ldap: "ldap" # mount-путь LDAP Secrets Engine в Vault
vault_ldap_static_endpoint: "" # авто: static-cred (Vault) или creds (SecMan); задать при нестандартном пути
lcm_gitlab_ldap_roles_mask: "gitlab-ldap" # базовое имя ролей GitLab: <mask>-1, <mask>-2
lcm_netbox_ldap_roles_mask: "netbox-ldap" # базовое имя ролей NetBox: <mask>-1, <mask>-2
# Явные имена ролей (опционально); если заданы — маска игнорируется
lcm_gitlab_ldap_role_a: ""
lcm_gitlab_ldap_role_b: ""
lcm_netbox_ldap_role_a: ""
lcm_netbox_ldap_role_b: ""
# DN учётной записи привязки (аккаунт -1) соответствующего приложения
ldap_gitlab_bind_dn: "CN=gitlab-ldap-1,CN=Users,DC=domain,DC=loc"
ldap_netbox_bind_dn: "CN=netbox-ldap-1,CN=Users,DC=domain,DC=loc"
Где:
enable_lcm_ad_passwords_rotation— включение ротации паролей LDAP для GitLab и NetBox.lcm_exp_threshold_days— порог TTL в днях; пароль ротируется, если до истечения осталось меньше указанного значения.lcm_pass_rotation_job_sch— расписание CronJob в формате cron.vault_secman— режим хранилища:trueдля SecMan,falseдля Vault.vault_ldap— mount-путь LDAP Secrets Engine в Vault.vault_ldap_static_endpoint— endpoint чтения учётных данных; по умолчанию определяется автоматически.lcm_gitlab_ldap_roles_mask,lcm_netbox_ldap_roles_mask— базовые имена static-role; используются роли<mask>-1и<mask>-2.lcm_gitlab_ldap_role_a/_b,lcm_netbox_ldap_role_a/_b— явные имена ролей, если они не соответствуют шаблону<mask>-1/<mask>-2.ldap_gitlab_bind_dn,ldap_netbox_bind_dn— DN учётной записи привязки (аккаунт-1) соответствующего приложения.
Параметры подключения к Vault (vault_addr, vault_namespace, vault_ca_bundle_file, vault_app_role_id) берутся из общей секции настроек Vault. CronJob аутентифицируется в Vault по AppRole; secret-id хранится в секрете cert-manager/vault-approle.
Примечание
Региональная ротация сервисных учётных записей (через globals.d/REGION.yml и переменные GitLab CI) описана отдельно в разделе Автоматическая ротация пользователей и паролей.
Сбор логов в сторонний сервис (опционально)¶
Откройте файл конфигурации:
$ vi ~/installer/lcm-k0s/lcm-config.yaml
Настройте блоки Внешний Syslog (UDP) и Внешний OpenSearch/Elasticsearch:
# Настройки экспорта логов во внешние системы # Внешний Syslog (UDP) external_syslog_enabled: "true" # Установить в "true", если нужно подключение к syslog external_syslog_endpoint: "syslog.example.com:514" # Адрес:порт syslog сервера # Внешний OpenSearch/Elasticsearch external_opensearch_enabled: "true" # Установить в "true", если нужно подключение к opensearch external_opensearch_endpoint: "https://opensearch.example.com:9200" external_opensearch_username: "admin" # Логин для подключения external_opensearch_password: "" # Пароль для подключения external_opensearch_index: "k8s-logs-%Y.%m.%d" # Паттерн индекса (опционально) external_opensearch_verify_tls: "true" # Включение проверки TLS сертификата external_opensearch_ca_cert_file: "opensearch-ca.crt" # Файл сертификата в формате PEM; должен находиться в той же директории, что и lcm-config.yaml
Index Template OpenSearch¶
Создайте index template в OpenSearch до первой записи логов. Тип flat_object предотвращает mapper_parsing_exception, dynamic_templates обрабатывает поле log как объект или строку в зависимости от пода:
kubernetes.pod_labels,pod_annotations,namespace_labels,node_labels— Vector хранит Kubernetes metadata с точками (app.kubernetes.io/name) как вложенные объекты.log— может быть строкой или JSON-объектом;dynamic_templatesавтоматически выбирает подходящий тип.
curl -sk -u "admin:<пароль>" -X PUT \
"https://<endpoint>/_index_template/k8s-logs-mapping" \
-H 'Content-Type: application/json' -d '{
"index_patterns": ["k8s-logs-*"],
"priority": 300,
"template": {
"settings": {"number_of_replicas": 0},
"mappings": {
"dynamic_templates": [
{
"log_as_object": {
"path_match": "log",
"match_mapping_type": "object",
"mapping": {"type": "flat_object"}
}
},
{
"log_as_string": {
"path_match": "log",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"fields": {"keyword": {"type": "keyword", "ignore_above": 256}}
}
}
}
],
"properties": {
"kubernetes": {
"properties": {
"pod_labels": {"type": "flat_object"},
"pod_annotations": {"type": "flat_object"},
"namespace_labels": {"type": "flat_object"},
"node_labels": {"type": "flat_object"}
}
}
}
}
}
}'
Примечание
Нижеследующие шаги выполняются всегда вне зависимости от необходимости авторизации в Active Directory или сбора логов.
Запустите установку приложений:
$ task k8s-install-apps-multi-node
Предупреждение
Команда ожидает готовности Ceph-кластера перед установкой приложений. Если Ceph ещё не завершил инициализацию OSD (фаза Progressing), команда завершится с ошибкой по таймауту. В этом случае дождитесь, пока кластер перейдёт в фазу Ready:
$ kubectl get -n ceph-cluster cephclusters.ceph.rook.io -w
После перехода в Ready запустите команду повторно.
Примечание
Команда устанавливает:
Vault + Vault Unsealer
GitLab (CNPG PostgreSQL + Redis HA + Gitaly + Garage S3)
Garage (S3-хранилище для GitLab)
NetBox (CNPG PostgreSQL + Redis HA)
Nexus3
Victoria Metrics K8s Stack (Grafana, vmstorage, vmselect, vminsert)
Victoria Logs Cluster
KeyStack Docs
Ironic (если включён)
$ task k8s-install-apps-single-node
Проверка успешного завершения¶
Проверьте список установленных Helm-чартов:
$ helm list -A
Должны отобразиться все компоненты LCM в статусе
deployed:calicocert-managercnpg-operatorexternal-snapshotter-crdgarage(S3-бэкенд для GitLab)gateway-api-crdgitlabistio-baseistio-csristiodkeystack-docskyvernokyverno-policiesmetallbnetboxnexus3redis-ha(для GitLab и NetBox)rook-ceph-clusterrook-ceph-systemsnapshot-controllervaultvault-unsealervlc-clustervmks
calicocert-managercnpg-operatorcsi-driver-nfsexternal-snapshotter-crdgarage(S3-бэкенд для GitLab)gateway-api-crdgitlabistio-baseistio-csristiodkeystack-docskyvernokyverno-policiesmetallbnetboxnexus3snapshot-controllervaultvault-unsealervlc-singlevmks
Проверьте состояние всех подов:
$ kubectl get all -A
Все поды должны быть в статусе
RunningилиCompleted.Проверьте состояние хранилищ:
# S3-кластер Garage: статус нод (3 HEALTHY) и список бакетов kubectl exec -n lcm-garage garage-0 -c garage -- /usr/local/bin/garage status kubectl exec -n lcm-garage garage-0 -c garage -- /usr/local/bin/garage bucket list # Redis HA kubectl get pods -n lcm-gitlab | grep redis
Примечание
Объектное хранилище GitLab (артефакты CI/CD, LFS, uploads, packages, pages, terraform-state, backups) вынесено в отдельный S3-кластер Garage (namespace
lcm-garage), заменивший встроенный MinIO. Redis HA обслуживает кэш GitLab и Sidekiq в режиме multi-node.
Наполнение LCM данными¶
После успешной установки всех компонентов выполните наполнение LCM начальными данными:
$ cd ..
$ bash upload.sh lcm-k0s/lcm-config.yaml
На каждый запуск скрипта создаётся лог-файл в формате upload_<дата>_<время>.log.
Настройка ролевой модели в GitLab и NetBox¶
Ролевая модель в GitLab и NetBox настраивается автоматически при включении интеграции с LDAP (см. раздел Ролевая модель KeyStack).
Важно
При включении интеграции с LDAP и ролевой модели учётная запись root в GitLab блокируется. Для автоматизированных операций в GitLab используется технический пользователь ks-admin. Пароль и персональный токен доступа (PAT) пользователя ks-admin сохраняются в Vault по пути secret_v2 / deployments / <LCM FQDN> / secrets / accounts.
После включения ролевой модели доступ к интерфейсам GitLab и NetBox получают пользователи с ролями admin, security_auditor и reader. Пользователи с ролями member, operator_vm, app_operator и os_operator не получают доступ к этим интерфейсам.
Если требуется дополнительная настройка, обратитесь к разделам Ролевая модель в NetBox и Ролевая модель в GitLab в Руководстве администратора.
Включение сервиса Ironic (опционально)¶
Сервис Ironic обеспечивает provisioning baremetal-узлов по протоколам IPMI/Redfish с загрузкой по сети (PXE). При первичной установке рекомендуется оставить install_ironic: false и включить Ironic после развёртывания основных компонентов LCM.
Сетевые требования¶
Ironic использует выделенную сеть provisioning (PXE). Перед включением убедитесь, что подготовлено следующее:
На каждом LCM-узле есть отдельный сетевой интерфейс, подключённый к PXE-сети.
Выделен VIP-адрес для Ironic API (
ironic_ip_address) в подсети provisioning. Адрес управляется keepalived на интерфейсе provisioning.В DNS зарегистрирована запись
ironic.<lcm_name>.vm.lab.itkey.com→ironic_ip_address.
Подготовка самих baremetal-серверов описана в разделе Подготовка baremetal-узлов для установки KeyStack.
Настройка параметров¶
Откройте файл lcm-config.yaml и задайте параметры Ironic:
install_ironic: true # включение сервиса Ironic
ironic_interface: "eth2" # интерфейс PXE-сети на LCM-узлах
ironic_network_cidr: "192.168.140.0/24" # подсеть provisioning
ironic_range_begin: "192.168.140.101" # начало диапазона DHCP
ironic_range_end: "192.168.140.250" # конец диапазона DHCP
ironic_dns_address: "192.168.140.254"
ironic_gateway_address: "192.168.140.254"
ironic_ip_address: "192.168.140.100" # VIP Ironic API
ironic_fqdn: "ironic.<lcm_name>.vm.lab.itkey.com"
ironic_keepalived_vrid: 1 # VRRP ID (1–255), уникален в L2-сегменте
ironic_keepalived_passwd: "" # пароль VRRP (≤8 символов); пусто — без аутентификации
Где:
install_ironic— включение сервиса Ironic (trueилиfalse).ironic_interface— сетевой интерфейс PXE-сети на LCM-узлах.ironic_network_cidr— подсеть сети provisioning.ironic_range_begin,ironic_range_end— границы диапазона DHCP для PXE-загрузки.ironic_dns_address,ironic_gateway_address— DNS-сервер и шлюз, выдаваемые узлам по DHCP.ironic_ip_address— VIP-адрес Ironic API.ironic_fqdn— FQDN Ironic API; должен указывать наironic_ip_address.ironic_keepalived_vrid,ironic_keepalived_passwd— параметры VRRP keepalived для VIP Ironic. VRID должен быть уникален в пределах L2-сегмента.
Несколько DHCP-диапазонов (PXE relay)
Если provisioning выполняется в нескольких подсетях (например, через PXE relay по стойкам), задайте дополнительные диапазоны в параметре ironic_dhcp_ranges. В каждом диапазоне обязателен префикс в networkCIDR:
ironic_dhcp_ranges:
- name: pxe-main
networkCIDR: "192.168.140.0/24"
rangeBegin: "192.168.140.101"
rangeEnd: "192.168.140.250"
gatewayAddress: "192.168.140.254"
- name: pxe-rack1
networkCIDR: "192.168.141.0/27"
rangeBegin: "192.168.141.2"
rangeEnd: "192.168.141.29"
gatewayAddress: "192.168.141.30"
Запуск установки¶
Компоненты Ironic относятся к инфраструктурному (ironic-operator, mariadb-operator) и прикладному (ironic, proxy-nginx) этапам. После настройки параметров повторно выполните оба этапа:
$ cd lcm-k0s
$ task k8s-install-infra-multi-node
$ task k8s-install-apps-multi-node
$ cd lcm-k0s
$ task k8s-install-infra-single-node
$ task k8s-install-apps-single-node
При использовании нескольких DHCP-диапазонов (PXE relay) дополнительно настройте статические маршруты к relay-подсетям:
$ task ironic-host-routes
Проверка установки Ironic¶
Убедитесь, что компоненты Ironic развёрнуты, а поды находятся в статусе Running:
$ helm list -n lcm-ironic
$ kubectl get pods -n lcm-ironic