Установка KeyStack LCM в режиме высокой доступности

Данная инструкция описывает установку LCM (Lifecycle Manager) в режиме высокой доступности. В этом режиме LCM развёртывается на трёх Control-узлах, образующих Kubernetes-кластер на базе k0s. Такая архитектура обеспечивает отказоустойчивость самой системы управления жизненным циклом платформы.

Описание базовой установки LCM на одном узле приведено в разделе Установка KeyStack LCM.

Настройка компонента VMHA для обеспечения отказоустойчивости виртуальных машин описана в разделе VMHA — Высокая доступность ВМ.

Примечание

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

  • Новый инсталлятор k0s (описан в данной инструкции) — рекомендуется для новых установок

  • Классический инсталлятор — поддерживается для обеспечения совместимости с существующими установками

Оба варианта будут поддерживаться в переходный период. Выбор инсталлятора зависит от требований вашей инфраструктуры и планов миграции.

Требования к инфраструктуре

Аппаратные требования для HA LCM

Для развёртывания LCM в режиме высокой доступности предъявляются специальные требования к LCM-узлам:

  • Количество узлов: ровно 3 (для обеспечения кворума)

  • Оперативная память: минимум 32 ГБ на узел

  • Процессор: минимум 16 ядер x86-64/AMD64 на узел

  • Дисковая подсистема:

    • Системные диски: 2×500 ГБ SSD в конфигурации RAID 1 для операционной системы и системных компонентов

    • Диск для Ceph: минимум 1×500 ГБ SSD без RAID для распределённого хранилища Ceph

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

    Важно использовать отдельные физические диски для системы и Ceph. Размещение системы и Ceph на одном диске существенно снижает производительность и надёжность кластера.

  • Сетевые интерфейсы: 2×10 ГБ NIC для обеспечения резервирования сетевых подключений

Аппаратные требования для остальных узлов

Требования к остальным типам узлов платформы:

Требование / Тип узла

Controller

Compute

Network

Storage

Обязательность

Да

Да

Да

Нет

Минимальное количество узлов

3

2

1

Оперативная память

256 ГБ

Процессор (ядер)

2×8

2×12

2×8

Архитектура процессора

x86-64 / AMD64

x86-64 / AMD64

x86-64 / AMD64

Место для хранения

2×512 ГБ SSD (RAID 1)

Сетевая карта

2×10 ГБ NIC

2×10 ГБ NIC

2× (2×10 ГБ NIC)

Программные требования

На всех узлах должна быть установлена ОС SberLinux 9.6.2.

Установщик запускается только от непривилегированного пользователя (не root). У пользователя должны быть права для выполнения команд sudo. Установщик не нужно запускать через sudo — он сам выполнит повышенные команды по мере необходимости.

Примечание

Установщик автоматически применяет необходимые настройки ядра ОС и устанавливает требуемые системные пакеты в процессе развёртывания. Все необходимые оптимизации и зависимости включены в дистрибутив и применяются на этапе выполнения installer.sh.

Сетевые требования

Для работы LCM требуется настроенная DNS-зона со следующими записями:

  • gitlab.<доменная зона> — для управления жизненным циклом платформы (CI),

  • nexus.<доменная зона> — для хранения артефактов платформы,

  • vault.<доменная зона> — для хранения паролей и сертификатов,

  • netbox.<доменная зона> — для настроек Baremetal-узлов,

  • minio.<доменная зона> — для работы GitLab,

  • docker.<доменная зона> — для хранения контейнеров,

  • grafana.<доменная зона> — для мониторинга платформы,

  • k0s.<доменная зона> — для API Kubernetes.

Для всех перечисленных записей укажите в DNS один и тот же адрес, который должен совпадать со значением параметра ext_vip_address (VIP-адрес сетевого интерфейса data, обеспечивающего доступ к сервисам LCM и к сети регионов OpenStack), задаваемого на этапе установки инсталлятора.

Также для всех Baremetal-узлов инфраструктуры требуется создать DNS-записи вида <IP-адрес> <имя узла>-rmi.<доменная зона>.

Подготовительные шаги

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

Настройка узлов

  1. Убедитесь, что на всех узлах время в BIOS настроено в зоне UTC. На LCM-узлах под управлением ОС SberLinux выполните команду:

    $ timedatectl set-local-rtc 0
    
  2. Убедитесь, что у непривилегированного пользователя есть права sudo на выполнение команд от root.

  3. Убедитесь, что на всех узлах включена аппаратная виртуализация:

    $ egrep '(vmx|svm)' /proc/cpuinfo
    

    Вывод должен содержать параметр vmx или svm. Если он отсутствует, включите аппаратную виртуализацию в настройках BIOS.

  4. Получите дистрибутив KeyStack одним из вариантов поставки.

  5. Создайте SSH-ключ и разместите его на LCM-узлы, чтобы обеспечить беспарольный вход с первого узла на другие узлы. SSH-ключ размещается для пользователя, который будет указан в параметре ssh_username файла lcm-config.yaml, конфигурация которого производится на этапе установки инсталлятора.

  6. Отключение фаервола и SELinux выполняется инсталлятором автоматически. Если отключение не выполнилось, то необходимо отключить фаервол и SELinux на всех LCM-узлах:

    $ sudo systemctl disable firewalld
    
    Removed "/etc/systemd/system/multi-user.target.wants/firewalld.service".
    Removed "/etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service".
    
    $ sestatus
    
    SELinux status:                 disabled
    
  7. Убедитесь, что на свободных дисках (особенно на дисках, предназначенных для Ceph) нет никакой информации, разделов и других данных. Диски должны быть полностью очищены.

Настройка сетевой связности

  1. На LCM-узле проверьте сетевую связность:

    • Настройте доступ до IPMI всех узлов инфраструктуры, MGMT-интерфейсов и VIP-адресов.

    • Проверьте доступность DHCP-сервера в сети PXE.

    • Включите поддержку Redfish всех узлов инфраструктуры.

  2. Для всех Baremetal-узлов создайте пользователя с правами administrator в IPMI-интерфейсе управления.

Установка инсталлятора

Установка выполняется на первом LCM-узле.

  1. Подключитесь по SSH к первому LCM-узлу.

  2. Скопируйте дистрибутив KeyStack на него любым удобным способом.

  3. Распакуйте дистрибутив платформы:

    $ tar -xf installer-k0s-ks2026.1-sberlinux-offline.tgz
    $ cd installer
    $ tar -xf mutiple-node-k0s-ks2026.1.tar.gz
    
  4. Откройте файл конфигурации:

    $ vi mutiple-node/lcm-config.yaml
    
  5. Настройте параметры установки.

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

    Параметры, перечисленные ниже, необходимо задать корректно до запуска этапов установки order 1 и order 2. Способов устранить ошибку в значении любого из них без полного повторного развёртывания нет — в этом случае потребуется полная переустановка платформы с чистой установкой ОС на каждом узле (ручная очистка артефактов k0s и Ceph нецелесообразна).

    Основные параметры:

    • ssh_username — имя непривилегированного пользователя, от которого выполняется установка.

    • fqdn_cp1, fqdn_cp2, fqdn_cp3 — DNS-имена LCM-узлов.

    • domain_name — доменная зона для региона. В этой зоне должны быть зарегистрированы все сервисы LCM.

    • mgt_vip_address — VIP-адрес управления Kubernetes (K0s).

    • ext_vip_address — VIP-адрес доступа к сервисам LCM (GitLab, NetBox, Vault, Nexus). Должен быть зарегистрирован в DNS в зоне domain_name.

    • keepalived_passwd — пароль для keepalived (максимум 8 символов).

    • ironic_enable — управление сервисом Ironic для работы с Baremetal-узлами. При первичной установке укажите "false". Ironic можно будет включить позже через настройки мониторинга после развёртывания основных компонентов.

    Пример конфигурации:

    ssh_username: "cloud-user"
    fqdn_cp1: "cp-1.testdomain.local"
    fqdn_cp2: "cp-2.testdomain.local"
    fqdn_cp3: "cp-3.testdomain.local"
    domain_name: "testdomain.local"
    mgt_vip_address: "172.16.130.10"
    ext_vip_address: "10.120.120.240"
    keepalived_passwd: "8LJw251u"
    ironic_enable: "false"
    

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

    Примечание

    В файле lcm-config.yaml доступны дополнительные параметры для настройки мониторинга и сервиса Ironic:

    • Мониторинг: параметры для настройки Grafana, Prometheus и алертинга можно найти в секции мониторинга файла конфигурации. По умолчанию включён базовый мониторинг компонентов LCM.

    • Ironic: после первичной установки платформы сервис Ironic можно активировать, изменив параметр ironic_enable на "true" и выполнив обновление конфигурации. Ironic необходим для управления Baremetal-узлами через IPMI/Redfish.

  6. Сохраните и закройте файл.

  7. Запустите установку:

    $ ./installer.sh mutiple-node/lcm-config.yaml
    

    Скрипт установит необходимые пакеты в систему и выполнит настройку ОС. На этом этапе применяются все необходимые настройки ядра и устанавливаются системные зависимости.

    Примечание

    Изменение настроек SELinux требует перезагрузки узлов после выполнения данного шага.

Этап установки order 1

На первом этапе устанавливается Kubernetes-кластер и система хранения данных Ceph.

Для первичной установки или переустановки этапа выполните:

$ cd mutiple-node/
$ ./offline-bundle/installer.sh --order 1

Проверка успешного завершения

  1. Проверьте состояние узлов кластера. Должны отобразиться три узла в статусе Ready:

    $ kubectl get nodes
    
    NAME                            STATUS   ROLES           AGE     VERSION
    <имя>-lcm-01.vm.lab.itkey.com   Ready    control-plane   7m14s   v1.31.5+k0s
    <имя>-lcm-02.vm.lab.itkey.com   Ready    control-plane   6m41s   v1.31.5+k0s
    <имя>-lcm-03.vm.lab.itkey.com   Ready    control-plane   6m41s   v1.31.5+k0s
    

    Примечание

    Скорость сборки Ceph-кластера зависит от скорости дисков. В среднем сборка занимает несколько минут. Дождитесь появления необходимого статуса, прежде чем переходить к следующему шагу.

  2. Проверьте состояние 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
    
  3. Проверьте состояние кластера Ceph. Должен отобразиться кластер в фазе Ready со статусом здоровья HEALTH_WARN:

    $ kubectl get -n ceph-cluster cephclusters.ceph.rook.io
    
    NAME           DATADIRHOSTPATH   MONCOUNT   AGE     PHASE   MESSAGE                      HEALTH
    ceph-cluster   /var/lib/rook     3          8m43s   Ready   Cluster created successfully HEALTH_WARN
    

Подключение к Active Directory

Для интеграции ролевой модели KeyStack с централизованным каталогом организации выполните настройку подключения к Active Directory или LDAP-серверу. Подробные сведения о ролевой модели и принципах её работы описаны в разделе Ролевая модель KeyStack.

Требования к LDAP-серверу

Для корректной работы интеграции требуется:

  • LDAP-сервер с поддержкой TLS (LDAPS).

  • Доступ к серверу исключительно по DNS-имени (для корректной проверки TLS-сертификатов).

  • Корневой сертификат центра сертификации в формате PEM.

  • Учётная запись для привязки (bind) с правами чтения каталога.

Настройка параметров

  1. Откройте файл конфигурации:

    $ vi mutiple-node/lcm-config.yaml
    
  2. Настройте блок Active Directory:

    # Active Directory
    ldap_enable: "true"
    ldap_host: "dc-01.domain.loc"
    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=KeyStack-Readers,CN=Users,DC=domain,DC=loc"
    ldap_auditor_group_dn: "CN=KeyStack-Auditors,CN=Users,DC=domain,DC=loc"
    ldap_admin_group_dn: "CN=KeyStack-Admins,CN=Users,DC=domain,DC=loc"
    

    Где:

    • ldap_enable — включение интеграции с LDAP ("true" или "false").

    • ldap_host — FQDN-имя сервера Active Directory. В SAN сертификата должно быть указано это имя.

    • 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.

  3. Создайте файл с корневым сертификатом CA:

    $ cat > mutiple-node/ca-cert.pem << EOF
    -----BEGIN CERTIFICATE-----
    <содержимое сертификата>
    -----END CERTIFICATE-----
    EOF
    
  4. Сохраните корневой сертификат центра сертификации в формате PEM в файл с именем, указанным в параметре ldap_ca_cert_file:

    $ vi mutiple-node/ldap-root-cert.crt
    

    Вставьте содержимое сертификата и сохраните файл.

Создание секретов для NetBox

Создайте Kubernetes-секрет с паролем для учётной записи привязки к LDAP:

$ export config_file='charts-config.yaml'
$ export netbox_namespace=$(yq '.charts[] | select(.name == "netbox") | .namespace' "$config_file")
$ kubectl create namespace "${netbox_namespace}"
$ kubectl create -n "${netbox_namespace}" secret generic netbox-ldap \
  --from-literal=email_password='' \
  --from-literal=secret_key=$(python3 -c "import secrets; print(secrets.token_urlsafe(50))") \
  --from-literal=ldap_bind_password='<пароль учётной записи ldap bind dn>'

Создание секретов для GitLab

Создайте Kubernetes-секрет с паролем для учётной записи привязки к LDAP:

$ export config_file='charts-config.yaml'
$ export gitlab_namespace=$(yq '.charts[] | select(.name == "gitlab") | .namespace' "$config_file")
$ kubectl create namespace "${gitlab_namespace}"
$ kubectl create -n "${gitlab_namespace}" secret generic gitlab-ldap \
  --from-literal=ldap_bind_password='<пароль учётной записи ldap bind dn>'

Подробная информация о ролях KeyStack и их привилегиях описана в разделах Настройка интеграции с LDAP/AD и Описание ролевой модели.

Этап установки order 2

На втором этапе устанавливаются сервисы LCM: GitLab, NetBox, Nexus, Vault, мониторинг и другие компоненты.

Перед запуском команды убедитесь, что все поды из предыдущего этапа подняты и нет ошибок:

$ kubectl get pod -A

Запустите установку:

$ ./offline-bundle/installer.sh --order 2

Проверка успешного завершения

  1. Проверьте список установленных Helm-чартов:

    $ helm list -A
    

    Должны отобразиться все компоненты LCM в статусе deployed:

    • cert-manager

    • cnpg-operator

    • gitlab

    • ingress-docs

    • ingress-gitlab

    • ingress-netbox

    • ingress-nexus

    • ingress-vault

    • ingress-vmks

    • keystack-documentation

    • kyverno

    • kyverno-policies

    • mariadb-operator

    • mariadb-operator-crds

    • metallb

    • netbox

    • nexus3

    • redis-ha (для GitLab и NetBox)

    • rook-ceph

    • rook-ceph-cluster

    • vault

    • vault-unsealer

    • vlc

    • vmks

  2. Проверьте состояние всех подов:

    $ kubectl get all -A
    

    Все поды должны быть в статусе Running или Completed.

Наполнение LCM данными

После успешной установки всех компонентов выполните наполнение LCM начальными данными:

$ bash upload.sh mutiple-node/charts-config.yaml

На каждый запуск скрипта создаётся лог-файл в формате upload_<дата>_<время>.log.

Обновление LCM

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

  1. Перед обновлением создайте резервную копию конфигурации кластера:

    $ k0sctl backup
    

    Эта операция может занять продолжительное время. Для тестовых окружений этот шаг можно пропустить.

  2. Скопируйте дистрибутив KeyStack на него любым удобным способом.

  3. Распакуйте дистрибутив платформы:

    $ tar -xf installer-k0s-ks2026.1-sberlinux-offline.tgz
    $ cd installer
    $ tar -xf mutiple-node-k0s-ks2026.1.tar.gz
    
  4. Скопируйте значения переменных из текущей инсталляции в новый файл конфигурации:

    $ vi charts-config.yaml
    

    Убедитесь, что все параметры (domain_name, mgt_vip_address, ext_vip_address, настройки LDAP и другие) соответствуют текущей установке.

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

    $ kubectl get pod -A
    
  6. Запустите процесс обновления:

    $ ./offline-bundle/installer.sh --upgrade
    

Резервное копирование LCM

Для хранения резервных копий LCM используется система Velero, которая сохраняет копии в объектном хранилище S3. Предполагается, что S3-совместимое хранилище предоставляется заказчиком.

Ниже описан процесс настройки резервного копирования на примере тестового развёртывания с использованием Minio.

Настройка Minio для тестирования

Для тестирования работы Velero можно развернуть Minio в Docker на отдельном узле.

  1. Создайте файл minio.yml для Docker Compose:

    services:
      minio:
      image: quay.io/minio/minio
      container_name: minio
      ports:
        - "9000:9000"
        - "9001:9001"
      environment:
        MINIO_ROOT_USER: minio
        MINIO_ROOT_PASSWORD: passw0rd
      volumes:
        - "${PWD}/data:/data"
      command: server /data --console-address ":9001"
    
  2. Создайте директорию для данных:

    $ mkdir data
    
  3. Запустите контейнер с Minio:

    $ docker compose -f minio.yml up -d
    
  4. Откройте веб-интерфейс Minio по адресу http://<IP-адрес>:9001 и создайте бакет с именем lcm.

Настройка Velero

  1. Создайте конфигурационный файл авторизации для доступа к Minio:

    $ cat << EOF > ./credentials-velero
    [default]
    aws_access_key_id=minio
    aws_secret_access_key=passw0rd
    EOF
    
  2. Установите Velero в Kubernetes:

    $ velero install \
      --features=EnableCSI \
      --provider aws \
      --plugins docker.io/velero/velero-plugin-for-aws:v1.12.1 \
      --bucket lcm \
      --secret-file ./credentials-velero \
      --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://<IP-адрес>:9000
    

    Где:

    • --plugins — образ плагина для работы с AWS S3 (указан в custom-images-list.txt).

    • --bucket — имя бакета для хранения резервных копий.

    • --backup-location-config — параметры подключения к S3:

      • region — регион S3 (можно посмотреть в GUI Minio).

      • s3Url — URL API Minio.

  3. Удалите файл с учётными данными:

    $ rm -f ./credentials-velero
    

    Настройки доступа хранятся в Kubernetes-секрете.

  4. Проверьте установку Velero. Должен отобразиться под в статусе Running:

    $ kubectl get pod -n velero
    NAME                      READY   STATUS    RESTARTS   AGE
    velero-75b867769d-gxh5s   1/1     Running   0          4h29m
    

Создание резервной копии

Velero поддерживает различные варианты создания резервных копий: по расписанию, с ротацией, с выбором компонентов для включения в копию.

Создайте резервную копию компонента LCM GitLab:

$ velero backup create gitlab --include-namespaces lcm-gitlab

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

NAME     STATUS      ERRORS   WARNINGS   CREATED                          EXPIRES   STORAGE LOCATION   SELECTOR
gitlab   Completed   0        0          2025-02-11 14:40:54 +0000 UTC    29d       default            <none>

Для получения подробной информации о резервной копии выполните:

$ velero backup describe gitlab --details

Восстановление из резервной копии

В качестве примера удалите namespace компонента LCM GitLab:

$ kubectl delete namespaces lcm-gitlab

Примечание

Удаление namespace занимает продолжительное время. Дождитесь завершения операции перед переходом к следующему шагу.

Восстановите namespace из резервной копии:

$ velero restore create --from-backup gitlab

Должно отобразиться состояние:

NAME                    BACKUP   STATUS      STARTED                          COMPLETED                        ERRORS   WARNINGS   CREATED                          SELECTOR
gitlab-20250211151000   gitlab   Completed   2025-02-11 15:10:00 +0000 UTC    2025-02-11 15:12:21 +0000 UTC    0        6          2025-02-11 15:10:00 +0000 UTC    <none>

Если восстановление завершилось с ошибками, изучите логи пода Velero:

$ kubectl logs -n velero <имя пода velero>

Для получения имени пода выполните команду:

$ kubectl get pod -n velero

Восстановление отказавшего LCM-узла

В данном разделе описан порядок действий при отказе одного из трёх LCM-узлов кластера k0s. Кластер спроектирован так, чтобы сохранять работоспособность при потере одного узла, однако для полного восстановления требуется вмешательство администратора.

Примечание

Описанные ниже процедуры применимы только к сценарию отказа одного LCM-узла. При одновременном отказе двух или трёх узлов кворум etcd будет потерян, и кластер станет недоступен. В этом случае восстановите кластер из резервной копии Velero или k0sctl.

Автоматическое поведение кластера при отказе узла

При отказе одного из трёх LCM-узлов кластер автоматически выполняет следующие действия:

  • Keepalived — VIP-адрес управления (mgt_vip_address) мигрирует на один из оставшихся узлов. Доступ к API Kubernetes сохраняется.

  • Управляющий контур — etcd сохраняет кворум (2 из 3 членов). Управляющий контур продолжает обслуживать запросы.

  • Перепланирование подов — Kubernetes автоматически перемещает поды на оставшиеся узлы:

    • Поды с меткой node.kubernetes.io/unreachable вытесняются через 30 секунд.

    • Поды с меткой node.kubernetes.io/not-ready вытесняются через 5 минут.

  • CronJob для StatefulSet — каждые 2 минуты выполняется автоматическая очистка подов Nexus3 и Gitaly, находящихся в состоянии Terminating. Это необходимо для подов с томами типа ReadWriteOnce, которые не могут быть принудительно удалены стандартным механизмом Kubernetes.

  • Базы данных (CNPG) — кластеры PostgreSQL для GitLab, NetBox и Grafana продолжают работу на оставшихся 2 из 3 реплик.

  • Vault (Raft) — сохраняет кворум (2 из 3 членов). Операции чтения и записи секретов продолжают работать.

  • Ceph — помечает OSD отказавшего узла как down. Кластер продолжает работу в деградированном состоянии с 2 из 3 OSD. Данные остаются доступными.

Восстановление узла после перезагрузки

Если отказавший узел восстановился (например, после перезагрузки), выполните проверку его возвращения в кластер.

  1. Убедитесь, что узел вернулся в кластер и находится в статусе Ready:

    $ kubectl get nodes
    

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

  2. Проверьте, что поды успешно распределились по узлам:

    $ kubectl get pod -A -o wide
    

    Убедитесь, что нет подов в статусе Pending, Error или CrashLoopBackOff.

  3. Проверьте состояние кластера Ceph:

    $ kubectl get -n ceph-cluster cephclusters.ceph.rook.io
    

    Дождитесь перехода кластера в состояние HEALTH_OK. Процесс восстановления данных Ceph может занять продолжительное время в зависимости от объёма данных.

  4. Убедитесь, что все три OSD-диска Ceph запущены:

    $ kubectl get pod -l app.kubernetes.io/name=ceph-osd -n ceph-cluster
    

    Все три пода должны быть в статусе Running с индикатором 2/2 в столбце READY.

  5. Проверьте состав кластера etcd:

    $ kubectl exec -n kube-system <etcd-pod> -- etcdctl member list
    

    В списке должны отображаться все 3 члена кластера.

  6. Проверьте состояние кластеров PostgreSQL (CNPG):

    $ kubectl get clusters.postgresql.cnpg.io -A
    

    Все кластеры должны отображать полное количество реплик (3/3) в столбце READY.

  7. Проверьте состояние кластера Vault:

    $ kubectl exec -n lcm-vault vault-0 -- vault status
    

    Убедитесь, что значение Sealed равно false. Повторите команду для vault-1 и vault-2. Если установлен vault-unsealer, разблокировка Vault происходит автоматически в течение 2 минут. В противном случае выполните действия, приведённые в разделе Восстановление Vault.

  8. Проверьте состояние Redis HA:

    $ kubectl get pod -l app=redis-ha -A
    

    Все поды Redis должны быть в статусе Running. Если все поды находятся в роли slave (ошибка Sentinel no-good-slave), выполните ручное повышение — см. Восстановление Redis HA.

Замена неисправного LCM-узла

Если отказавший узел не подлежит восстановлению и требуется его замена (переустановка ОС), выполните действия, приведённые ниже.

Для выполнения процедуры восстановления необходимы файлы инсталлятора и конфигурация кластера. Все перечисленные файлы размещаются на узле, с которого запускается инсталлятор (seed-узел).

Важно

Если отказавший узел являлся seed-узлом (узлом, с которого запускался инсталлятор), необходимо восстановить рабочую директорию инсталлятора на одном из оставшихся узлов.

Необходимые компоненты:

  • Дистрибутив инсталлятора — архив mutiple-node-k0s-<версия>.tar.gz. Загрузите из репозитория артефактов и распакуйте на один из оставшихся узлов. Архив содержит шаблоны, бинарные файлы (k0sctl, k0s, helm, kubectl, yq), Helm-чарты и образы контейнеров (bundle_file.tar).

  • Файл конфигурации lcm-config.yaml — содержит параметры, специфичные для кластера (FQDN узлов, VIP, домен, пароли). Файл входит в дистрибутив со значениями по умолчанию, которые необходимо адаптировать под конкретный кластер перед запуском инсталлятора.

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

    lcm-config.yaml является единственным источником конфигурации кластера. При замене seed-узла убедитесь, что используется файл с корректными значениями для данного кластера (FQDN, VIP, домен). Рекомендуется хранить отредактированный файл в системе контроля версий или создавать резервную копию.

    При утере файла его можно восстановить из данных работающего кластера. Выполните следующие команды с любого узла, имеющего доступ к kubectl:

    • FQDN узлов и ssh_username:

      $ kubectl get nodes -o wide
      $ sudo cat /var/lib/k0s/pki/admin.conf
      

      Если kubectl недоступен, скопируйте /var/lib/k0s/pki/admin.conf как ~/.kube/config.

    • VIP и keepalived_passwd — из конфигурации k0s:

      $ sudo cat /etc/k0s/k0s.yaml | grep -A5 keepalived
      
    • domain_name — из любого Ingress:

      $ kubectl get ingress -A
      
    • loadbalancer_ip_range и IP-адреса сервисов — из MetalLB:

      $ kubectl get ipaddresspools.metallb.io -n metallb-system -o yaml
      
    • Размеры PV:

      $ kubectl get pvc -A -o custom-columns='NAMESPACE:.metadata.namespace,NAME:.metadata.name,SIZE:.spec.resources.requests.storage'
      
    • Флаги установки (vault, ironic, csi и др.) — по наличию namespace/release:

      $ helm list -A
      
    • Параметры LDAP, Syslog, OpenSearch — из values установленных чартов:

      $ helm get values gitlab -n lcm-gitlab
      $ helm get values vlc -n lcm-logging
      
  • SSH-ключ (~/.ssh/id_rsa) — для беспарольного доступа ко всем узлам кластера. Должен присутствовать на seed-узле.

  • Конфигурация kubectl (~/.kube/config) — если утеряна, может быть восстановлена командой k0sctl kubeconfig с использованием файла k0sctl.yaml, либо скопирована из файла /var/lib/k0s/pki/admin.conf с любого работающего контроллера.

Файлы k0sctl.yaml и charts-config.yaml не нужно восстанавливать вручную — они автоматически генерируются инсталлятором из шаблонов и lcm-config.yaml.

Подготовка нового узла

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

    1. Установите ОС SberLinux.

    2. Настройте непривилегированного пользователя с правами sudo.

    3. Разместите SSH-ключ для беспарольного доступа с seed-узла.

    4. Отключите фаервол и SELinux.

    5. Настройте синхронизацию времени.

    6. Очистите диски, предназначенные для Ceph. После переустановки ОС диск может содержать файловую систему (например, ephemeral), которую необходимо удалить:

      $ sudo wipefs -a /dev/<диск_для_ceph>
      $ sudo sgdisk --zap-all /dev/<диск_для_ceph>
      
  2. Обновите SSH-ключи хоста. После переустановки ОС-узел получает новые SSH-ключи, что приводит к ошибке верификации при подключении. Удалите старые ключи и добавьте новые на узле, с которого будет выполняться инсталлятор:

    $ ssh-keygen -R <FQDN_нового_узла>
    $ ssh-keygen -R <IP_нового_узла>
    $ ssh-keyscan -H <FQDN_нового_узла> >> ~/.ssh/known_hosts
    $ ssh-keyscan -H <IP_нового_узла> >> ~/.ssh/known_hosts
    

    Важно

    Необходимо добавить ключи как по FQDN, так и по IP-адресу. k0sctl может подключаться по обоим адресам, и отсутствие любого из них приведёт к ошибке host key verification failed. Инсталлятор использует StrictHostKeyChecking=no для своих SSH-соединений, но вызываемый им k0sctl проверяет known_hosts.

    Убедитесь, что SSH-подключение работает:

    $ ssh <пользователь>@<FQDN_нового_узла> hostname
    
  3. Обновите DNS-запись, чтобы имя отказавшего узла указывало на IP-адрес нового узла, либо измените параметр fqdn_cpN в файле lcm-config.yaml.

Удаление отказавшего узла

  1. При наличии доступа к отказавшему узлу выполните:

    $ ssh <отказавший узел>
    $ sudo k0s stop
    $ sudo k0s reset
    
  2. Затем удалите узел из кластера Kubernetes и из etcd:

    $ kubectl delete node <имя отказавшего узла>
    $ sudo k0s etcd leave --peer-address <IP_отказавшего_узла>
    

    Важно

    Команда k0s etcd leave обязательна. Без неё k0sctl apply завершится с ошибкой: «controller is listed as an existing etcd member but k0s is not found installed on it».

Если доступа к отказавшему узлу нет (переустановка ОС, аппаратный сбой), выполните удаление из кластера Kubernetes и etcd с любого работающего контроллера.

Добавление нового узла

Для добавления нового узла рекомендуется использовать инсталлятор. Инсталлятор автоматически генерирует k0sctl.yaml из шаблона и lcm-config.yaml, устанавливает необходимые инструменты и выполняет k0sctl apply.

Из рабочей директории инсталлятора (mutiple-node/) выполните:

$ ./installer.sh --order 1

Инсталлятор выполнит следующие действия:

  • Установит инструменты (k0sctl, kubectl, helm, yq, velero) в /usr/bin/.

  • Проведёт предварительные проверки (SSH-доступ, firewall, resolv.conf).

  • Сгенерирует k0sctl.yaml из шаблона templates/k0sctl.j2 и lcm-config.yaml.

  • Выполнит k0sctl apply --config k0sctl.yaml --timeout 15m.

  • Получит kubeconfig и настроит VIP.

  • Дождётся готовности всех узлов.

  • Переустановит Helm-чарты первого этапа (MetalLB, Rook-Ceph, CNPG, cert-manager и др.).

Если требуется только добавить узел без переустановки Helm-чартов, можно сгенерировать k0sctl.yaml и выполнить k0sctl apply вручную:

$ jinja -D bundle_images_file "bundle_file.tar" -d lcm-config.yaml templates/k0sctl.j2 > k0sctl.yaml
$ k0sctl apply --config k0sctl.yaml --timeout 15m

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

k0sctl apply выполняет последовательную переустановку (reinstall) всех контроллеров кластера, а не только нового узла. Это приводит к кратковременному перезапуску сервиса k0s на существующих узлах. Процесс может занять 3–5 минут. В этот период kubelet на существующих узлах перезапускается, что вызывает кратковременную недоступность подов.

Дождитесь появления нового узла в кластере:

$ kubectl get nodes

Новый узел должен появиться в статусе Ready. Это может занять 2–3 минуты после завершения k0sctl apply.

Восстановление kubelet на существующих узлах

После переустановки контроллеров через k0sctl apply на существующих узлах kubelet может не запуститься из-за устаревших процессов и точек монтирования. Если kubelet не запускается в течение 5 минут (узел остаётся в статусе NotReady), выполните следующую процедуру на каждом проблемном узле:

  1. Остановите k0s:

    $ sudo k0s stop
    
  2. Завершите устаревшие процессы контейнерной среды выполнения:

    $ sudo pkill -9 containerd-shim
    
  3. Отключите оставшиеся точки монтирования контейнеров, которые не были сняты после завершения процессов containerd-shim:

    $ mount | grep '/run/k0s/containerd' | awk '{print $3}' | while read m; do sudo umount "$m"; done
    
  4. Запустите k0s:

    $ sudo k0s start
    
  5. Дождитесь запуска kubelet. Процесс инициализации включает согласование конфигурации worker-узла и запуск Node Local Load Balancer (NLLB/EnvoyProxy). Kubelet начинает полноценную работу через 2–3 минуты после старта k0s:

    $ sudo k0s status
    $ kubectl get nodes
    

    Убедитесь, что все узлы находятся в статусе Ready.

Восстановление Ceph

После замены узла старый OSD перейдёт в состояние CrashLoopBackOff, так как данные на диске были утеряны. Оператор Ceph для Kubernetes (Rook) не создаёт новый OSD автоматически — необходимо удалить старый OSD из кластера, очистить диск и перезапустить оператор.

Примечание

Если очистка диска (wipefs, sgdisk) была выполнена на этапе подготовки узла, после удаления старого OSD достаточно перезапустить оператор — Rook автоматически обнаружит чистый диск и создаст новый OSD.

  1. Проверьте состояние OSD:

    $ kubectl get pod -l app.kubernetes.io/name=ceph-osd -n ceph-cluster -o wide
    
  2. Если старый OSD находится в статусе CrashLoopBackOff, удалите его из кластера Ceph. Выполните команды из пода rook-ceph-tools:

    $ kubectl exec -n ceph-cluster deploy/rook-ceph-tools -- ceph osd out <ID_старого_OSD>
    $ kubectl exec -n ceph-cluster deploy/rook-ceph-tools -- ceph osd crush remove osd.<ID_старого_OSD>
    $ kubectl exec -n ceph-cluster deploy/rook-ceph-tools -- ceph auth del osd.<ID_старого_OSD>
    $ kubectl exec -n ceph-cluster deploy/rook-ceph-tools -- ceph osd rm <ID_старого_OSD>
    
  3. Удалите Deployment старого OSD:

    $ kubectl delete deploy rook-ceph-osd-<ID_старого_OSD> -n ceph-cluster
    
  4. Если диск не был очищен на этапе подготовки узла, выполните очистку сейчас (на замещённом узле):

    $ sudo wipefs -a /dev/<диск_для_ceph>
    $ sudo sgdisk --zap-all /dev/<диск_для_ceph>
    
  5. Перезапустите оператор Rook для обнаружения чистого диска:

    $ kubectl rollout restart deploy rook-ceph-operator -n rook-ceph
    
  6. Дождитесь создания нового OSD и начала восстановления данных:

    $ kubectl exec -n ceph-cluster deploy/rook-ceph-tools -- ceph status
    

    Rook создаст новый OSD на подготовленном диске. Кластер перейдёт в состояние HEALTH_WARN с сообщением о backfill/recovery. Дождитесь завершения восстановления данных и перехода в HEALTH_OK. Время восстановления зависит от объёма данных.

Восстановление Redis HA

Кластеры Redis HA (используемые в NetBox и других сервисах) в большинстве случаев восстанавливаются автоматически: Sentinel выполняет failover и назначает нового master из оставшихся подов. После добавления узла в кластер третий под Redis запускается и подключается как slave.

Примечание

Инсталлятор (installer.sh) при запуске с --no-reinstall-k0s также устанавливает Helm-чарты, которые проверяют и корректируют конфигурацию Redis HA.

Если автоматическое восстановление не произошло (все поды отображают role:slave, а master недоступен), выполните ручное повышение:

  1. Проверьте роли Redis:

    $ kubectl exec -n <namespace> <redis-ha-server-pod> -- redis-cli info replication
    
  2. Выберите один из работающих Redis-подов и повысьте его до master:

    $ kubectl exec -n <namespace> <redis-ha-server-pod> -- redis-cli SLAVEOF NO ONE
    

    После повышения Sentinel автоматически обнаружит нового master и перенастроит оставшиеся поды.

Восстановление Vault

После перезапуска контроллеров поды Vault могут оказаться в заблокированном (sealed) состоянии.

  1. Проверьте состояние каждого пода Vault:

    $ kubectl exec -n lcm-vault vault-0 -- vault status
    $ kubectl exec -n lcm-vault vault-1 -- vault status
    $ kubectl exec -n lcm-vault vault-2 -- vault status
    
  2. Если установлен vault-unsealer, дождитесь автоматической разблокировки (до 2 минут). Если vault-unsealer не установлен, выполните разблокировку вручную:

    $ kubectl exec -n lcm-vault <vault-pod> -- vault operator unseal <unseal_key>
    

    Повторите для каждого заблокированного пода.

Финальная проверка

Выполните полную проверку по шагам из раздела Восстановление узла после перезагрузки.