Развёртывание Kubernetes-кластера в Debian
Требуется: развернуть Kubernetes-кластер для получения опыта, связанного с настройкой и управлением Kubernetes-кластера, и дальнейшего его использования для разработки и хостинга персональных проектов.
Минимальная конфигурация кластера может состоять из одного-двух узлов: либо один master, которому разрешено хостить пользовательские нагрузки, либо один master и один worker. Однако, подобный кластер не будет, даже близко, похож на типичный промышленный high available (HA) кластер, а значит, полученный опыт будет сильно ограничен как в процессе развёртывания, так и в процессе эксплуатации. Конечно, ни о каком HA-кластере на одной физической машине речи быть не может, но, напомню, главная цель — получение опыта и площадки для экспериментов. К слову, если для разработки нужен кластер на рабочей станции, скажем для разработки cloud native приложений, или для изучения простейших команд kubectl, отличным выбором будет minikube.
Как выглядит минимально-достаточный промышленный 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-узлы в кластер можно в любой момент.
Файл настроек
Создайте новую папку на машине, имеющей сетевой доступ к виртуалкам. В данной папке будут размещаться скрипты, которые будут запускаться на виртуалках. Далее по тексту я буду называть эту папку рабочей.
Все скрипты будут использовать общие настройки, которые я разместил в отдельном файле variables.sh. Создайте его в рабочей папке.
#!/bin/bash # IP-адреса и имена хостов мастер-узлов Kubernetes. Замените на свои. master1_IP=192.168.3.211 master2_IP=192.168.3.212 master3_IP=192.168.3.213 master1_Hostname=master1 master2_Hostname=master2 master3_Hostname=master3 # IP-адрес и имя хоста, на котором выполняется скрипт. thisHostname=$(hostname) thisIP=$(hostname -i) # etcd-token. Замените на свой. Может быть любой строкой. etcdToken=my-etcd-cluster-token # CRI-socket. containerdEndpoint=unix:///run/containerd/containerd.sock # Версии пакетов. Замените на текущие актуальные. etcdVersion=3.5.8 containerdVersion=1.6.20 runcVersion=1.1.1 cniPluginsVersion=1.1.1 kubernetesVersion=1.27.1 calicoVersion=3.22 # Пространство адресов подов. Зависит от CNI-плагина. В данном случае используется Calico. podSubnet=10.10.0.0/16 # Пространство адресов сервисов. Замените на своё. Может быть любое, но должно быть достаточно большим. serviceSubnet=10.46.0.0/16
Параметры, которые можно/нужно заменить помечены соответствующим комментарием. Назначение параметров должно быть понятно из их имён.
Развёртывание etcd
etcd используется в качестве основного хранилища информации о состоянии Kubernetes-кластера. Считайте, что это его база данных. Для устойчивости к отказам этого хранилища, как было сказано ранее, необходимо создать etcd-кластер. etcd можно развернуть различными способами, но я выбрал самый простой: развернуть на том же «виртуальном железе», что и master-узлы.
Создаём скрипт развёртывания etcd-узла install-etcd.sh в рабочей папке:
#!/bin/bash source variables.sh etcdEnvironmentFilePath=/etc/etcd.env serviceFilePath=/etc/systemd/system/etcd.service function installAndConfigurePrerequisites { apt install curl -y } function downloadAndInstallEtcd { curl -L https://github.com/etcd-io/etcd/releases/download/v${etcdVersion}/etcd-v${etcdVersion}-linux-amd64.tar.gz --output etcd-v${etcdVersion}-linux-amd64.tar.gz tar -xvf etcd-v${etcdVersion}-linux-amd64.tar.gz -C /usr/local/bin/ --strip-components=1 } function createEnvironmentFile { cat > ${etcdEnvironmentFilePath} <<EOF ${thisHostname} > ${etcdEnvironmentFilePath} ${thisIP} >> ${etcdEnvironmentFilePath} EOF } function createServiceFile { cat > $serviceFilePath <<EOF [Unit] Description=etcd Documentation=https://github.com/coreos/etcd Conflicts=etcd.service Conflicts=etcd2.service [Service] EnvironmentFile=/etc/etcd.env Type=notify Restart=always RestartSec=5s LimitNOFILE=40000 TimeoutStartSec=0 ExecStart=/usr/local/bin/etcd \\ --name ${thisHostname} \\ --data-dir /var/lib/etcd \\ --listen-peer-urls http://${thisIP}:2380 \\ --listen-client-urls http://0.0.0.0:2379 \\ --advertise-client-urls http://${thisIP}:2379 \\ --initial-cluster-token ${etcdToken} \\ --initial-advertise-peer-urls http://${thisIP}:2380 \\ --initial-cluster ${master1_Hostname}=http://${master1_IP}:2380,${master2_Hostname}=http://${master2_IP}:2380,${master3_Hostname}=http://${master3_IP}:2380 \\ --initial-cluster-state new [Install] WantedBy=multi-user.target EOF } function removeDownloads { rm -f etcd-v${etcdVersion}-linux-amd64.tar.gz } installAndConfigurePrerequisites downloadAndInstallEtcd createEnvironmentFile createServiceFile removeDownloads systemctl enable --now etcd
И копируем все скрипты из рабочей папки в папку /root каждой виртуалки master-узлов Kubernetes (здесь и далее показано только для одной виртуалки):
scp *.sh root@192.168.3.211:/root
SSH-клиент запросит пароль (если вы его установили) доступа к приватному SSH-ключу и скопирует скрипты.
Последовательно подключаемся по SSH к каждому master-узлу и запускаем скрипт из папки /root:
./install-etcd.sh
Стоит отметить, что пока не отработает скрипт на втором узле, запущенный скрипт на первом узле не завершит своё выполнение. Это связано с тем, что etcd не может завершить голосование по выбору лидера пока не будет хотя бы двух узлов в кластере.
После того как скрипт на всех трёх master-узлах будет запущен, статус etcd-узлов должен стать active (running):
● etcd.service - etcd Loaded: loaded (/etc/systemd/system/etcd.service; enabled; vendor preset: enabled) Active: active (running) since Fri 2023-05-12 08:59:58 MSK; 4min 34s ago Docs: https://github.com/coreos/etcd Main PID: 412 (etcd) Tasks: 12 (limit: 4657) Memory: 209.9M CPU: 14.905s CGroup: /system.slice/etcd.service └─412 /usr/local/bin/etcd --name master1 --data-dir /var/lib/etcd --listen-peer-urls http://192.168.3.211:2380 --listen-cli>
…а статус всего etcd-кластера должен выглядеть примерно так:
root@master1:~# etcdctl --write-out=table --endpoints=192.168.3.211:2379,192.168.3.212:2379,192.168.3.213:2379 endpoint status +--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | ENDPOINT | ID | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS | +--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+ | 192.168.3.211:2379 | f9f7e4f118c2fa2a | 3.5.8 | 3.8 MB | false | false | 28 | 17163 | 17163 | | | 192.168.3.212:2379 | 3e04d49b592fc75d | 3.5.8 | 3.7 MB | true | false | 28 | 17163 | 17163 | | | 192.168.3.213:2379 | 61c0872d036471cc | 3.5.8 | 3.8 MB | false | false | 28 | 17163 | 17163 | | +--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
Установка containerd и runc
После того, как Kubernetes перестал поддерживать Dockershim (да и не нужен Docker, по большому счёту, в Kubernetes-кластере), осталось два довольно равнозначных варианта среды исполнения: containerd и CRI-O. Я выбрал первый. Поставить его можно двумя способами (компиляция из исходников не в счёт): воспользоваться репозиторием пакетов ОС или скачать релиз с GitHub. На момент написания статьи версия в репозитории Debian — 1.4.13, версия релиза в GitHub — 1.6.20. Разница существенная, поэтому я выбрал вариант с GitHub.
containerd нужно установить на всех узлах кластера
Для установки containerd в рабочей папке создаём скрипт install-containerd.sh следующего содержания:
#!/bin/bash source variables.sh function installAndConfigurePrerequisites { apt install curl -y cat <<EOF | tee /etc/modules-load.d/containerd.conf overlay br_netfilter EOF modprobe overlay modprobe br_netfilter # Настройка обязательных параметров sysctl. cat <<EOF | tee /etc/sysctl.d/99-kubernetes-cri.conf net.bridge.bridge-nf-call-iptables=1 net.ipv4.ip_forward=1 net.bridge.bridge-nf-call-ip6tables=1 EOF # Применяем изменения без перезагрузки. sysctl --system } function downloadAndInstallContainerd { # Загружаем релиз containerd. curl -L https://github.com/containerd/containerd/releases/download/v${containerdVersion}/containerd-${containerdVersion}-linux-amd64.tar.gz --output containerd-${containerdVersion}-linux-amd64.tar.gz tar -xvf containerd-${containerdVersion}-linux-amd64.tar.gz -C /usr/local # Создаём файл конфигурации containerd. mkdir /etc/containerd/ containerd config default > /etc/containerd/config.toml # Разрешаем использование systemd cgroup. sed -i "s/SystemdCgroup = false/SystemdCgroup = true/g" /etc/containerd/config.toml # Создаём файл сервиса containerd. cat > /etc/systemd/system/containerd.service <<EOF [Unit] Description=containerd container runtime Documentation=https://containerd.io After=network.target local-fs.target [Service] ExecStartPre=-/sbin/modprobe overlay ExecStart=/usr/local/bin/containerd Type=notify Delegate=yes KillMode=process Restart=always RestartSec=5 LimitNPROC=infinity LimitCORE=infinity LimitNOFILE=infinity TasksMax=infinity OOMScoreAdjust=-999 [Install] WantedBy=multi-user.target EOF # Разрешаем и запускаем сервис containerd. systemctl daemon-reload systemctl enable --now containerd } function downloadAndInstallRunc { # Загружаем и устанавливаем низкоуровневую службу запуска контейнеров. curl -L https://github.com/opencontainers/runc/releases/download/v${runcVersion}/runc.amd64 --output runc.amd64 install -m 755 runc.amd64 /usr/local/sbin/runc } function downloadAndInstallCniPlugins { curl -L https://github.com/containernetworking/plugins/releases/download/v${cniPluginsVersion}/cni-plugins-linux-amd64-v${cniPluginsVersion}.tgz --output cni-plugins-linux-amd64-v${cniPluginsVersion}.tgz mkdir -p /opt/cni/bin tar Cxzvf /opt/cni/bin cni-plugins-linux-amd64-v${cniPluginsVersion}.tgz } function removeDownloads { rm -f containerd-${containerdVersion}-linux-amd64.tar.gz rm -f runc.amd64 rm -f cni-plugins-linux-amd64-v${cniPluginsVersion}.tgz } installAndConfigurePrerequisites downloadAndInstallContainerd downloadAndInstallRunc downloadAndInstallCniPlugins removeDownloads systemctl restart containerd
Снова копируем скрипты на все master- и worker-узлы:
scp *.sh root@192.168.3.211:/root
…и запускаем их на каждом узле:
./install-containerd.sh
После его установки проверяем, что сервис работает (должно быть Active:
active (running)):
● containerd.service - containerd container runtime Loaded: loaded (/etc/systemd/system/containerd.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-05-07 16:41:01 MSK; 4 days ago Docs: https://containerd.io Main PID: 666 (containerd) Tasks: 119 Memory: 1.3G CPU: 7min 4.139s CGroup: /system.slice/containerd.service ├─ 666 /usr/local/bin/containerd ├─2591 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 6cedd48fff62593eacbbea68bdf6a01e64f401a420efa3a6e4c70177b74462c0 -address /run/cont> ├─2615 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 7240ab10082c27e67f872847e991d1b1c4421bce7319969e93fa803ab792bc8b -address /run/cont> ├─2638 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 9a4847bcdb18b25189ff5550bbc0e5fa1538d4333c3bcc83e97a9edb6c89f681 -address /run/cont> ├─2961 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id fb9cd36bc95d773b8648862dba6b984791ce87fa7e297232ccbbfd1933f4b09f -address /run/cont> ├─3002 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id ef340c8986faf39512526bacfcb8cf598848cee2876502af37e80b5d11b58891 -address /run/cont> ├─4277 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id a0590d157367ba34a12e1ad8045efefb8e4cdc94480dec1e09bab38d44b10e97 -address /run/cont> ├─4443 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 60936f49daca0fdb61f8e3cc536d1376abb960652c1030d1b075fdf94ebbf584 -address /run/cont> └─4513 /usr/local/bin/containerd-shim-runc-v2 -namespace k8s.io -id 7b107aa8d0f19a2b772f3ae084a0b9539cc61c3e2aa4e675f8f09190cf998997 -address /run/cont>
Развёртывание первого master-узла Kubernetes
В рабочей папке создаём скрипт install-master-node.sh:
#!/bin/bash source variables.sh function installAndConfigurePrerequisites { apt install -y apt-transport-https curl gnupg2 apparmor apparmor-utils curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF # Установить необходимые пакеты и зафиксировать их версию. apt update apt install -y kubelet=$kubernetesVersion-00 apt install -y kubeadm=$kubernetesVersion-00 apt install -y kubectl=$kubernetesVersion-00 apt-mark hold kubelet kubeadm kubectl } function createKubeadmConfig { cat > kubeadm-init.yaml <<EOF --- apiVersion: kubeadm.k8s.io/v1beta3 kind: InitConfiguration localAPIEndpoint: advertiseAddress: "${thisIP}" nodeRegistration: criSocket: "${containerdEndpoint}" --- apiVersion: kubeadm.k8s.io/v1beta3 kind: ClusterConfiguration kubernetesVersion: v${kubernetesVersion} apiServer: certSANs: - ${master1_IP} - ${master2_IP} - ${master3_IP} - 127.0.0.1 controlPlaneEndpoint: ${thisIP} etcd: external: endpoints: - http://${master1_IP}:2379 - http://${master2_IP}:2379 - http://${master3_IP}:2379 networking: podSubnet: "${podSubnet}" serviceSubnet: "${serviceSubnet}" dnsDomain: "cluster.local" EOF } function initializeMasterNode { kubeadm init --config=kubeadm-init.yaml } function installCalicoCNI { export KUBECONFIG=/etc/kubernetes/admin.conf kubectl apply -f https://docs.projectcalico.org/v${calicoVersion}/manifests/calico.yaml } function archiveCertificates { tar -zcvf certificates.tar.gz -C /etc/kubernetes/pki . } function extractCertificates { mkdir -p /etc/kubernetes/pki tar -xvf certificates.tar.gz -C /etc/kubernetes/pki } installAndConfigurePrerequisites createKubeadmConfig if [[ $thisIP == $master1_IP ]]; then # На первом мастер-узле устанавливаем CNI-плагин и архивируем сертификаты # для последующего использования на других мастер-узлах. initializeMasterNode installCalicoCNI archiveCertificates fi if [[ $thisIP != $master1_IP ]]; then # На не первом мастер-узле используем сертификаты, полученные с первого мастер-узла. extractCertificates initializeMasterNode fi
Этот скрипт будет использоваться также и для остальных master-узлов, поэтому копируем его также и на них.
Запускаем скрипт на первом master-узле master01:
./install-master-node.sh
После успешного запуска в папке /root появится архив с сертификатами кластера certificates.tar.gz, который необходимо скопировать в папки /root остальных master-узлов.
В результате успешного выполнения вы должны получить примерно такой вывод:
You can now join any number of control-plane nodes by copying certificate authorities and service account keys on each node and then running the following as root: kubeadm join 192.168.3.211:6443 --token 405s55.bpe3cdieqfshw2p3 \ --discovery-token-ca-cert-hash sha256:3bdea11b4cfa3e290b687599884b0bb392caea6d07839ec648cf3e29addaca08 \ --control-plane
Необходимо сохранить данный текст, так как далее нам понадобятся два параметра из него.
Обеспечение доступа kubectl к кластеру
kubectl используется в качестве основного инструмента администрирования Kubernetes-кластера. Мы его установим на всех узлах кластера, однако, если попробовать его использовать, мы получим ошибку с достаточно непонятным текстом сообщения.
The connection to the server localhost:8080 was refused - did you specify the right host or port?
Для того, чтобы kubectl работал необходимо сказать ему, где искать конфигурацию для доступа к кластеру. Проще всего это сделать с помощью переменной окружения KUBECONFIG
, указывающей на файл конфигурации. В зависимости от разных условий, файл этот может располагаться в разных местах.
- На master-узлах при работе из-под учётки root: /etc/kubernetes/admin.conf.
- На worker-узлах при работе из-под учётки root: /etc/kubernetes/kubelet.conf.
- На любых узлах при работе из-под другой учётки: $HOME/.kube/config.
В последнем случае этот файл необходимо создать или скопировать с master-узлов.
После того, как файл найден/скопирован/создан в файле .bashrc (или аналогичном, вашей командной оболочки) добавляем следующую строку (показано для случая master-узел из-под root):
export KUBECONFIG=/etc/kubernetes/admin.conf
И перезагружаем оболочку (показано для bash):
exec bash
Рекомендую установить kubectl на вашей рабочей машине.
Развёртывание остальных master-узлов Kubernetes
Для развёртывания оставшихся master-узлов используется тот же скрипт install-master-node.sh. Помимо скриптов, как было сказано ранее, необходимо скопировать в папку скриптов на целевые машины архив с сертификатами. Без этого архива скрипт не отработает. Проще всего распространить данный архив на все master-узлы можно, скопировав его вначале в рабочую папку с master01, а затем из рабочей папки на master02 и master03.
После установки посредством скрипта install-master-node.sh проверяем, что все master-узлы работают:
kubectl get nodes NAME STATUS ROLES AGE VERSION master1 Ready control-plane 25m v1.27.1 master2 Ready control-plane 11m v1.27.1 master3 Ready control-plane 7m34s v1.27.1
Развёртывание worker-узлов Kubernetes-кластера
Worker-узлы развёртываем с помощью следующего скрипта install-worker-node.sh, который необходимо создать в рабочей папке:
#!/bin/bash source variables.sh function installAndConfigurePrerequisites { apt install -y apt-transport-https curl gnupg2 apparmor apparmor-utils curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add - cat <<EOF >/etc/apt/sources.list.d/kubernetes.list deb https://apt.kubernetes.io/ kubernetes-xenial main EOF apt update apt install -y kubelet=$kubernetesVersion-00 apt install -y kubeadm=$kubernetesVersion-00 apt install -y kubectl=$kubernetesVersion-00 apt-mark hold kubelet kubeadm kubectl } function joinMasterToCluster { read -p "Enter token: " token read -p "Enter SHA256 without 'sha256:' prefix: " sha kubeadm join 192.168.3.211:6443 --token $token --discovery-token-ca-cert-hash sha256:$sha } installAndConfigurePrerequisites joinMasterToCluster
Как и в предыдущих шагах копируем все скрипты на worker-узлы:
scp *.sh root@192.168.3.214:/root
Подключаемся по SSH к узлу и запускаем скрипт:
./install-worker-node.sh
В ходе его выполнения будут заданы два вопроса про токен и SHA его сертификата. Их значения нужно взять из вывода, полученного при развёртывании первого master-узла. В моём случае это были: 405s55.bpe3cdieqfshw2p3 и 3bdea11b4cfa3e290b687599884b0bb392caea6d07839ec648cf3e29addaca08 соответственно.
Время жизни токена ограничено 24 часами. Поэтому если между развёртыванием первого master-узла и worker-узла пройдёт более 24 часов, вам необходимо повторно сгенерировать этот токен. Для этого, подключившись к кластеру, необходимо выполнить следующую команду и использовать полученный токен и его хэш-сумму для скрипта install-worker-node.sh.
kubeadm token create --print-join-command
Развёртывание узлов haproxy-кластера
Последним штрихом будет создание haproxy-кластера для доступа worker-узлов к master-узлам. Зачем это нужно? Дело в том, что в конфигурации worker-узла жёстко прописывается адрес одного из master-узлов. В этом можно убедиться, найдя в файле /etc/kubernetes/kubelet.conf на worker-узле параметр server:. Если этот master-узел «приляжет», worker-узел «отвалится» от кластера. Чтобы этого не происходило, и кластер не терял свои worker-узлы, необходимо обеспечить защиту от подобных проблем. Одно из возможных решений реализовать доступ к control-plane через HA-proxy.
Создаём в рабочей папке скрипт install-haproxy.sh со следующим содержимым:
#!/bin/bash source variables.sh function installAndConfigurePrerequisites { apt install -y apt-transport-https curl gnupg2 apparmor apparmor-utils } function downloadAndInstallHaproxy { curl https://haproxy.debian.net/bernat.debian.org.gpg \ | gpg --dearmor > /usr/share/keyrings/haproxy.debian.net.gpg echo deb "[signed-by=/usr/share/keyrings/haproxy.debian.net.gpg]" \ http://haproxy.debian.net bullseye-backports-2.5 main \ > /etc/apt/sources.list.d/haproxy.list apt update apt install -y haproxy=2.5.\* } function configureHaproxy { cat > /etc/haproxy/haproxy.cfg <<EOF global log /dev/log local0 log /dev/log local1 notice chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy daemon # Default SSL material locations ca-base /etc/ssl/certs crt-base /etc/ssl/private # Default ciphers to use on SSL-enabled listening sockets. # For more information, see ciphers(1SSL). This list is from: # https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ # An alternative list with additional directives can be obtained from # https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=haproxy ssl-default-bind-ciphers ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS ssl-default-bind-options no-sslv3 defaults log global mode http option httplog option dontlognull timeout connect 5000 timeout client 50000 timeout server 50000 errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http frontend k8s-api bind ${thisIP}:6443 bind 127.0.0.1:6443 mode tcp option tcplog default_backend k8s-api backend k8s-api mode tcp option tcplog option tcp-check balance roundrobin default-server port 6443 inter 10s downinter 5s rise 2 fall 2 slowstart 60s maxconn 250 maxqueue 256 weight 100 server apiserver1 ${master01_IP}:6443 check server apiserver2 ${master02_IP}:6443 check server apiserver3 ${master03_IP}:6443 check EOF systemctl restart haproxy } function connectNodeToLocalHaproxy { # Заменить адрес мастер узла на локальный адрес узла Haproxy. sed -i --regexp-extended "s/(server: https:\/\/)[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}\.[[:digit:]]{1,3}/\1127.0.0.1/g" /etc/kubernetes/kubelet.conf systemctl restart kubelet } installAndConfigurePrerequisites downloadAndInstallHaproxy configureHaproxy connectNodeToLocalHaproxy
И, как обычно, копируем все скрипты из рабочей папки на worker-узлы:
scp *.sh root@192.168.3.214:/root
Запускаем скрипт на worker-узлах:
./install-haproxy.sh
После этого проверяем, что кластер работает и доступен:
kubectl get nodes NAME STATUS ROLES AGE VERSION master1 Ready control-plane 59m v1.27.1 master2 Ready control-plane 45m v1.27.1 master3 Ready control-plane 41m v1.27.1 worker1 Ready <none> 9m13s v1.27.1 worker2 Ready <none> 5m36s v1.27.1