ADG Оставить заявку
Блог DevOps 5 мин чтения

kubeadm out of beta: разворачиваем первый production-кластер Kubernetes на bare-metal

kubeadm выходит из beta в Kubernetes 1.8 и становится рекомендованным способом поднять кластер. Разворачиваем HA на трёх master-нодах через keepalived и haproxy - и сразу упираемся в пробелы документации.

Контекст момента

kubeadm выходит из beta в Kubernetes 1.8 и становится официально рекомендованным инструментом развёртывания кластера на bare-metal и VM

С выходом Kubernetes 1.8 kubeadm официально покинул статус beta. Это не просто смена лейбла в документации - команда Kubernetes прямо говорит: kubeadm является рекомендованным способом поднять кластер на bare-metal и VM. Мы взяли это за отправную точку и развернули первый полноценный production-кластер для одного из клиентов целиком через kubeadm. Опыт получился показательным.

Зачем вообще bare-metal

У клиента - собственный датацентр, несколько стоек, никакого желания перекладывать данные в облако. Задача: запустить managed-кластер Kubernetes поверх имеющегося железа. До этого мы работали с кластерами на облачных VM через kops и kubeadm в тестовом режиме. Здесь впервые - чистый bare-metal, production, и сразу HA-схема.

HA на трёх master-нодах - это минимум для того, чтобы etcd имел кворум и потеря одной ноды не роняла весь control plane. Схема выглядит понятно на бумаге: keepalived держит виртуальный IP, haproxy балансирует запросы к apiserver на всех трёх мастерах, etcd кластеризован между ними же.

VIP (keepalived)
      |
   HAProxy
  /   |   \
API  API  API
 |    |    |
 etcd-etcd-etcd

На практике эта схема потребовала примерно вдвое больше времени, чем мы планировали.

Что не описано в документации

kubeadm в 1.8 умеет инициализировать первый мастер и добавлять рабочие ноды - это всё хорошо документировано. HA-сценарий с несколькими мастерами в официальной документации на момент выхода 1.8 описан как «экспериментальный» и дан очень бегло. Конкретные грабли:

Первое - kubeadm init и advertise-address. При инициализации первого мастера нужно передать --apiserver-advertise-address равный виртуальному IP keepalived, а не реальному IP ноды. Иначе сертификаты генерируются под реальный адрес, и когда VIP переезжает на другую ноду при failover, клиенты начинают получать ошибку TLS. Это нигде прямо не написано - вывели из принципа работы TLS и нескольких часов отладки.

Второе - etcd на тех же нодах. kubeadm по умолчанию поднимает etcd как static pod на той же ноде. При добавлении второго и третьего мастера через kubeadm join нужно вручную добавлять каждый новый узел в кластер etcd до того, как kubeadm завершит настройку. Порядок операций важен, и если его перепутать - получаешь etcd без кворума, который молчаливо отказывается принимать новые ноды.

Третье - haproxy и health checks. haproxy нужно настроить с корректными health check-ами к /healthz на каждом apiserver. Казалось бы очевидно, но дефолтный TCP-check в нашем случае давал ложноположительные результаты при рестарте apiserver в процессе обновления. Переключились на HTTP check - стало нормально.

Четвёртое - keepalived и VRRP. Если все три ноды в одном L2-сегменте (у нас так), keepalived работает без проблем. Если ноды в разных VLAN - VRRP-пакеты нужно пропускать отдельно, и это зависит от конфигурации коммутаторов, а не от Kubernetes.

Как в итоге прошли инициализацию

Схема, которая сработала:

  1. Поднять keepalived на всех трёх нодах, убедиться что VIP работает и переезжает при отключении ноды.
  2. Поднять haproxy на всех трёх нодах, настроить балансировку на локальные apiserver с HTTP health check.
  3. kubeadm init на первом мастере с --apiserver-advertise-address=<VIP> и --apiserver-cert-extra-sans=<VIP>,<real-ip-1>.
  4. Вручную добавить ноды 2 и 3 в etcd-кластер через etcdctl member add.
  5. Скопировать PKI с первого мастера на второй и третий (kubeadm не делает это автоматически).
  6. kubeadm join на нодах 2 и 3 с флагом --experimental-control-plane.
  7. Только после этого - kubeadm join для рабочих нод.

Каждый шаг звучит несложно. Вместе - это пол-дня осторожной работы с постоянными проверками состояния etcd и кворума.

Состояние kubeadm сегодня

Инструмент явно дозрел по сравнению с тем, что было в 1.6. Генерация сертификатов, настройка RBAC, kubeconfig для admin - всё это kubeadm берёт на себя и делает правильно. Базовый сценарий «один мастер плюс N рабочих нод» действительно работает из коробки и занимает минут двадцать.

HA-сценарий пока требует дополнительных рук. Флаг --experimental-control-plane в названии содержит честное предупреждение - команда сама его так назвала. Мы рассчитываем что в следующих минорных версиях этот путь обрастёт нормальной документацией и, возможно, большей автоматизацией со стороны самого kubeadm.

Сеть и CNI

Отдельная история - выбор CNI-плагина. На bare-metal без overlay-поддержки со стороны провайдера мы остановились на Calico: он работает в BGP-режиме без encapsulation, что даёт нормальную производительность на физических интерфейсах. Weave и Flannel тоже рассматривали, но Calico лучше ложится на то, что у клиента есть в плане сетевого оборудования.

Установка Calico через kubeadm - стандартный kubectl apply -f после инициализации кластера. Единственный нюанс: нужно передать --pod-network-cidr в kubeadm init заранее, иначе controller-manager не знает о podCIDR и Calico ведёт себя странно.

Итог

Кластер работает. Три мастера, keepalived проверили в бою - убивали ноды по очереди, VIP переезжал за секунды, kubectl продолжал работать. Рабочие ноды добавляются стандартным kubeadm join без каких-либо сюрпризов.

kubeadm как инструмент - хороший выбор для тех, кто разворачивает кластер вручную на своём железе. Только нужно понимать, что документация HA-сценария идёт сильно позади реальных возможностей инструмента. Мы всё это записали в виде runbook-а - при следующем развёртывании будет сильно быстрее.

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.