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

Мы решили сделать гибридный кластер Kubernetes на базе существующего bare-metal-кластера, чтобы:

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

  • разворачивать на этих узлах нужные окружения для тестов;

  • сворачивать окружения после выхода изменений в production и отключать узлы.

Для этого мы воспользовались модулем cloud-provider-openstack, который входит в состав Kubernetes-платформы Deckhouse. Расскажу, как это работает.

☝️ В статье рассматривается вариант развертывания гибридного кластера в Selectel и OpenStack-облаке, которое предоставляет провайдер. Но сам подход универсален, его можно применять, к примеру, и на собственной инфраструктуре.

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

У нас был bare-metal-кластер Kubernetes, расположенный в Selectel. Узлы в нем находились в разных зонах: SPB-3 и SPB-5. Также некоторые приложения использовали managed PostgreSQL, расположенный в облачной зоне ru-3. Чтобы была возможность дозаказывать узлы в OpenStack-облаке Selectel, нам пришлось настроить сетевое взаимодействие между уже существующими сетями и облачными.

Так выглядит L3VPN-роутер от Selectel, который позволяет связать bare-metal-узлы в зонах SPB-3 (network_SPB-3) и SPB-5 (network_SPB-5) с PostgreSQL (network_ru-3):

Четвёртую сеть — k8s_l3vpn — добавили инженеры Selectel, чтобы связать виртуальные машины (ВМ) в облаке с остальными сетями.

Облачным ВМ нужен доступ не только к внутренним сетям, но и во внешнюю сеть. Поэтому пришлось сделать две сети в облаке и попросить коллег из Selectel настроить маршруты в них.

Одна из сетей дает ВМ доступ во внешнюю сеть:

Через вторую L3VPN-роутер связывает облачные ВМ с остальными сетями:

Две этих сети объединены отдельным облачным роутером, который подключен к внешней сети:

Затем мы попросили настроить маршрутизацию таким образом, чтобы ВМ, которые заказываются в сети k8s_l3vpn (192.168.200.0/24), получали маршруты вида:

            -   to: 0.0.0.0/0
                via: 192.168.200.1
            -   to: 10.13.1.0/24
                via: 192.168.200.252
            -   to: 192.168.204.0/24
                via: 192.168.200.252
            -   to: 192.168.205.0/24
                via: 192.168.200.252

В результате получилась такая схема: 

  • доступ во внешнюю сеть k8s-external-access реализован через основной шлюз 192.168.200.1;

  • доступ к «серым» подсетям организован через шлюз 192.168.200.252.

На этом подготовительные работы были закончены.

Подготовка и настройка модуля cloud-provider-openstack в Deckhouse

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

Сделать это можно в личном кабинете Selectel: Профиль и настройки → Управление пользователями → Добавить пользователя → Сервисный пользователь. Там нужно указать имя, пароль и выдать права администратора необходимого проекта:

Затем мы создали keypair, чтобы при необходимости подключаться к ВМ по ключу:

openstack keypair create --public-key ~/.ssh/id-rsa.pub --type ssh deckhouse

Также можно загрузить свой образ, с которым будет бутстрапиться новая ВМ с помощью openstack image create.

Чтобы настроить OpenStack CLI под созданного пользователя, скачали скрипт в разделе Облачная платформаДоступ, выбрав там нужного пользователя:

И выполнили:

source rc.sh

Для работы с OpenStack мы воспользовались модулем Deckhouse cloud-provider-openstack. Вот его конфигурация:

apiVersion: deckhouse.io/v1alpha1
kind: ModuleConfig
metadata:
  name: cloud-provider-openstack
spec:
  enabled: true
  settings:
    connection:
      authURL: <OS_AUTH_URL из rc.sh>
      domainName: <OS_PROJECT_DOMAIN_NAME из rc.sh>
      password: <пароль сервисного пользователя>
      region: <OS_REGION_NAME из rc.sh>
      tenantID: <OS_TENANT_ID из rc.sh>
      username: <имя сервисного пользователя>
    instances:
      sshKeyPairName: deckhouse # Имя keypair, созданного ранее.
    internalNetworkNames:
    - k8s_l3vpn # Имя сети, которая подключена к роутеру L3VPN и в которой будут находиться ВМ.
    podNetworkMode: DirectRouting
    zones:
    - ru-3a
  version: 1

Со всеми доступными параметрами модуля можно ознакомиться в разделе документации «OpenStack: настройки».

Сначала создали flavor с нужными параметрами:

openstack flavor create c4m8d50 --ram 8192 --disk 50 --vcpus 4 --private

Затем InstanceClass:

apiVersion: deckhouse.io/v1
kind: OpenStackInstanceClass
metadata:
  name: cloud-worker
spec:
  flavorName: c4m8d50
  imageName: ubuntu-22-04-cloud-amd64 # Берем существующий (openstack image list) или загруженный на шаге ранее.
  mainNetwork: k8s_l3vpn

И, наконец, NodeGroup:

apiVersion: deckhouse.io/v1
kind: NodeGroup
metadata:
  name: cloud-worker
spec:
  chaos:
    mode: Disabled
  cloudInstances:
    classReference:
      kind: OpenStackInstanceClass 
      name: cloud-worker # Указываем имя InstanceClass, созданного ранее.
    maxPerZone: 10 # Максимальное кол-во узлов в зоне.
    minPerZone: 1 # Минимальное кол-во узлов в зоне.
    zones:
    - ru-3a
  disruptions:
    approvalMode: Automatic
  nodeTemplate:
    labels:
      node-role/cloud-worker: ""
    taints:
    - effect: NoExecute
      key: dedicated
      value: cloud-worker
  nodeType: CloudEphemeral

Работа с ВМ

Через 2–3 минуты после создания NodeGroup узлы начинают заказываться с учетом параметра minPerZone и добавляться в кластер. За процессом можно следить в панели Selectel:

И в кластере:

~ $ kubectl get no -owide | grep cloud
cloud-worker-af1ba977-7d4d4-lltnf   Ready    cloud-worker               28d      v1.23.15   192.168.200.68    <none>        Ubuntu 22.04.1 LTS   5.15.0-57-generic   docker://20.10.14

Смотрим на узлы с точки зрения cloud instance manager'a:

~ $ kubectl -n d8-cloud-instance-manager get machine
NAME                                STATUS    AGE
cloud-worker-af1ba977-7d4d4-lltnf   Running   5d3h

Если при создании возникают ошибки, связанные с недостаточностью прав или некорректным подключением к API, их можно наблюдать в логах контроллера:

~ $ kubectl -n d8-cloud-instance-manager logs -l app=machine-controller-manager -c controller

Когда временные окружения сворачиваются и ресурсы в кластере освобождаются, Cluster Autoscaler удаляет облачные ВМ.

Если требуется удалить ненужную ВМ вручную, нужно выполнить два шага.

  1. Получаем список машин:

 kubectl ‑n d8-cloud‑instance‑manager get machine NAME STATUS AGE cloud‑worker‑af1ba977–7d4d4-lltnf Running 25d
  1. Удаляем ненужную:

 kubectl -n d8-cloud-instance-manager delete machine cloud-worker-af1ba977-7d4d4-lltnf

Заключение

С помощью модуля cloud-provider-openstack, который входит в состав платформы Deckhouse, мы превратили обычный bare-metal-кластер в гибридный. В нем можно создавать различные группы узлов под специфические цели с непостоянной нагрузкой и масштабировать узлы в зависимости от потребностей.

Хотя в статье рассматривается вариант развертывания гибридного кластера в Selectel, связку «Deckhouse + модуль cloud-provider-openstack» можно использовать где угодно, в том числе и на собственной инфраструктуре.

P.S.

Читайте также в нашем блоге:

Комментарии (0)