Развёртывание 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

Похожие записи