Гибридный Kubernetes-кластер из bare metal и динамически подключаемых облачных виртуальных машин

Kate

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

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

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

1c13c82f2f03b171d1f36d5ef2e7b213.png

☝️ В статье рассматривается вариант развертывания гибридного кластера в 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):

85ae51c199b464b7d40b02d2e792d771.png

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

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

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

9536dee23f8700894a268553202fe756.png

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

e629a1589ba7207e2895306cc0f11c52.png

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

e850c157a2e8f2833f0d8a7bf407884b.png

Затем мы попросили настроить маршрутизацию таким образом, чтобы ВМ, которые заказываются в сети 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: Профиль и настройки → Управление пользователями → Добавить пользователя → Сервисный пользователь. Там нужно указать имя, пароль и выдать права администратора необходимого проекта:

d8dc34278ef73113abc04f89aebe520b.png

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

openstack keypair create --public-key ~/.ssh/id-rsa.pub --type ssh deckhouse
Также можно загрузить свой образ, с которым будет бутстрапиться новая ВМ с помощью openstack image create.

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

e27c2c41ea759ff920f53ba3d2c119fb.png

И выполнили:

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:

4ccdf92083c6597a333759176a9dbcc1.png

И в кластере:

~ $ 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» можно использовать где угодно, в том числе и на собственной инфраструктуре.

 
Сверху