В этой статье блога мы будем реализовывать кластеры Kubernetes с высокой доступностью (HA) с помощью kubeadm! В этом руководстве мы рассмотрим, как использовать kubeadm в Rocky Linux 9.4 и 9.5 (проверено на обоих дистрибутивах) для настройки устойчивых и отказоустойчивых сред Kubernetes. Независимо от того, являетесь ли вы новичком в системах высокой доступности или хотите повысить надежность существующего кластера, в этой статье вы найдете практические идеи и пошаговые инструкции, которые помогут вам обеспечить бесперебойную работу и масштабируемость.
Мы будем использовать последнюю версию Kubernetes v1.31.5
При использовании многоуровневых узлов плоскости управления этот подход сводит к минимуму требования к инфраструктуре за счет совместного размещения членов etcd и узлов плоскости управления.
Требования к системе
3 узла, требования к плоскости управления — 4 ГБ, 4 ЦП, 50 ГБ
3 узла, требования к рабочему узлу — 16 ГБ, 8 ЦП, 100 ГБ
1 узел, требования к спецификации узла HAProxy — 2 ГБ, 2 ЦП, 50 ГБ
DNS-записи для всех узлов кластера k8s и HAProxy создаются в IDM.
Полное доменное имяIP-адресkube-apiserver.kalyuzhnyy.ru192.168.0.50k8smas1.kalyuzhnyy.ru192.168.0.51k8smas2.kalyuzhnyy.ru192.168.0.52k8smas3.kalyuzhnyy.ru192.168.0.53k8swor1.kalyuzhnyy.ru192.168.0.54k8swor2.kalyuzhnyy.ru192.168.0.55k8swor3.kalyuzhnyy.ru192.168.0.56Полное доменное имя и IP-адрес для кластера Kubernetes HA
Настройка HAProxy
Если вы хотите настроить HAProxy для Kubernetes, обратитесь к
Инструменты системного администратора
Установите следующие предварительные требования на всех узлах
dnf install nano mc iputils wget curl vim bash-completion nc tcpdump telnet bind-utils -y
Шаг 1: Установите имя хоста и обновите файл хостов
Войдите в систему или ssh на каждой машине и выполните команды hostnamectl, чтобы задать соответствующее имя хоста.
sudo hostnamectl set-hostname “kube-apiserver.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8smas1.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8smas2.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8smas3.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8swor1.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8swor2.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8swor3.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8swor4.kalyuzhnyy.ru” && exec bash
sudo hostnamectl set-hostname “k8swor5.kalyuzhnyy.ru” && exec bash
и т.д. для соответствующего сервера своя запись sudo hostnamectl set-hostname...
Добавьте следующие записи в файл
nano /etc/hosts на каждом узле.
192.168.0.50 kube-apiserver.kalyuzhnyy.ru
192.168.0.51 k8smas1.kalyuzhnyy.ru
192.168.0.52 k8smas2.kalyuzhnyy.ru
192.168.0.53 k8smas3.kalyuzhnyy.ru
192.168.0.54 k8swor1.kalyuzhnyy.ru
192.168.0.55 k8swor2.kalyuzhnyy.ru
192.168.0.56 k8swor3.kalyuzhnyy.ru
Шаг 2: Отключите пространство подкачки на каждом узле
Удалите записи подкачки Swap из /etc/default/grub
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
Сохраните и выйдите, а затем введите команду
grub2-mkconfig -o /boot/grub2/grub.cfg
Шаг 3: Настройте правила SELinux и Firewall для Kubernetes
Установите режим SELinux как разрешающий на всех узлах с помощью следующих команд:
sudo setenforce 0
sudo sed -i --follow-symlinks 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/sysconfig/selinux
Требования к межсетевому экрану
Нам нужно количество портов как в плоскости управления, так и в рабочих узлах, убедитесь, что разрешены порты ниже
На главном узле разрешите следующие порты в брандмауэре.
На плоскости управления или главных узлах
firewall-cmd --permanent --add-service={kube-apiserver,kube-control-plane,kube-control-plane-secure,kube-api,kube-worker}
firewall-cmd --permanent --zone=trusted --add-interface=lo
firewall-cmd --permanent --zone=trusted --add-service={kube-api,kube-scheduler,kube-scheduler-secure,kube-controller-manager}
firewall-cmd --reload
firewall-cmd --list-all-zones
или
sudo firewall-cmd --zone=public --permanent --add-port=6443/tcp
sudo firewall-cmd --zone=public --permanent --add-port=2379-2380/tcp
sudo firewall-cmd --zone=public --permanent --add-port=10250/tcp
sudo firewall-cmd --zone=public --permanent --add-port=10251/tcp
sudo firewall-cmd --zone=public --permanent --add-port=10252/tcp
sudo firewall-cmd --zone=public --permanent --add-port=10255/tcp
sudo firewall-cmd --zone=public --permanent --add-port=5473/tcp
sudo firewall-cmd --zone=public --permanent --add-port=8080/tcp
или
sudo firewall-cmd --permanent --add-port={6443,2379,2380,10250,10251,10252,10257,10259,179}/tcp
sudo firewall-cmd --permanent --add-port=4789/udp
sudo firewall-cmd --reload
Или выключить фаервол
systemctl stop firewalld
systemctl disable firewalld
На рабочих узлах
firewall-cmd --permanent --add-service=kube-worker
firewall-cmd --permanent --zone=trusted --add-interface=lo
firewall-cmd --permanent --zone=trusted --add-service=kube-api
firewall-cmd --reload
firewall-cmd --list-all-zones
Шаг 4: Добавьте модули и параметры ядра
Переадресация IPv4 и предоставление iptables возможности видеть трафик по мостам
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
Параметры sysctl, необходимые во время настройки.
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
Включение модулей и проверка.
modprobe overlay
modprobe br_netfilter
lsmod | grep br_netfilter
lsmod | grep overlay
Применяйте параметры без перезагрузки серверов
sysctl --system
Убедитесь, что установлено значение 1.
sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward
Установка контейнерных сред выполнения CRI-O
В этой конфигурации мы предпочитаем использовать CRI-O в качестве среды выполнения контейнера, хотя доступны и другие варианты, такие как containerd, Docker и Mirantis.
Установите переменную для версии платформы Kubernetes.
Для установки версии 1.29 введите
KUBERNETES_VERSION=v1.29
Для установки версии 1.31 введите
KUBERNETES_VERSION=v1.31
PROJECT_PATH=prerelease:/main
Далее взависимости от той версии что вы указали, дальнейший скпирт установит необходимые компоненты
Создание необходимых репозиториев Kubernetes и CRI-O
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/core:/stable:/$KUBERNETES_VERSION/rpm/repodata/repomd.xml.key
exclude=kubelet kubeadm kubectl cri-tools kubernetes-cni
EOF
cat <<EOF | tee /etc/yum.repos.d/cri-o.repo
[cri-o]
name=CRI-O
baseurl=https://pkgs.k8s.io/addons:/cri-o:/$PROJECT_PATH/rpm/
enabled=1
gpgcheck=1
gpgkey=https://pkgs.k8s.io/addons:/cri-o:/$PROJECT_PATH/rpm/repodata/repomd.xml.key
EOF
Установите, запустите и включите службу.
dnf install -y container-selinux
dnf install -y cri-o
systemctl start crio.service
systemctl enable crio.service
Установка пакетов Kubernetes
И финальные пакеты, необходимые для настройки кластера kubeadm HA
dnf install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet
Инициализация кластера
Для начала нам нужно инициализировать на любой из плоскостей управления
kubeadm init --control-plane-endpoint "kube-apiserver.kalyuzhnyy.ru:6443" --upload-certs
[root@kube-apiserver nkalyuzhnyy]# kubeadm init --control-plane-endpoint "kube-apiserver.kalyuzhnyy.ru:6443" --upload-certs
[addons] Applied essential addon: kube-proxy
Your Kubernetes control-plane has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
Alternatively, if you are the root user, you can run:
export KUBECONFIG=/etc/kubernetes/admin.conf
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of the control-plane node running the following command on each as root:
kubeadm join kube-apiserver.kalyuzhnyy.ru:6443 --token eifbd3.2wkmh307w5pmkmmo \
--discovery-token-ca-cert-hash sha256:ffebcd332141b6b91b4e81b6a2a0c71a6bf17fc3cc5d16a4e3280534121f4cf0 \
--control-plane --certificate-key cb6598d98bfcc1139ff7f006e0c16ac716bc9855366610d1abe661d4fc220dff
Please note that the certificate-key gives access to cluster sensitive data, keep it secret!
As a safeguard, uploaded-certs will be deleted in two hours; If necessary, you can use
"kubeadm init phase upload-certs --upload-certs" to reload certs afterward.
Then you can join any number of worker nodes by running the following on each as root:
kubeadm join kube-apiserver.kalyuzhnyy.ru:6443 --token eifbd3.2wkmh307w5pmkmmo \
--discovery-token-ca-cert-hash sha256:ffebcd332141b6b91b4e81b6a2a0c71a6bf17fc3cc5d16a4e3280534121f4cf0
Как только мы выполним приведенную выше команду, она успеет загрузить необходимые образы для настройки кластера kubernetes.
Для версии Kubernetes 1.29 вывод следующий
[root@kube-apiserver nkalyuzhnyy]# crictl images
IMAGE TAG IMAGE ID SIZE
registry.k8s.io/coredns/coredns v1.11.1 cbb01a7bd410d 61.2MB
registry.k8s.io/etcd 3.5.16-0 a9e7e6b294baf 151MB
registry.k8s.io/kube-apiserver v1.29.13 724efdc6b8440 129MB
registry.k8s.io/kube-controller-manager v1.29.13 04dd549807d44 124MB
registry.k8s.io/kube-proxy v1.29.13 f20cf1600da6c 84.2MB
registry.k8s.io/kube-scheduler v1.29.13 42b8a40668702 61.3MB
registry.k8s.io/pause 3.10 873ed75102791 742kB
registry.k8s.io/pause 3.9 e6f1816883972 750kB
[root@kube-apiserver nkalyuzhnyy]#
Для версии Kubernetes 1.31.5 вывод
Подготовьте обычного пользователя к доступу к API.
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
export KUBECONFIG=/etc/kubernetes/admin.conf
kubectl cluster-info dump
Присоединение к другим хостам управления (Control Planes)
Как только мы получим вышеуказанный вывод, соединим другие плоскости управления с помощью команды
kubeadm join kube-apiserver.kalyuzhnyy.ru:6443 --token eifbd3.2wkmh307w5pmkmmo \
--discovery-token-ca-cert-hash sha256:ffebcd332141b6b91b4e81b6a2a0c71a6bf17fc3cc5d16a4e3280534121f4cf0 \
--control-plane --certificate-key cb6598d98bfcc1139ff7f006e0c16ac716bc9855366610d1abe661d4fc220dff
В случае возникновения проблем с подключением из-за сертификата, перегенируйте его
Обновление сертификата на api-kube.kalyuzhnyy.ru
kubeadm init phase upload-certs --upload-certs
Присоединение рабочих узлов
Сразу после плоскости управления начните присоединяться к рабочим узлам, выполнив команду
kubeadm join kube-apiserver.kalyuzhnyy.ru:6443 --token eifbd3.2wkmh307w5pmkmmo \
--discovery-token-ca-cert-hash sha256:ffebcd332141b6b91b4e81b6a2a0c71a6bf17fc3cc5d16a4e3280534121f4cf0
Проверка установленной версии кластера kubectl version для Kubernetes 1.29.13
Создание сети подов
Теперь мы должны развернуть сеть pod для кластера, я собираюсь использовать Calico.
Скачайте последний файл YAML с официального сайта calico и создайте сеть подов.
# wget https://docs.projectcalico.org/manifests/calico.yaml
# kubectl apply -f calico.yaml
Мы должны увидеть, как calico работает на каждом узле
kubectl get pods -n kube-system
[root@kube-apiserver ~]# kubectl get pods -n kube-system
NAME READY STATUS RESTARTS AGE
calico-kube-controllers-6879d4fcdc-82jj8 1/1 Running 0 103m
calico-node-7hrph 1/1 Running 0 103m
calico-node-lw888 1/1 Running 0 48m
calico-node-mq4zd 1/1 Running 0 103m
calico-node-mqsn7 1/1 Running 0 66m
coredns-7c65d6cfc9-lxmgc 1/1 Running 0 132m
coredns-7c65d6cfc9-v76c2 1/1 Running 0 132m
etcd-k8smas1.kalyuzhnyy.ru 1/1 Running 0 66m
etcd-kube-apiserver.kalyuzhnyy.ru 1/1 Running 2 133m
kube-apiserver-k8smas1.kalyuzhnyy.ru 1/1 Running 0 66m
kube-apiserver-kube-apiserver.kalyuzhnyy.ru 1/1 Running 44 133m
kube-controller-manager-k8smas1.kalyuzhnyy.ru 1/1 Running 0 66m
kube-controller-manager-kube-apiserver.kalyuzhnyy.ru 1/1 Running 2 133m
kube-proxy-6m782 1/1 Running 0 48m
kube-proxy-85x7n 1/1 Running 0 132m
kube-proxy-s568v 1/1 Running 0 110m
kube-proxy-vhngp 1/1 Running 0 66m
kube-scheduler-k8smas1.kalyuzhnyy.ru 1/1 Running 0 66m
kube-scheduler-kube-apiserver.kalyuzhnyy.ru 1/1 Running 2 133m
[root@kube-apiserver ~]#
Тестирование развертывания приложения
В заключение, разверните веб-сервер с помощью императивной команды с опциями.
[root@kube-apiserver ~]$ kubectl create namespace webserver
namespace/webserver created
[root@kube-apiserver ~]
[root@kube-apiserver ~]$ kubectl get namespaces
NAME STATUS AGE
default Active 8h
kube-node-lease Active 8h
kube-public Active 8h
kube-system Active 8h
webserver Active 6s
[root@kube-apiserver ~]
[root@kube-apiserver ~]$ kubectl create deployment webserver --image nginx --replicas 3 --namespace webserver
deployment.apps/webserver created
[root@kube-apiserver ~]
[root@kube-apiserver ~]$ kubectl get deployments.apps -n webserver
NAME READY UP-TO-DATE AVAILABLE AGE
webserver 3/3 3 3 18s
[root@kube-apiserver ~]$
kubectl logs -n webserver deployments/webserver
[root@kube-apiserver ~]# kubectl logs -n webserver deployments/webserver
Found 3 pods, using pod/webserver-659c684488-25q6z
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2025/02/07 12:27:07 [notice] 1#1: using the "epoll" event method
2025/02/07 12:27:07 [notice] 1#1: nginx/1.27.4
2025/02/07 12:27:07 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14)
2025/02/07 12:27:07 [notice] 1#1: OS: Linux 5.14.0-427.13.1.el9_4.x86_64
2025/02/07 12:27:07 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2025/02/07 12:27:07 [notice] 1#1: start worker processes
2025/02/07 12:27:07 [notice] 1#1: start worker process 24
2025/02/07 12:27:07 [notice] 1#1: start worker process 25
2025/02/07 12:27:07 [notice] 1#1: start worker process 26
2025/02/07 12:27:07 [notice] 1#1: start worker process 27
[root@kube-apiserver ~]#
Вот и все, мы закончили с настройкой высокодоступного кластера Kubernetes на Rocky Linux 9.4 и 9.5 с CRI-O в качестве среды выполнения контейнера.
В будущем я планирую доразвернуть остальные узлы согласно схемы и после ввода в пром эксплуатацию нового кластера Kubernetes 1.31
развернуть на нем различные сервисы,и перенести поды с версии 1.28, а значит продолжение следует.
Если у вас есть какие-либо мысли или вопросы по этой теме, пожалуйста, не стесняйтесь оставить комментарий или отправить мне сообщение. Я хотел бы продолжить дискуссию и услышать вашу точку зрения.
А также вы всегда можете поддержать меня зайдя на сайт и подписаться https://dzen.ru/kalyuzhnyy.ru и найти больше статей на моих ресурсах https://kalyuzhnyy.ru и https://dev.kalyuzhnyy.ru