Дано: домашний сервер под управлением Debian 11 с установленным гипервизором Xen. Требуется: развернуть Kubernetes-кластер для получения опыта, связанного с настройкой и управлением Kubernetes-кластера, и дальнейшего его использования для разработки и хостинга персональных проектов. Развёртывание Debian и Xen, а также миграция с Hyper-V на Xen нескольких Windows-виртуальных машин описана в моей статье Миграция домашнего сервера с Hyper-V на Xen Project на Debian. В ней также описана конфигурация моей сети. В данной статье я исхожу из того, что читатель имеет представление о том, что такое Kubernetes, как он работает, из каких компонентов состоит и знаком с необходимой терминологией. Многие идеи и код я брал из статьи Разворачиваем среду для работы с микросервисами. Часть 1 установка Kubernetes HA на bare metal (Debian), но местами адаптировал под свои нужды и окружение. Задача данной статьи дать читателям готовое решение, требующее минимальных усилий для повторения и, вместе с тем, не требующее дополнительных инструментов (вроде Ansible или Terraform), а также показать новичкам некоторые моменты работы с Linux, Kubernetes и используемыми пакетами. Повествование разбито на несколько шагов, каждый из которых заключается в запуске скрипта и нескольких ручных командах. Минимальная конфигурация кластера может состоять из одного-двух узлов: либо один master, которому разрешено хостить пользовательские нагрузки, либо один master и один worker. Однако, подобный кластер не будет, даже близко, похож на типичный промышленный high available (HA) кластер, а значит, полученный опыт будет сильно ограничен как в процессе развёртывания, так и в процессе эксплуатации. Конечно, ни о каком HA-кластере на одной физической машине (как в моём случае) речи быть не может, но, напомню, главная цель — получение опыта и площадки для экспериментов. К слову, если для разработки нужен кластер на рабочей станции, скажем для разработки cloud native приложений, или для изучения простейших команд kubectl, отличным выбором будет minikube. Я уже его использую для TDD через end-to-end и интеграционные тесты с использованием skaffold, о чём, возможно, расскажу в одной из следующих статей. Как выглядит минимально-достаточный промышленный HA Kubernetes-кластер? от двух master-узлов, от трёх etcd-узлов и load balancer для них, от двух worker-узлов. Если мы будем хостить какие-либо web-приложения в кластере, доступ к которым необходимо обеспечить извне, может потребоваться либо внешний load balancer, либо ingress. Однако, это отдельная большая тема, достойная отдельной статьи. Нам потребуется 5 виртуальных машин. На первых трёх будут развёрнуты master-узлы Kubernetes и etcd-серверы. На двух оставшихся worker-узлы Kubernetes и узлы haproxy-кластера. Важный момент, почему мастеров 3? Дело в том, что etcd-узлов в кластере должно быть не менее трёх. Если их будет 2, в случае если один из них выйдет из строя или будет отключён, голосование по выбору лидера etcd-кластера не сможет завершиться, и единственный оставшийся etcd-узел будет недоступен, а вместе с ним и функциональность Kubernetes-кластера. Таким образом, узлов в etcd-кластере должно быть не менее 3. etcd-узлы я планирую размещать вместе с master-узлами Kubernetes, чтобы не плодить виртуалки. Поэтому master-узлов должно быть 3. Worker-узлов может быть любое количество. Я выбрал 2, чтобы можно было симулировать выход одного из них из строя и наблюдать за миграцией подов на оставшийся. Добавить новые worker-узлы в кластер можно в любой момент. В состав кластера будут входить следующие виртуалки: Имя узла IP-адрес узла Роли узла Процессор Объём ОЗУ master01   10.44.44.11 etcd, k8s-master 2vcpu 4GB master02 10.44.44.12 etcd, k8s-master 2vcpu 4GB master03 10.44.44.13 etcd, k8s-master 2vcpu 4GB worker01 10.44.44.14 haproxy, k8s-worker 2vcpu 4GB worker02 10.44.44.15 haproxy, k8s-worker 2vcpu 4GB Для начала необходимо создать виртуалки для нашего кластера. Xen поддерживает несколько техник виртуализации. Одна из них называется paravirtualization. Если кратко, эта техника не требует от процессора встроенной поддержки виртуализации. На первый взгляд это может показаться незначительным, ведь большинство современных процессоров поддерживают специальные расширения для виртуализации. На практике же это означает ускорение работы виртуалок, так как не требует перехода между пользовательским контекстом и контекстом ядра ОС. Для Linux-виртуалок нужно пользоваться именно этим видом виртуализации. Каких-либо специальных драйверов, в отличии от Windows HVM виртуалок, ставить не нужно, всё уже есть в ядре Linux. В Xen PV-домены можно создать вручную или с помощью набора инструментов xen-tools. Это набор скриптов, которые позволяют создать из шаблона виртуалку одного из дистрибутивов Linux (и не только), настроив её с помощью параметров командной строки и «скелета» файловой системы (набор папок и файлов, которые должны быть скопированы в файловую систему виртуалки). Я буду использовать LVM для хранения дисков и Debian 11 в качестве гостевой ОС. Поскольку мне нужно будет создать 5 подобных друг другу виртуалок, я решил немного автоматизировать этот процесс и создал следующий простой скрипт (я назвал его create-debian-pv.sh): Скрипт необходимо сделать запускаемым: В первом параметре указывается имя хоста, во втором последняя цифра IP-адреса и MAC-адреса. Для простоты я принял следующее соглашение к формированию MAC-адреса: «00:16:3e» — стандартный префикс MAC-адреса Xen-виртуалок, «44:44» — взято из подсети, последний сегмент одинаков у MAC-адреса и IP-адреса. Мне так проще ориентироваться, но вы можете придумать что-то своё и скорректировать скрипт. «vg0» — название моей LVM volume group, «bullseye» — название одного из поддерживаемых данной командой дистрибутивов (это Debian 11, полный список можно посмотреть в папке /usr/share/xen-tools/). Создание раздела swap запрещено, так как этого требует Kubernetes, и, чтобы не расходовать место на диске, я отключил создание этого раздела полностью. Более подробно о доступных параметрах xen-create-image можно ознакомиться на его man-странице. Но перед тем, как использовать данный скрипт, на хосте Xen нужно установить необходимый пакет: Я предпочитаю сразу настроить SSH в новой виртуалке аналогично тому, как это сделано в ОС гипервизора (dom0). Для этого необходимо создать в папке (папка «скелета» файловой системы xen-tools, о которой я говорил ранее) /etc/xen-tools/skel/ необходимую структуру папок и скопировать файлы (также на хосте Xen). Я использую авторизацию с помощью пользовательского сертификата с установленным на нём паролем для доступа. Последовательно запускаем создание необходимых виртуалок: В процессе своей работы скрипт будет запрашивать пароль для учётной записи root. Вводим его дважды и вскоре виртуалка создана. Для каждой из них будет создан соответствующий файл конфигурации в папке /etc/xen. Например для master01 будет создан скрипт /etc/xen/master01.pv. Позднее, по мере необходимости, можно настроить количество памяти, количество виртуальных ядер процессора и другие параметры виртуальных машин. В каждом из созданных файлов конфигурации домена необходимо добавить следующую строку: localtime = 1. Это скажет Xen, что в виртуалке нужно использовать ваш часовой пояс, а не время по Гринвичу. Создайте новую папку на машине, имеющей сетевой доступ к виртуалкам, и настроенный SSH-клиент для доступа к хосту Xen. В данной папке будут размещаться скрипты, которые будут запускаться на виртуалках. Далее по тексту я буду называть эту папку рабочей. Все скрипты будут использовать общие настройки, которые я разместил в отдельном файле variables.sh.  Создайте его в рабочей папке. Параметры, которые можно/нужно заменить помечены соответствующим комментарием. Назначение параметров должно быть понятно из их имён. etcd используется в качестве основного хранилища информации о состоянии Kubernetes-кластера. Считайте, что это его база данных. Для устойчивости к отказам этого хранилища, как было сказано ранее, необходимо создать etcd-кластер. etcd можно развернуть различными способами, но я выбрал самый простой: развернуть на том же «виртуальном железе», что и master-узлы. Запускаем виртуалки master-узлов из консоли dom0 Xen: Создаём скрипт развёртывания etcd-узла install-etcd.sh в рабочей папке: И копируем все скрипты из рабочей папки в папку /root каждой виртуалки master-узлов Kubernetes (здесь и далее показано только для одной виртуалки): SSH-клиент запросит пароль (если вы его установили) доступа к приватному SSH-ключу и скопирует скрипты. Последовательно подключаемся по SSH к каждому master-узлу и запускаем скрипт из папки /root: Стоит отметить, что пока не отработает скрипт на втором узле, запущенный скрипт на первом узле не завершит своё выполнение. Это связано с тем, что etcd не может завершить голосование по выбору лидера пока не будет хотя бы двух узлов в кластере. После того как скрипт на всех трёх master-узлах будет запущен, статус etcd-узлов должен стать active (running): …а статус всего etcd-кластера должен выглядеть примерно так: Для более подробного ознакомления можно почитать в документации kubernetes. После того, как Kubernetes перестал поддерживать Dockershim (да и не нужен Docker, по большому счёту, в Kubernetes-кластере), осталось два довольно равнозначных варианта среды исполнения: containerd и CRI-O. Я выбрал первый. Поставить его можно двумя способами (компиляция из исходников не в счёт): воспользоваться репозиторием пакетов ОС или скачать релиз с GitHub. На момент написания статьи версия в репозитории Debian — 1.4.13, версия релиза в GitHub — 1.6.2. Разница существенная, поэтому я выбрал вариант с GitHub. Для того, чтобы понять, что такое среда выполнения, для чего она нужна, а также осознать, что Docker — не наше всё, рекомендую почитать статью Различия между Docker, containerd, CRI-O и runc. containerd нужно установить на всех узлах кластера, поэтому запускаем и виртуалки worker-узлов: Для установки containerd в рабочей папке создаём скрипт  install-containerd.sh следующего содержания: Снова копируем скрипты на все master- и worker-узлы: …и запускаем его на каждом узле: После его установки проверяем, что сервис работает (должно быть Active: active (running)): В рабочей папке создаём скрипт install-master-node.sh: Этот скрипт будет использоваться также и для остальных master-узлов, поэтому копируем его также и на них. Запускаем скрипт на первом master-узле master01: После успешного запуска в папке /root появится архив с сертификатами кластера certificates.tar.gz, который необходимо скопировать в папки /root остальных master-узлов. В результате успешного выполнения вы должны получить примерно такой вывод: Необходимо сохранить данный текст, так как далее нам понадобятся два параметра из него. После установки проверяем, что master-узел работает: kubectl используется в качестве основного инструмента администрирования Kubernetes-кластера. Мы его установим на всех узлах кластера, однако, если попробовать его использовать, мы получим ошибку с достаточно непонятным текстом сообщения. Для того, чтобы kubectl работал необходимо сказать ему, где искать конфигурацию для доступа к кластеру. Проще всего это сделать с помощью переменной окружения KUBECONFIG, указывающей на файл конфигурации. В зависимости от разных условий, файл этот может располагаться в разных местах. На master-узлах при работе из-под учётки root: /etc/kubernetes/admin.conf. На worker-узлах при работе из-под учётки root: /etc/kubernetes/kubelet.conf. На любых узлах при работе из-под другой учётки: $HOME/.kube/config. В последнем случае этот файл необходимо создать или скопировать с master-узлов. Устройство этого файла — тема достаточно обширная, поэтому детально описывать её здесь я не буду. Ознакомиться можно здесь: Organizing Cluster Access Using kubeconfig Files. После того, как файл найден/скопирован/создан в файле .bashrc (или аналогичном, вашей командной оболочки) добавляем следующую строку (показано для случая master-узел из-под root): И перезагружаем оболочку (показано для bash): Рекомендую установить kubectl на вашей рабочей машине. Дистрибутивы есть для всех основных ОС, включая Windows. Хотя на Windows я всё же предпочитаю работать не из PowerShell, а из bash в WSL-виртуалке. Для развёртывания оставшихся master-узлов используется тот же скрипт install-master-node.sh. Помимо скриптов, как было сказано ранее, необходимо скопировать в папку скриптов на целевые машины архив с сертификатами. Без этого архива скрипт не отработает. Проще всего распространить данный архив на все master-узлы можно, скопировав его вначале в рабочую папку с master01, а затем из рабочей папки на master02 и master03. После установки посредством скрипта install-master-node.sh проверяем, что все master-узлы работают: Worker-узлы развёртываем с помощью следующего скрипта install-worker-node.sh, который необходимо создать в рабочей папке: Как и в предыдущих шагах копируем все скрипты на worker-узлы: Подключаемся по SSH к узлу и запускаем скрипт: В ходе его выполнения будут заданы два вопроса про токен и SHA его сертификата. Их значения нужно взять из вывода, полученного при развёртывании первого master-узла. В моём случае это были: 635j2y.7ar0dbhq7l77jne0 и 8fab070cc51d4449d8fa0fc86348aeccc0554ca5e473da3a5138c6fc5a3f5e77 соответственно. Время жизни токена ограничено 24 часами. Поэтому если между развёртыванием первого master-узла и worker-узла пройдёт более 24 часов, вам необходимо повторно сгенерировать этот токен. Для этого, подключившись к кластеру, необходимо выполнить следующую команду и использовать полученный токен и его хэш-сумму для скрипта install-worker-node.sh. Последним штрихом будет создание haproxy-кластера для доступа worker-узлов к master-узлам. Зачем это нужно? Дело в том, что в конфигурации worker-узла жёстко прописывается адрес одного из master-узлов. В этом можно убедиться, найдя в файле /etc/kubernetes/kubelet.conf на worker-узле параметр server:. Если этот master-узел «приляжет», worker-узел «отвалится» от кластера. Чтобы этого не происходило, и кластер не терял свои worker-узлы, необходимо обеспечить защиту от подобных проблем. Одно из возможных решений реализовать доступ к control-plane через HA-proxy. Создаём в рабочей папке скрипт install-haproxy.sh со следующим содержимым: И, как обычно, копируем все скрипты из рабочей папки на worker-узлы: Запускаем скрипт на worker-узлах: После этого проверяем, что кластер работает и доступен: Кластер работает, но, в моём случае, пока не готов к использованию. Необходимо реализовать ещё, как минимум, две задачи: обеспечить доступ извне к web-приложениям с помощью ingress и настройки роутера, обеспечить хранение данных на дисках. Однако, это выходит за рамки данной статьи. Я планирую осветить реализацию этих задач, а также развёртывание одного web-приложения в кластере в будущих статьях. Благодарю за внимание. Надеюсь моя статья поможет вам разобраться с развёртыванием собственного кластера.