Install Kubernetes cluster
Last updated
Last updated
https://habr.com/ru/companies/domclick/articles/682364/
В предыдущей статье я рассказывал, как построить простой кластер Kubernetes с одним мастер-узлом. Прошло время, опали листья... и мне захотелось большего, поэтому решил позариться на высокодоступные кластеры. В интернете много статей о том, как построить подобное решение, и давайте даже опустим тот факт, что многие из них уже устарели. Одно дело — установить кластер, а как же обслуживание: удаление, добавление, замена узлов? Про это и не вспоминают! В итоге оказалось, что не всё так просто, и вот, спустя больше ста установок, удалений и замен, у меня получилось собрать подробнейшее руководство по установке и, главное, обслуживанию highly available кластера с помощью Kubespray.
Высокодоступный кластер (aka high-availability) - это еще один шажок к production-ready кластеру. Как написано в официальной документации, построить высокодоступный кластер значит:
Отделить плоскость управления (мастер) от рабочих узлов
Реплицировать компоненты плоскости управления на несколько узлов
Добавить балансировщик нагрузки на API Kubernetes
Иметь достаточное количество рабочих узлов, чтобы выдержать нештатные ситуации и высокие нагрузки
Если подходить серьезно к вопросу, то наш будущий кластер будет квази high-available (в основном из-за внешнего балансировщика). Кластер будет состоять из четырёх узлов — двух мастеров и двух рабочих. Машины с характеристиками получше можно использовать как рабочие, а машины послабее — как мастера. На последних не будет запускаться рабочая нагрузка.
Сетап кластера:
Kubenetes version - 1.23.7
Сontainer runtime - Сontainerd 1.6.4
Network plugin - Calico 3.22.3
Доступные виртуалки и их роли я распределил так:
IP 185.186.142.53 - Master #1
IP 185.186.142.5 - Master #2
IP 46.8.19.144 - Worker #1
IP 46.8.19.244 - Worker #2
У всех машин характеристики: 2 CPU 3,0 ГГц, 4 Гб RAM, 100 Гб HDD, ОС Ubuntu 20.04. На рабочих машинах заявлена частота процессора 3,6 ГГц, хотя команда grep MHz /proc/cpuinfo
говорит, что фактически 3 ГГц (на мастер-узлах и того чуть меньше). По стоимости четыре машины в месяц обходятся в 2700 руб. (с учётом скидки за оплату на три месяца вперёд). Хочу опять отметить, насколько такой handmade дешевле Kubernetes-as-a-Service решений, аж на 75%!
Важно (но не обязательно) чтобы ваш VPS провайдер поддерживал снимки виртуальных машин, это облегчит обслуживание и тренировку по установке кластера.
Устанавливать кластер будем с домашней машины (далее — Ansible-машина). На ней должны быть Python, Ansible версии 2.4 или выше, и Jinja (это всё мы установим немного позже).
Большая головная боль при установки Kubernetes на "голое" железо - это отсутствие внешнего балансировщика. Для пользователя облачного сервиса GKE или AWS балансировщик прилагается в комплекте.
В предыдущей своей статье проблему решал с помощью MetalLb, в этот раз попробую другой подход. Все 4 узла смогут принимать трафик извне, так как поды ingress-nginx будут развернуты на каждом узле (с помощью ресурса Daemonset) и использовать порт 80/443 этой машины.
И конечно нужно привести цитату с предостережением по безопасности данного решения:
Enabling this option exposes every system daemon to the NGINX Ingress controller on any network interface, including the host's loopback. Please evaluate the impact this may have on the security of your system carefully.
Заключительный штрих - я заказал доменное имя awesomeservice.pro на которое будут разрешаться все 4 IP адреса, таким образом задействуем DNS балансировку трафика. Балансировка осуществляется с помощью алгоритма Round Robin — алгоритма кругового обслуживания. Первый запрос передается одному серверу, затем следующий запрос передается другому, и так далее до достижения последнего сервера. Затем направление запросов начинается сначала. Это самое бюджетное и простое решение которое я нашел на данный момент. Именно из-за DNS балансировки будущий кластер выйдет почти высокодоступным. Данное решение имеет ряд неприятных минусов:
Сложно управлять пулом адресов. Хорошо если DNS провайдер предоставляет API для программного изменения адресов. Но это лишний софт, плюс надо учитывать TTL на стороне клиента, его в таком случае советуют ставить на минимальное значение.
И самая большая проблема - нет отслеживания состояния серверов. Если одна машина из пула выйдет из строя, DNS сервер все равно будет отдавать этот адрес. Эту проблему и её последствия я наглядно продемонстрирую после установки кластера.
альтернативное решение
Если ваш VPS провайдер позволяет создавать Virtual IP, то можно его привязать ко всем 4 удаленным машинам и тогда не нужна будет никакая DNS балансировка. Мой провайдер, к сожалению, не предоставляет такой функционал, поэтому протестировать такое решение не могу. А там, где есть данная фича VPS стоят неоправданно дорого.
Приступим к делу.
В основе главы лежит эта статья, но на текущий момент она уже устарела, поэтому некоторые разделы будут продублированы и дополнены либо изменены.↑
Этот раздел необходимо выполнить для каждой виртуальной машины будущего кластера. Прежде всего настроим SSH-доступ без пароля. Для этого выполните команду ssh-copy-id
на своей локальной машине. Например, у меня она выглядит так:
Тут необходимо будет ввести пароль от удалённой машины. После успешного выполнения команды подключаемся к удалённой машине без пароля:
Установим Python:
Включим переадресацию IPv4:
Отключим подкачку памяти:
Пример из жизни №1
Раньше я полагал, что поставщики виртуалок предоставляют чистые образы ОС. Как оказалось, это не совсем так. Я пробовал установить Kubernetes на VPS двух провайдеров. У первого всё работало замечательно, а у второго (который был предпочтителен из-за низкой цены) установка кластера прерывалась на середине из-за внезапного пропадания интернета, а точнее, невозможности скачать определённый файл.
Поиск в интернете упорно ничего не давал, подсказали только в техподдержке: предложили заглянуть в файл resolv.conf и проверить наличие в конфигурации серверов адресов 1.1.1.1 или 8.8.8.8. Как оказалось, у этого провайдера интересная преднастройка ОС, и файл /etc/resolv.conf представляет собой simlink. О чём недвусмысленно сообщал объёмный комментарий в самом файле:
И в самом файле, конечно, этих резолверов обнаружено не было. Проблему удалось решить только удалением simlink и пересозданием файла с добавлением двух DNS-резолверов (в принципе, будет достаточно одного 1.1.1.1 или 8.8.8.8).
В итоге файл выглядит следующим образом:
Удаленная машина успешно настроена и готовка к установке Kubernetes. Инструкции из этого подраздела повторите на всех оставшихся машинах будущего кластера.
Также крайне рекомендую на этом этапе сделать снимок системы, чтобы при переустановке кластера можно было откатить систему до текущего состояния. Причём даже не понадобится перенастраивать SSH-доступ без пароля. И тогда в будущем об этом подразделе можно забыть. Функциональность снимков предоставляется провайдером VPS (у меня это vmmanager).
Эти инструкции нужно выполнить только на своей локальной машине, с которой будет устанавливаться Kubernetes. Перейдите в подготовленную директорию и клонируйте репозиторий проекта Kubespray:
Помните, что подобные инструкции по установке любого софта без указания версии могут в будущем привести к проблемам. Либо статья устареет, либо новые версии могут быть обратно несовместимыми. Если вы уверены в себе и готовы решать проблемы и несостыковки, клонируйте мастер-ветку. У меня на данный момент tag v2.19.0. Команда для переключения:
Перейдём к установке Kubernetes-кластера. Подготовим наш инвентарь, шаблон находится в папке sample, мы его скопируем под новым именем и будем использовать при установке:
Должна появиться новая директория k8s*.* Теперь объявим переменную IPS
массивом с перечислением наших виртуальных машин, это нужно для последующего генерирования конфигурации:
Сгенерируем конфигурацию в новый инвентарь:
Был создан файл, посмотрим его содержимое:
У меня конфиг выглядит следующих образом
Получилась такая конфигурация кластера:
Мастер-узлы перечисляются в разделе kube_control_plane
, в моём случае это node1 и node2.
Всего четыре Kubernetes-узла: node1, node2, node3 и node4.
Etcd-кластер будет установлен на три хоста: node1, node2 и node3. Три потому, что для etcd-кластера жизненно необходим кворум большинства, то есть всегда должно быть нечётное количество работающих узлов. Если попробуете удалить один из хостов в etcd:hosts
, то Ansible-роль завершится с ошибкой о необходимости нечётного количества узлов
Настройки будущего кластера находятся в папке group_vars. Чтобы не устанавливать Helm вручную на каждом мастер-узле, установим в файле addons.yaml параметр helm_enable
равным true
:
В том же файле addons.yaml раскомментируем и активируем nginx-ingress, а также параметр ingress_nginx_host_network, благодаря которому, к каждому узлу будет привязана пода nginx-ingress:
Итоговый файл выглядит следующим образом
Добавим в конфигурацию Ansible пользователя, под которым логинимся по SSH:
В группе ssh_connection
добавьте параметр remote_user
, равный root
:
Полностью файл выглядит так:
И наконец, команда запуска установки кластера. Выполните её в корне директории kubespray:
Установка кластера может занять от получаса до полутора часов, в зависимости от скорости интернета. После установки вывод в консоли должен быть примерно таким:
Теперь нужно проверить состояние узлов. Выполните команду:
Затем важно проверить, работают ли системные поды (coredns, kube-controller-manager, kube-scheduler и тд.):
Если появилась ошибка CrashLoopBackOff (пример из жизни №2)
Возможно, после установки возникнет ошибка CrashLoopBackOff у coredns и nodelocaldns:
Проблема легко гуглится, и решение подробно описано тут. Отредактируем конфигурацию kubelet:
В файле необходимо подправить поле resolvConf
на:
И перезагрузить машину:
Выполните это на всех узлах, рабочих и управляющих. После этого поды перезапустятся и ошибка должна исчезнуть:
Готово, установка Kubernetes-кластера завершена. Теперь проверим на практике. насколько кластер высокодоступный, то бишь high-availability.
На любом из мастер-узлов развернём простое приложение из предыдущей статьи, которое по GET-ручке возвращает случайно сгенерированный UUID. Создадим три ресурса, первый — deployment: