Поднимаем Kubernetes с нуля

Создание кластера Kubernetes может казаться сложным процессом, который включает в себя множество настроек, но сложные вещи могут стать более понятными, когда их разложить на части. В этой статье мы демистифицируем процесс создания кластера Kubernetes, понимая минимальный набор компонентов, необходимых для запуска Kubernetes кластера.

Введение

Прежде всего, важно иметь виртуальную машину (VM), на которой запущено Debian- или RHEL-основное дистрибутивы Linux. Для этого урока мы будем использовать Debian 11 VM, запущенную в виртуальной среде KVM. Сам дистрибутив Debian был слегка модифицирован моими личными так называемых «dotfiles», которые обеспечат нам более приятный опыт использования командной строкой.

Tерминал вдохновленный конфигурацией Garuda - дистрибутивом Linux на базе Arch.

Tерминал вдохновленный конфигурацией Garuda — дистрибутивом Linux на базе Arch.

Предварительные требования

После настройки VM мы можем перейти к следующим шагам в создании кластера Kubernetes с использованием cri-o в качестве контейнерного рантайма. Во-первых, нам необходимо внести несколько необходимых изменений, чтобы пройти проверки при инициализации kubeadm init. Об этих пунктах чуть ниже.

В качестве первого шага мы должны следовать главной рекомендации при работе с программным обеспечением — проверка на наличие обновлений и установка последних пакетов:

sudo apt update
sudo apt upgrade

Кроме того, необходимо загрузить и установить несколько зависимостей:

sudo apt install software-properties-common apt-transport-https ca-certificates gnupg2 gpg sudo

1. Отключение swap

В Linux, swap — это полезный способ расширения доступной оперативной памяти, когда физическая память исчерпана, позволяющий процессам продолжать работу. Однако при настройке узла для кластера Kubernetes обычно рекомендуется отключить swap по нескольким причинам.

Во-первых, для эффективной работы Kubernetes требуется значительное количество памяти, и любое снижение производительности из-за использования swap может повлиять на производительность всего кластера. Кроме того, Kubernetes предполагает, что на узле есть фиксированное количество доступной памяти, и если swap включен, это может вызвать путаницу и неожиданное поведение.

Кроме того, отключение swap может помочь предотвратить риск вызова так называемого «OOM killer». OOM killer — это процесс ядра Linux, который отвечает за завершение процессов, когда система исчерпывает свободную память. Хотя это и предназначено для защиты от сбоев системы, это может привести к непредсказуемому поведению при запуске рабочих нагрузок Kubernetes, так как OOM killer может завершить критические компоненты кластера.

Мы можем узнать, использует ли наша машина swap-память, используя команду htop:

На этом скриншоте своп равен 0. Однако. если бы это было иначе, нам нужно было бы отключить его.

На этом скриншоте своп равен 0. Однако. если бы это было иначе, нам нужно было бы отключить его.

В целом, хотя swap-память может быть полезным инструментом для расширения доступной памяти на машине Linux, при настройке узла для кластера Kubernetes обычно рекомендуется отключить его, чтобы обеспечить надежную и предсказуемую производительность. Мы можем сделать это, выполнив следующую команду:

swapoff -a

Чтобы убедиться, что swap остается отключенным после запуска, нам необходимо раскомментировать строку в файле /etc/fstab, который инициализирует swap-память при загрузке Linux:

5a92cd7cecb5290c319f279f0aa95126.png

В этом конкретном случае в качестве раздела swap использовался файл с именем swap.img, который мы можем удалить после этого с правами root:

sudo rm /swap.img 

Примечание: В современных дистрибутивах Linux часто используется swap-файл вместо отдельного раздела swap. Если ваша система настроена с отдельным разделом swap, важно учитывать это при настройке кластера Kubernetes и избегать настройки раздела swap при установке виртуальной машины.

Теперь вы можете перезагрузить машину, и swap должен быть отключен. Используйте htop еще раз, чтобы подтвердить это.

2. Включение модулей ядра Linux

Включение необходимых модулей ядра Linux — это важный шаг при настройке контейнерного запуска для кластера Kubernetes. Эти модули необходимы для обеспечения функциональности сетевого подключения и хранения данных в Kubernetes Pods, которые являются наименьшими и простейшими единицами в системе Kubernetes. Модули сетевого подключения позволяют Kubernetes обеспечивать сетевое соединение между различными Pods в кластере, а модули хранения — постоянное хранилище данных в Pods кластера.

Для включения этих модулей ядра обычно нужно изменить параметры ядра Linux и загрузить соответствующие модули ядра с помощью утилиты modprobe. Это обеспечивает доступность необходимой функциональности для кластера Kubernetes и позволяет Pods эффективно общаться и хранить данные. Включая эти модули, мы можем гарантировать, что наш кластер Kubernetes хорошо подготовлен к выполнению широкого спектра задач и может предоставить надежную и масштабируемую платформу для запуска контейнеризованных приложений.

Прежде чем продолжить, мы войдем под учетную запись root и выполним все нижеуказанные действия с привилегиями этого суперпользователя:

sudo su - root

Вот два модуля ядра Linux, которые нам нужно включить:

  1. br_netfilter — этот модуль необходим для включения прозрачного маскирования и облегчения передачи трафика Virtual Extensible LAN (VxLAN) для связи между Kubernetes Pods в кластере.

  2. overlay — этот модуль обеспечивает необходимую поддержку на уровне ядра для правильной работы драйвера хранения overlay. По умолчанию модуль overlay может не быть включен в некоторых дистрибутивах Linux, и поэтому необходимо включить его вручную перед запуском Kubernetes.

Мы можем включить эти модули, выполнив команду modprobe вместе с флагом -v(подробный вывод), чтобы увидеть результат:

modprobe overlay -v
modprobe br_netfilter -v

После этого мы должны получить следующий вывод:

e3aae83c6f93ad0ea1b4056da48e0df8.png

Чтобы убедиться, что модули ядра загружаются после перезагрузки, мы также можем добавить их в файл /etc/modules:

echo "overlay" >> /etc/modules
echo "br_netfilter" >> /etc/modules

После включения модуля br_netfilter необходимо включить IP-пересылку в ядре Linux, чтобы обеспечить сетевое взаимодействие между подами и узлами. IP-пересылка позволяет ядру Linux маршрутизировать пакеты с одного сетевого интерфейса на другой. По умолчанию IP-пересылка отключена на большинстве дистрибутивов Linux из соображений безопасности, поскольку она позволяет использовать машину как маршрутизатор.

Однако в кластере Kubernetes нам нужно включить IP-пересылку, чтобы позволить подам общаться друг с другом, а также пересылать трафик наружу. Без IP-пересылки поды не смогут получить доступ к внешним ресурсам или взаимодействовать друг с другом, что приведет к неисправности кластера.

Для этого мы должны записать »1» в файл конфигурации с названием »ip_forward»:

echo 1 > /proc/sys/net/ipv4/ip_forward

С этих необходимых шагов для настройки требований нашего кластера Kubernetes мы можем перейти к установке Kubelet — сердцу Kubernetes.

Установка Kubelet

Установка Kubelet, возможно, самый простой шаг, поскольку он очень хорошо описан в официальной документации Kubernetes. В основном, нам нужно выполнить следующие команды:

mkdir /etc/apt/keyrings
sudo curl -fsSLo /etc/apt/keyrings/kubernetes-archive-keyring.gpg https://packages.cloud.google.com/apt/doc/apt-key.gpg
echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
apt-get update
apt-get install -y kubelet kubeadm kubectl
apt-mark hold kubelet kubeadm kubectl 

Строка apt-mark hold kubelet kubeadm kubectl сообщает нашему менеджеру пакетов не обновлять эти компоненты, так как это необходимо делать вручную при обновлении кластера.

Запустите команду, скрестите пальцы и надеемся, что все сработает:

ec8efd3af6dec582c5f1d0f42f9bb154.png

Теперь, когда мы установили kubelet, kubeadm и kubectl, мы можем продолжить установку среды выполнения контейнеров, которая будет запускать компоненты Kubernetes.

Установка нашей среды выполнения контейнеров

Kubernetes — это система оркестрации для контейнеризированных нагрузок. Он управляет развертыванием, масштабированием и работой контейнеризированных приложений на кластере узлов. Однако Kubernetes не запускает контейнеры напрямую. Вместо этого он полагается на среду выполнения контейнеров, которая отвечает за запуск, остановку и управление контейнерами. Среда выполнения контейнеров — это программное обеспечение, которое запускает контейнеры на узлах в кластере Kubernetes.

Существует несколько сред выполнения контейнеров, которые можно использовать с Kubernetes, включая Docker, cri-o, containerd и другие. Выбор среды выполнения контейнеров зависит от таких факторов, как производительность, безопасность и совместимость с другими инструментами в инфраструктуре. Для наших целей мы выберем cri-o в качестве среды выполнения контейнеров нашего Kubernetes кластера.

Следуя официальной документации по cri-o, нам сначала нужно указать переменные, необходимые для загрузки желаемой версии cri-o для нашего конкретного дистрибутива Linux. Учитывая, что мы запускаем Debian 11, а на момент написания 1.24 — это последняя версия cri-o, мы экспортируем несколько переменных:

export OS=Debian_11
export VERSION=1.24

Мы также можем проверить, сохранены ли эти переменные в текущей сессии терминала, передав команду env в grep:

4e6180d1e4fa947f738440083d608019.png

Теперь мы можем начать установку контейнерного времени выполнения:

echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/Release.key | apt-key add -
curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -
apt-get update
apt-get install -y cri-o cri-o-runc

Если все прошло успешно, мы должны получить следующий вывод:

902e1c9309b0de4f34188688409b5775.png

Теперь, когда мы установили пакеты cri-o, мы должны включить и запустить cri-o как службу:

systemctl enable crio
systemctl start crio
systemctl status crio

Команда systemctl status crio должна вывести текущее состояние службы:

5fd583177030186d9168cbfe0301cf85.png

Поздравляем! Наш узел Kubernetes готов к запуску.

Запуск нашего первого узла

Я надеюсь, вы плотно затянули свои ботинки, потому что наша сеть Pod будет иметь CIDR 10.100.0.0/16.

Что такое сетевой CDR?

CIDR (Classless Inter-Domain Routing) — это обозначение, используемое для представления префикса сети в адресации IP. Это комбинация IP-адреса и маски подсети, представленных в виде »/<маска подсети>». Маска подсети определяет, какая часть IP-адреса является сетевой, а какая — хостовой.

В случае диапазона 10.100.0.0/16 это означает, что IP-адрес — 10.100.0.0, а маска подсети состоит из 16 бит. Маска подсети из 16 бит указывает, что первые 16 бит IP-адреса являются сетевой частью, а оставшиеся 16 бит — хостовой частью. Это означает, что наш хост может управлять до 65 536 IP-адресами, находящимися в диапазоне от 10.100.0.0 до 10.100.255.255.

Теперь, когда мы решили, что наш маленький, но могущественный кластер Kubernetes будет иметь сеть из 65 536 IP-адресов, мы можем проверить нашу конфигурацию.

Dry run

Для запуска нашего кластера мы будем использовать официальную утилиту kubeadm. Прежде чем применять наши изменения, мы можем запустить настройку сети с использованием флага --dry-run без каких-либо изменений:

kubeadm init --pod-network-cidr=10.100.0.0/16 --dry-run

Если наша виртуальная машина была настроена правильно, мы должны получить длинный вывод:

a2b1cff2780b4b451581f6d8051e4a64.png

Если так называемые «предварительные проверки» выдают ошибку, то, выполнив быстрый поиск в Google, мы можем исправить проблему и в последствии применить эти изменения без флага --dry-run.

Инициализация нашего кластера

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

После выполнения этой команды kubeadm превратит нашу виртуальную машину в узел управления Kubernetes, состоящий из следующих основных компонентов:

  • etcd — хранилище ключ-значение, используемое для хранения состояния всего кластера Kubernetes;

  • kube-scheduler — компонент управления, который отслеживает вновь созданные Pod без назначенного узла и выбирает для них узел для запуска;

  • kube-controller-manager — компонент управления, запускающий процессы контроллера.

Если наша инициализация прошла успешно, мы получим вывод с командой, которую можно использовать для присоединения других узлов:

bedb875de10e1b081e706933a2ae7dcf.png

Обратите внимание на эту команду присоединения:

kubeadm join 192.168.122.97:6443 --token nljqps.vypo4u9y07lsw7s2 \
        --discovery-token-ca-cert-hash sha256:f820767cfac10cca95cb7649569671a53a2240e1b91fcd12ebf1ca30c095c2d6

Примечание: По умолчанию токен этой команды присоединения действителен только в течение 2 часов, после чего вам нужно будет сообщить kubeadm, чтобы он выдал новый токен для присоединения других узлов.

После того, как мы запустили первый узел управления, мы можем использовать crictl так же, как используем команду docker, и увидеть, какие компоненты работают в нашем контейнерном времени выполнения cri-o:

1d449b651a5967e60b714b2c994ab43b.png

Как мы видим, вышеупомянутые компоненты Kubernetes все работают как контейнеры внутри первой ноды нашего кластера .

Добавляем нашего первого воркера

По умолчанию узел Control Plane запускает только контейнеры, которые являются частью системы Kubernetes, но не Pod-ы с контейнерными приложениями. Теперь, когда у нас есть работающий узел Control Plane, мы можем приступить к добавлению первого узла рабочего процесса.

Перед этим мы должны выполнить те же самые шаги, что и при настройке нашего узла управления. Я создал вторую виртуальную машину под названием «worker1» в правой части моего оконного менеджера терминалов tmux:

b0176644ed015bf568035f27c55ce279.png

После того, как мы выполнили те же процедуры, я копирую токен присоединения из шагов выше:

kubeadm join 192.168.122.97:6443 --token nljqps.vypo4u9y07lsw7s2 \
        --discovery-token-ca-cert-hash sha256:f820767cfac10cca95cb7649569671a53a2240e1b91fcd12ebf1ca30c095c2d6

И вставляю его в окно worker1. kubeadm снова потребует время, чтобы пройти все проверки, прежде чем присоединить рабочего к узлу Control Plane.

63bc1f60e765d7da499b1ee459d1f799.png

Как только это будет сделано, мы можем поздравить себя с созданием кластера Kubernetes с нуля!

Доступ к нашему кластеру с помощью kubectl

Последний шаг, который нам нужно сделать — скопировать учетные данные администратора, которые будут использоваться kubectl для управления ресурсами нашего кластера через компонент API-сервера Kubernetes, работающий на нашем узле Control Plane.

В целях этого руководства мы будем получать доступ к нашему кластеру через узел Control Plane. Мы скопируем конфигурацию в домашний каталог нашего пользователя следующим образом:

mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

После этого мы можем использовать команду kubectl для управления, создания, редактирования, удаления и развертывания нашего кластера Kubernetes. Для начала мы можем получить список узлов, которые в настоящее время являются частью нашего кластера Kubernetes:

kubectl get nodes

И мы получаем список, состоящий из нашего узла Control Plane и главного рабочего узла:

b06e0e4bcb60baf5550712a906dff657.png

Теперь мы можем создавать Pod-ы, сервисы, пространства имен и все прочие замечательные вещи!

Заключение

В заключение можно сказать, что процесс создания кластера Kubernetes с использованием cri-o в качестве контейнерного рантайма может показаться сложным на первый взгляд, но с правильным пониманием и знанием отдельных компонентов, его можно достичь относительно легко. Следуя шагам, описанным в этом учебнике, мы получили более глубокое понимание того, как работает Kubernetes, и требований, необходимых для настройки функционального кластера. Вооруженные этими знаниями, мы теперь можем уверенно экспериментировать и исследовать все возможности Kubernetes в наших средах разработки и эксплуатации.

© Habrahabr.ru