Привет, я Кирилл Шаталаев, инженер инфраструктуры и автоматизации в X5 Tech.  Я в курсе, что статей на эту тему достаточно, в том числе и на Habr. И когда у меня возникла задача поднять кластер, я их все перечитал. Где-то очень подробно рассказывается, как ставить виртуалки с убунтой на Windows под virtualbox, и очень скудно про сам кубер. Где-то досконально описано, как это всё круто можно провернуть с terraform в Яндекс.Облаке. Где-то про сам kubespray скупо пару слов, зато куча скриншотов прометея с кибаной. В итоге до большинства ключевых моментов пришлось доходить самостоятельно, гуглежом и изучением исходников ролей kubespray. Поехали! В настоящее время существует большое количество способов поднять локальный kubernetes быстро и грязно. Официальная документация рекомендует использовать для этого minikube. Canonical продвигает свой MicroK8s. Есть ещё k0s, k3s, kind — в общем, инструменты на любой вкус. Все эти игрушечные кластеры подходят максимум для целей разработки или проверки концепций. Но зачастую возникают задачи протестировать что-то в условиях максимально приближенных к боевым. Ну или просто поковыряться в потрохах kubernetes и понять, как работает тот или иной компонент. В этой ситуации все эти недокластеры вам мало помогут. Тут выход один — поднять нормальный кластер на виртуалках. Плюсов такого решения — масса. Можно играться с кластером как угодно, делать с нодами drain и cordon, ковыряться с LoadBalancer, можно имитировать сетевые проблемы и смотреть, что будет происходить с kubernetes при этом. Можно даже поднять рядом в виртуалке, допустим, Gitlab CE, подцепить к нему ваш кластер и обкатывать CI/CD. Минусы тоже есть — нужно иметь место, где запускать виртуалки. Например, достаточно производительный рабочий компьютер. Ну и придётся повозиться немного. Виртуальные машины: Мастер-ноды - 2 ядра, 4 Гб памяти, 20 Гб HDD master0 — 192.198.122.10 master1 — 192.168.122.11 master2 — 192.168.122.12 Воркер-ноды - 4 ядра, 16 Гб памяти, 20 Гб HDD worker0 — 192.198.122.20 worker1 — 192.168.122.21 worker2 — 192.168.122.22 ОС - Ubuntu 20.04.3 Инструмент разворачивания кластера — kubespray Инструменты управления кластером (локальные) — kubectl, k9s Я кратко опишу развёртывание виртуалок на моей локальной машине при помощи qemu и virt-manager. Если вы предпочитаете другой гипервизор, у вас уже есть виртуалки где-то в облаке или у вас есть, ну, я не знаю, отдельный сервер proxmox для экспериментов — пропустите шаги 1 и 2 и делайте по-своему. Хост-система - Ubuntu 20.04, CPU AMD Ryzen 7 3700X, оперативной памяти - 128 Гб. Конфигурация средняя, за исключением памяти (да, я маньяк) — но память нынче дёшевая, в отличие от видеокарт. Плюс ко всему, с учётом аппетита современных приложений, многие уже 32Гб считают минимально достаточным количеством оперативки. Хотя лучше в наших реалиях всё же иметь 64Гб. Устанавливаем необходимые пакеты: Добавляем себя в группу kvm, чтобы управлять виртуалками без использования прав суперпользователя: Теперь надо перелогиниться (в консоли, чтобы обновить список групп, можно использовать newgrp, но графическая сессия не всегда корректно подхватывает новые группы) и можно запускать менеджер виртуальных машин. При установке libvirt уже создана виртуальная сеть default, которая при помощи NAT транслирует трафик виртуальных машин во внешнюю сеть. Виртуалки гостей при этом цепляются к bridge-интерфейсу хоста. Хост также выполняет роль DHCP и DNS-серверов. Для этих целей выделена подсеть 192.168.122.0/24, адрес 192.168.122.1 назначается на bridge-интерфейс хоста, этот адрес является шлюзом по умолчанию и основным DNS-сервером для виртуалок. Все интерфейсы наших виртуалок, подключенных к одной виртуальной сети, находятся в одном l2-сегменте. Эта информация нам важна для будущей настройки балансировщика. Вы также можете настроить новые виртуальные сети, можете сделать их маршрутизируемыми или даже связать сеть с физическим интерфейсом хоста (в этом случае виртуалки будут подключены ко внешней сети напрямую). В рамках данной задачи это нам не нужно. Мы сделаем только первую виртуалку master0, а затем просто склонируем её. Создаётся машина вообще проще простого, я сделал несколько скриншотов в важных моментах. Установка завершена, дальше дожидаемся перезагрузки и добавляем на машину свой ssh-ключ и пробуем зайти на неё по ssh: На свежесозданной виртуалке добавляем наш ключ к учетной записи root: Выходим и пробуем зайти под root по ssh. Должно пустить. После этих тривиальных настроек мы выключаем нашу виртуалку и приступаем к клонированию. Теперь важный момент номер два — клонирование создаёт полную копию машины, со всеми ключами, UUID и прочим. Чтобы заново инициализировать каждую из виртуалок, выполняем команду virt-sysprep для склонированной виртуалки: пустит, т.к. предыдущая команда снесла все ключи, а как заставить sysprep сгенерировать их сразу, я не нашёл). Выполняем команды: Проверяем, что сервер ssh успешно запущен: Последним этапом мы меняем IP в настройках сетевого интерфейса и устанавливаем правильный hostname Настройки сети содержатся в файле /etc/netplan/00-installer-config.yaml Здесь нам нужно поменять единственную строчку - ip-адрес с 192.168.122.10/24 на 192.168.122.11/24 На всякий случай проверяем содержимое файла, после чего выполняем команду: В завершение — hostname: Перезагружаем виртуалку и пробуем залогиниться под root: Дальше повторяем эту процедуру для оставшихся нод — master2, worker0, worker1, worker2. Не забудьте, что для worker-нод надо будет установить нужное количество ядер и памяти. Делается это элементарно — через интерфейс управления виртуальными машинами. Да, такие вещи неплохо автоматизировать, но мне не пришло в голову сходу, как это сделать. Конечно, можно было использовать для этих целей vagrant, но не хотелось, так как там куча своих заморочек и в итоге потратил бы гораздо больше времени. Если у вас есть идеи — буду рад услышать в комментариях. Кубер мы будем разворачивать при помощи kubespray. Это набор ansible-ролей, которые позволяют с минимальными усилиями получить готовый продакшн кластер. Тут всё ещё проще. Ещё раз обращаю внимание, что дополнительно ничего на машинах делать не надо — ни править hosts, ни отключать swap. Достаточно стандартной установки дистрибутива. Обо всём позаботится kubespray. Клонируем себе репозиторий: На момент написания статьи стабильный выпуск у нас 2.17.1. В репозитории релизы отмечены соответствующими тегами: Репозиторий содержит образец конфигурации в директории inventory/sample. Мы создадим копию и будем её портить. Итак, первый файл, который нам нужно исправить — это inventory.ini. В принципе, он снабжён комментариями и понятен. Приводим его к следующему виду. Тут всё ясно — определяем, кто у нас будет мастером, а кто воркером: Теперь, собственно, настройки кластера. Я укажу те переменные, которые нужно поменять. Здесь меняем только одну переменную для того, чтобы работал балансировщик: Включаем метрики: Включаем nginx ingress controller: Включаем MetalLB. Для балансировщика выделяем диапазон IP из нашей виртуальной сети default: Provisioning для PV не включаем. Можно это сделать потом, по желанию, но надо поменять конфигурацию ваших нод и сделать хотя бы одну с достаточным дисковым пространством. Можно поднимать кластер. Команды такие: Роль должна отработать без всяких ошибок. По времени это занимает минут 15. Проверяем, что всё поднялось. Заходим на любую из мастер-нод и выполняем: Отлично, кластер работает. Утаскиваем себе на локальную машину kubeconfig: На локальной машине в файле меняем строчку: На: Дальше либо копируем его себе в ~/.kube/ целиком, либо правим существующий там файл, если есть уже настроенные кластеры. И пробуем приконнектиться, например, k9s Теперь несколько неочевидный момент. kubespray выкатывает ingress-nginx в виде daemonset-а. Как известно, в kubernetes есть разные способы публикации сервисов. Можно было не заморачиваться и включить в файле inventory/lab/group_vars/k8s_cluster/addons.yml но это некрасиво. Красиво — это MetalLB в режиме Layer2. Почти как на настоящем продакшне. Как работает MetalLB? Если коротко, он берёт адрес из указанного ему диапазона, назначает его одной из нод и сообщает об этом окружающим посредством ARP (может и по BGP, но это не для игрушечных кластеров). Все запросы, приходящие на заданный адрес, он направляет соответствующему сервису kubernetes. Если нода внезапно подохнет, то MetalLB переназначает IP другой ноде. Создаём манифест под названием ingress-nginx-service.yaml со следующим содержимым: И применяем его: Проверяем: Nginx отвечает по указанному адресу. В большинстве случаев меняете соответствующие переменные и запускаете роль снова. Повторный прогон kubespray кластер не сломает. Надеюсь, статья вам поможет, и вы потратите на задачу «поднять кластер на поиграться» не так много времени, сколько пришлось потратить мне.