Как устроен Deckhouse Commander

Схема

У Deckhouse Commander есть внешняя зависимость — база данных PostgreSQL.

Сервер API является центральным компонентом. Данные хранятся в PostgreSQL. Варианты установки Deckhouse Commander с СУБД указаны в разделе «Установка».

Сервер API предоставляет как внешние API — веб-приложения и для внешней интеграции - так и внутренние API для работы с кластерами.

Веб-приложение использует API для управления кластерами и другими сущностями Deckhouse Commander.

Для управления кластерами используются асинхронные операции — задания. Менеджер кластеров — это сервис, который отслеживает задания и выполняет их. Заданиями могут быть установка кластера, удаление кластера или сверка состояния кластера с заданной конфигурацией.

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

Менеджер кластеров использует специальный компонент для управления кластерами — сервер dhctl. В целевой картине менеджер кластеров запускает реплику сервера dhctl только нужной версии для каждого кластера Deckhouse Kubernetes Platform (DKP) индивидуально. Однако сервер dhctl сейчас в активной разработке, поэтому на данный момент есть ограничение на версию DKP, которую Deckhouse Commander гарантированно устанавливает. См ниже раздел «Текущие ограничения».

В каждом кластере Deckhouse Commander автоматически устанавливает модуль commander-agent. Этот модуль отвечает за синхронизацию ресурсов Kubernetes в прикладном кластере, а так же за отправку телеметрии в сервер API Deckhouse Commander. Телеметрия сейчас включает в себя основные метрики (ЦП, память, количество узлов и общий объем хранилищ), версию DKP, версию Kubernetes и доступность компонентов DKP. Помимо агента, в кластере устанавливается модуль console, который используется для управления индивидуальным кластером через Deckhouse Commander во вкладке Администрирование. Служебные компоненты в прикладном кластере по умолчанию размещаются на системных узлах.

Так же в Deckhouse Commander используются дополнительные сервисы, которые не отображены на схеме — рендерер и коннектор. Рендерер отвечает за генерацию и валидацию конфигурации кластеров, а коннектор — за работу интерфейса администрирования кластера.

Шифрование данных

Начиная с версии 1.6 Коммандер шифрует чувствительные данные в базе. Для шифрования используются ключи из секрета commander-envs, которые генерируются Коммандером автоматически.

Внимание: Крайне важно сохранить ключи в надежное место, чтобы иметь возможность восстановить базу данных в случае каких-либо проблем. При отсутствии ключей восстановить данные будет невозможно!

$ kubectl -n d8-commander get secret commander-envs -oyaml
apiVersion: v1
data:
  ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY: YVBBNVh5QUxoZjc1Tk5uTXphc3BXN2FrVGZacDBsUFk=
  ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT: eEVZMGR0NlRaY0FNZzUySzdPODR3WXpranZiQTYySHo=
  ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY: RUdZOFdodWxVT1hpeHlib2Q3Wld3TUlMNjhSOW81a0M=
kind: Secret
metadata:
...
  name: commander-envs
  namespace: d8-commander
type: Opaque

Изменение класса хранилища для БД (StorageClass)

Эта инструкция нужна только в том случае, если для СУБД используется модуль operator-postgres. На это указывает режим подключения к БД Internal в ModuleConfig/commander

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: commander
spec:
  enabled: true
  version: 1
  settings:
    postgres:
      mode: Internal
    ...

Вариант 1 (предпочтительный)

  1. Выполняем резервное копирование экземпляра БД

    kubectl -n d8-commander exec -t commander-postgres-0 -- su - postgres -c "pg_dump -Fc -b -v -d commander" > commander.dump
    
  2. Изменяем storageClass в настройках модуля, заменив <NEW_STORAGECLASS_NAME> на название необходимого класса хранения

    Список доступных классов хранения можно узнать при помощи команды kubectl get storageclasses

    kubectl patch moduleconfig commander --type=merge -p '{"spec":{"settings":{"postgres":{"internal":{"storageClass":"<NEW_STORAGECLASS_NAME>"}}}}}'
    
    moduleconfig.deckhouse.io/commander patched
    

    Дожидаемся, пока очередь deckhouse окажется пустой

    kubectl -n d8-system exec -it $((kubectl -n d8-system get leases.coordination.k8s.io deckhouse-leader-election -o jsonpath={.spec.holderIdentity} || printf "deployments/deckhouse") | cut -d. -f1) -c deckhouse -- deckhouse-controller queue main
    
    Queue 'main': length 0, status: 'waiting for task 5s'
    

    Проверяем логи оператора postgres на отсутствие ошибок

    kubectl -n d8-operator-postgres logs deployments/operator-postgres
    
    {"cluster-name":"d8-commander/commander-postgres","level":"info","msg":"cluster has been updated","pkg":"controller","time":"2024-05-19T20:36:22Z","worker":0}
    
  3. Увеличиваем количество реплик БД PostgreSQL (опционально)

    Этот шаг необходимо пропустить, если в кластере активен режим HighAvailability и PostgreSQL имеет 2 реплики

    kubectl -n d8-commander patch postgresqls.acid.zalan.do commander-postgres --type=merge -p '{"spec":{"numberOfInstances":2}}'
    
    postgresql.acid.zalan.do/commander-postgres patched
    

    Проверяем логи оператора и экземпляра postgres

    kubectl -n d8-operator-postgres logs deployments/operator-postgres
    
    {"cluster-name":"d8-commander/commander-postgres","level":"info","msg":"cluster has been updated","pkg":"controller","time":"2024-05-19T20:36:22Z","worker":0}
    
    kubectl -n d8-commander logs commander-postgres-1
    
    2024-05-19 20:38:15,648 INFO: no action. I am (commander-postgres-1), a secondary, and following a leader (commander-postgres-0)
    
  4. Выполняем переключение мастера

    kubectl -n d8-commander exec -it commander-postgres-0 -- patronictl failover
    
    Current cluster topology
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.167 | Leader  | running |  5 |           |
    | commander-postgres-1 | 10.111.2.239 | Replica | running |  5 |         0 |
    +----------------------+--------------+---------+---------+----+-----------+
    Candidate ['commander-postgres-1'] []: commander-postgres-1
    Are you sure you want to failover cluster commander-postgres, demoting current leader commander-postgres-0? [y/N]: y
    2024-05-19 20:40:52.63041 Successfully failed over to "commander-postgres-1"
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.167 | Replica | stopped |    |   unknown |
    | commander-postgres-1 | 10.111.2.239 | Leader  | running |  5 |           |
    +----------------------+--------------+---------+---------+----+-----------+
    

    Убеждаемся, что оба экземпляра БД находятся в состоянии running

    kubectl -n d8-commander exec -t commander-postgres-0 -- patronictl list
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.167 | Replica | running |  6 |         0 |
    | commander-postgres-1 | 10.111.2.239 | Leader  | running |  6 |           |
    +----------------------+--------------+---------+---------+----+-----------+
    

    Проверяем, что диск новой реплики БД создался с необходимым storageClass

    kubectl -n d8-commander get pvc --selector application=spilo
    NAME                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    pgdata-commander-postgres-0   Bound    pvc-fd80fde4-d0e2-4b5f-9e3a-eac998191f11   2Gi        RWO            network-hdd    36h
    pgdata-commander-postgres-1   Bound    pvc-7af2f442-3097-4fe3-a795-5ad18bb11351   2Gi        RWO            network-ssd    2m54s
    
  5. Удаляем диск и под первого экземпляра

    kubectl -n d8-commander delete pvc pgdata-commander-postgres-0 --wait=false
    kubectl -n d8-commander delete po commander-postgres-0
    

    Проверяем логи

    kubectl -n d8-commander logs commander-postgres-0
    
    2024-05-19 20:43:33,293 INFO: Lock owner: commander-postgres-1; I am commander-postgres-0
    2024-05-19 20:43:33,293 INFO: establishing a new patroni connection to the postgres cluster
    2024-05-19 20:43:33,357 INFO: no action. I am (commander-postgres-0), a secondary, and following a leader (commander-postgres-1)
    

    Проверяем, что диск создался с правильным storageClass

    kubectl -n d8-commander get pvc
    NAME                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    pgdata-commander-postgres-0   Bound    pvc-fd80fde4-d0e2-4b5f-9e3a-eac998191f11   2Gi        RWO            network-ssd    2m6s
    pgdata-commander-postgres-1   Bound    pvc-7af2f442-3097-4fe3-a795-5ad18bb11351   2Gi        RWO            network-ssd    7m11s
    
  6. Выполняем обратное переключение мастера

    kubectl -n d8-commander exec -it commander-postgres-0  -- patronictl failover
    
    Current cluster topology
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.189 | Replica | running |  6 |         0 |
    | commander-postgres-1 | 10.111.2.239 | Leader  | running |  6 |           |
    +----------------------+--------------+---------+---------+----+-----------+
    Candidate ['commander-postgres-0'] []: commander-postgres-0
    Are you sure you want to failover cluster commander-postgres, demoting current leader commander-postgres-1? [y/N]: y
    2024-05-19 20:46:11.69855 Successfully failed over to "commander-postgres-0"
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.189 | Leader  | running |  6 |           |
    | commander-postgres-1 | 10.111.2.239 | Replica | stopped |    |   unknown |
    +----------------------+--------------+---------+---------+----+-----------+
    

    Убеждаемся, что оба экземпляра БД находятся в состоянии running

    kubectl -n d8-commander exec -t commander-postgres-0 -- patronictl list
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.189 | Leader  | running |  6 |         0 |
    | commander-postgres-1 | 10.111.2.239 | Replica | running |  6 |           |
    +----------------------+--------------+---------+---------+----+-----------+
    
  7. Уменьшаем количество реплик БД PostgreSQL (опционально)

    Этот шаг необходимо пропустить, если в кластере активен режим HighAvailability и PostgreSQL имеет 2 реплики

    kubectl -n d8-commander patch postgresqls.acid.zalan.do commander-postgres --type=merge -p '{"spec":{"numberOfInstances":1}}'
    
    postgresql.acid.zalan.do/commander-postgres patched
    

    Проверяем логи оператора

    kubectl -n d8-operator-postgres logs deployments/operator-postgres
    
    {"cluster-name":"d8-commander/commander-postgres","level":"info","msg":"cluster has been updated","pkg":"controller","time":"2024-05-19T20:50:22Z","worker":0}
    
  8. Удаляем диски

  • Удаляем диск и под первого экземпляра (если в кластере активен режим HighAvailability и PostgreSQL имеет 2 реплики)

    Этот шаг необходимо пропустить, если в кластере не используется режим HighAvailability

    kubectl -n d8-commander delete pvc pgdata-commander-postgres-1 --wait=false
    kubectl -n d8-commander delete po commander-postgres-1
    

    Проверяем логи

    kubectl -n d8-commander logs commander-postgres-1
    
    2024-05-19 20:53:33,293 INFO: Lock owner: commander-postgres-0; I am commander-postgres-1
    2024-05-19 20:53:33,293 INFO: establishing a new patroni connection to the postgres cluster
    2024-05-19 20:53:33,357 INFO: no action. I am (commander-postgres-1), a secondary, and following a leader (commander-postgres-0)
    

    Проверяем, что диск создался с правильным storageClass

    kubectl -n d8-commander get pvc
    NAME                          STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
    pgdata-commander-postgres-0   Bound    pvc-fd80fde4-d0e2-4b5f-9e3a-eac998191f11   2Gi        RWO            network-ssd    7m6s
    pgdata-commander-postgres-1   Bound    pvc-7af2f442-3097-4fe3-a795-5ad18bb11351   2Gi        RWO            network-ssd    1m11s
    

    Убеждаемся, что оба экземпляра БД находятся в состоянии running

    kubectl -n d8-commander exec -t commander-postgres-0 -- patronictl list
    + Cluster: commander-postgres --------+---------+---------+----+-----------+
    | Member               | Host         | Role    | State   | TL | Lag in MB |
    +----------------------+--------------+---------+---------+----+-----------+
    | commander-postgres-0 | 10.111.3.189 | Leader  | running |  6 |         0 |
    | commander-postgres-1 | 10.111.2.239 | Replica | running |  6 |           |
    +----------------------+--------------+---------+---------+----+-----------+
    
  • Удаляем неиспользуемый диск, оставшийся от временной реплики БД (если режим HighAvailability не используется)

    Этот шаг необходимо пропустить, если в кластере активен режим HighAvailability и PostgreSQL имеет 2 реплики

    kubectl -n d8-commander delete pvc pgdata-commander-postgres-1
    
    persistentvolumeclaim "pgdata-commander-postgres-1" deleted
    

Вариант 2

  1. Выполняем резервное копирование экземпляра БД

    kubectl -n d8-commander exec -t commander-postgres-0 -- su - postgres -c "pg_dump -Fc -b -v -d commander" > commander.dump
    
  2. Выключаем модуль commander

    kubectl patch moduleconfig commander --type=merge -p '{"spec":{"enabled":false}}'
    
    moduleconfig.deckhouse.io/commander patched
    

    Дожидаемся, пока очередь deckhouse окажется пустой

    kubectl -n d8-system exec -it $((kubectl -n d8-system get leases.coordination.k8s.io deckhouse-leader-election -o jsonpath={.spec.holderIdentity} || printf "deployments/deckhouse") | cut -d. -f1) -c deckhouse -- deckhouse-controller queue main
    
    Queue 'main': length 0, status: 'waiting for task 5s'
    

    Проверяем, что неймспейс d8-commander удален

    kubectl get namespace d8-commander
    Error from server (NotFound): namespaces "d8-commander" not found
    
  3. Указываем необходимый класс хранения и включаем модуль commander

     kubectl patch moduleconfig commander --type=merge -p '{"spec":{"enabled":true,"settings":{"postgres":{"internal":{"storageClass":"<NEW_STORAGECLASS_NAME>"}}}}}'
    
     moduleconfig.deckhouse.io/commander patched
    

    Дожидаемся, пока очередь deckhouse окажется пустой

    kubectl -n d8-system exec -it $((kubectl -n d8-system get leases.coordination.k8s.io deckhouse-leader-election -o jsonpath={.spec.holderIdentity} || printf "deployments/deckhouse") | cut -d. -f1) -c deckhouse -- deckhouse-controller queue main
    
    Queue 'main': length 0, status: 'waiting for task 5s'
    

    Проверяем, что экземпляр БД в статусе Running

    kubectl -n d8-commander get po commander-postgres-0
    
    NAME                   READY   STATUS    RESTARTS   AGE
    commander-postgres-0   1/1     Running   0          2m4s
    
  4. Восстанавливаем ранее сохраненную резервную копию БД

    kubectl -n d8-commander exec -it commander-postgres-0 -- su - postgres -c "pg_restore -v -c --if-exists -Fc -d commander" < commander.dump