Введение
Привет! В своей работе я регулярно внедряю различные решения на кластере Kubernetes. Для тестирования проектов очень важно иметь тестовую среду, которая была бы недорогой, проста в обслуживании и, при необходимости, могла поддерживать не слишком нагруженные приложения в продакшене.
Самый простой способ — это использовать виртуальные машины или различные контейнерные решения (как, например, kind (Kubernetes in Docker) ), однако мне не нравится такой подход из-за ограничений виртуализации и ресурсов. Я стремлюсь создать кластер, который можно использовать в реальном бизнесе и который обеспечит надежность в случае сбоев. Готовить кластер будем с помощью утилиты kubeadm.
Идеальным и бюджетным решением являются микрокомпьютеры на базе архитектуры ARM, например Orange Pi 3 LTS.
Я слышал о российских аналогах, таких как Repka Pi, но пока не имел опыта работы с ними, а Raspberry Pi, хоть и обладает множеством модулей, но стоит дороже. Orange Pi 3 LTS компактный, достаточно мощный и поставляется с образом OC Debian 11. Это устройство оснащено 4 ядрами, 2 ГБ оперативной памяти и процессором с тактовой частотой 1,8 ГГц. Стоимость этого устройства, на момент написания статьи, весьма демократичная — около 4000 ₽.
Стенд
Чтобы наш кластер не создавал беспорядка мной в 3д редакторе был смоделирован и распечатан макет для элементов. Так как я активно пользуюсь этими машинками в своих задачах, макет я сделал разборным, чтобы без труда вынуть нужный микрокомпьютер, сменить в нем microSD и запустить для других задач. Чистая функциональность.
Наш план
Поскольку это кластер, как минимум, мы должны подготовить 2 узла (рабочую и управляющую). Что необходимо сделать:
-
Подготовить машины, настроить сеть и аутентификацию
-
Настроить Docker и CRI-Dockerd на машинах
-
Настроим балансировщик нагрузки
-
Добавим узлы в кластер
-
Установим дашборд кластера
Наша кластер будет выглядеть следующим образом:
-
opi-node1.internal 192.168.0.90 Управляющий узел
-
opi-node2.internal 192.168.0.91 Рабочий узел
-
opi-node3.internal 192.168.0.92 Рабочий узел (оставим в настройках для будущего расширения)
-
192.168.0.95 — виртуальный ip адрес (необходим для работы балансировщика нагрузки)
1. Подготовка узлов
Для начала загрузим последний образ Debian с официального сайта производителя Orange Pi 3 LTS по ссылке:
Затем запишем образ на SD-карту устройства с помощью выбранного вами редактора образов, например, Rufus.
После загрузки входим в систему используя дефолтный логин и пароль (логин: orangepi, пароль: orangepi).
Займемся сетью, отключим NetworkManager и настроим статику, в моем случаем:
для node1
sudo systemctl stop NetworkManager sudo systemctl disable NetworkManager sudo tee /etc/network/interfaces <<EOF source /etc/network/interfaces.d/* # Network is managed by Network manager auto lo iface lo inet loopback EOF sudo tee /etc/network/interfaces.d/lan <<EOF auto eth0 iface eth0 inet static address 192.168.0.90 netmask 255.255.255.0 gateway 192.168.0.1 dns-nameservers 192.168.0.1 EOF sudo tee nano /etc/resolv.conf <<EOF # Generated by NetworkManager search opi-node1.internal nameserver 192.168.0.1 EOF sudo systemctl restart networking
для node2
sudo systemctl stop NetworkManager sudo systemctl disable NetworkManager sudo tee /etc/network/interfaces <<EOF source /etc/network/interfaces.d/* # Network is managed by Network manager auto lo iface lo inet loopback EOF sudo tee /etc/network/interfaces.d/lan <<EOF auto eth0 iface eth0 inet static address 192.168.0.91 netmask 255.255.255.0 gateway 192.168.0.1 dns-nameservers 192.168.0.1 EOF sudo tee nano /etc/resolv.conf <<EOF # Generated by NetworkManager search opi-node2.internal nameserver 192.168.0.1 EOF sudo systemctl restart networking
Пропишем репозитории на всех узлах
sudo nano /etc/apt/sources.list
deb http://deb.debian.org/debian bullseye main contrib non-free deb http://deb.debian.org/debian bullseye-updates main contrib non-free deb http://deb.debian.org/debian bullseye-backports main contrib non-free deb http://security.debian.org/ bullseye-security main contrib non-free
Обновим кеш и систему
sudo apt update sudo apt upgrade
Сменим пользователя в целях безопасности
sudo useradd -s /bin/bash ch groups sudo usermod -aG tty,disk,dialout,sudo,audio,video,plugdev,games,users,systemd-journal,input,netdev,ssh ch sudo passwd ch sudo passwd orangepi sudo mkhomedir_helper ch su ch # Удаляем пользователя orangepi sudo deluser --remove-all-files orangepi
Настроим время
sudo timedatectl set-timezone Europe/Moscow timedatectl
Настроим rsa ключи для беспарольной аутентификации и запишем открытый ключ на машинах
ssh-keygen -t rsa sudo mkdir ~/.ssh/ ; \ sudo touch ~/.ssh/authorized_keys ; \ sudo nano ~/.ssh/authorized_keys
Настроим имена узлов
для opi-node1.internal
sudo apt install dnsutils -y sudo hostnamectl set-hostname opi-node1.internal sudo tee /etc/hosts <<EOF 127.0.0.1 localhost 127.0.1.1 opi-node1.internal opi-node1 # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters # Cluster nodes 192.168.0.90 opi-node1.internal 192.168.0.91 opi-node2.internal 192.168.0.92 opi-node3.internal EOF sudo systemctl restart systemd-hostnamed sudo hostname opi-node1.internal
для opi-node2.internal
Ставим необходимые утилиты
sudo apt install -y curl wget gnupg sudo iptables tmux keepalived haproxy
Настроим автозагрузку и запуск модуля ядра br_netfilter и overlay, необходимые для работы сети и хранилища на кластере и разрешим маршрутизацию ip трафика между интерфейсами. Также для корректной работы узлов кластера нужно отключить файл подкачки
sudo tee /etc/modules-load.d/k8s.conf <<EOF overlay br_netfilter EOF sudo modprobe overlay sudo modprobe br_netfilter #<------- Разрешение маршрутизации IP-трафика sudo echo -e "net.bridge.bridge-nf-call-ip6tables = 1\nnet.bridge.bridge-nf-call-iptables = 1\nnet.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/10-k8s.conf sudo sysctl -f /etc/sysctl.d/10-k8s.conf #<------- Отключение файла подкачки sudo swapoff -a sudo sed -i '/ swap / s/^/#/' /etc/fstab
Для нашего устройства файл подкачки через /etc/fstab отключить не выйдет, тогда действуем обходными путями. Для этого сделаем запись swapoff -a в файле /etc/rc.local перед строкой exit 0. В этом случаем файл подкачки будет отключаться при загрузке системы.
sudo nano /etc/rc.local
.... swapoff -a exit 0
Делаем проверки:
#<------- Для проверки автоматической загрузки модулей br_netfilter и overlay sudo lsmod | grep br_netfilter sudo lsmod | grep overlay ## Ожидаемый примерный результат: # br_netfilter 32768 0 # bridge 258048 1 br_netfilter # overlay 147456 0 #<------- Для проверки успешности изменения настроек в параметрах сетевого стека sudo sysctl net.bridge.bridge-nf-call-iptables net.bridge.bridge-nf-call-ip6tables net.ipv4.ip_forward # Ожидаемый примерный результат: # net.bridge.bridge-nf-call-iptables = 1 # net.bridge.bridge-nf-call-ip6tables = 1 # net.ipv4.ip_forward = 1 #<------- Для проверки отключения файла подкачки выполним команду: sudo swapon -s ## Ожидаемый вывод команды – пустой. Она ничего не должна отобразить
2. Настройка Docker и CRI-Dockerd
Настройка deb-репозитория Kubernetes
#<------- загрузка ключа репозитория sudo apt-get install -y apt-transport-https ca-certificates curl gpg curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/kubernetes-apt-keyring.gpg echo 'deb [signed-by=/etc/apt/trusted.gpg.d/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list sudo apt-get update #<------- Установка пакетов kubeadm и kubectl sudo apt-get install -y kubelet kubeadm kubectl #<------- Установка Docker sudo curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/docker.gpg sudo echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/trusted.gpg.d/docker.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin
Установка Docker cri-dockerd, необходима для работы с контейнерами в среде Kubernetes.
uname -m #<------- видим что архитектура нашего устройства ARM64 sudo wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.14/cri-dockerd-0.3.14.arm64.tgz sudo tar xvf cri-dockerd-*.tgz sudo mv cri-dockerd/cri-dockerd /usr/local/bin/ sudo wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.service sudo wget https://raw.githubusercontent.com/Mirantis/cri-dockerd/master/packaging/systemd/cri-docker.socket sudo mv cri-docker.socket cri-docker.service /etc/systemd/system/ sudo sed -i -e 's,/usr/bin/cri-dockerd,/usr/local/bin/cri-dockerd,' /etc/systemd/system/cri-docker.service sudo systemctl daemon-reload sudo systemctl enable cri-docker.service sudo systemctl enable --now cri-docker.socket #<------- Проверка доступности сокета cri-dockerd sudo usermod -aG docker ch sudo crictl --runtime-endpoint unix:///var/run/cri-dockerd.sock version ## Ожидаемый примерный результат: # Version: 0.1.0 # RuntimeName: docker # RuntimeVersion: 23.0.1 # RuntimeApiVersion: v1
3. Настройка балансировщика нагрузки
Демон keepalived нужен работы виртуального ip адреса и будет вторым адресом на сетевом интерфейсе узла. При отказе узла keepalived переключит виртуальный адрес на другой доступный узел. Демон haproxy обрабатывает поочередно запросы на API сервера управляющих узлов кластера. Не забываем указывать корректные имена сетевых интерфейсов!
sudo nano etc/keepalived/keepalived.conf
global_defs { enable_script_security script_user nobody } vrrp_script check_apiserver { script "/etc/keepalived/check_apiserver.sh" interval 3 } vrrp_instance VI_1 { state BACKUP interface eth0 virtual_router_id 5 priority 100 advert_int 1 nopreempt authentication { auth_type PASS auth_pass ZqSj#f1G } virtual_ipaddress { 192.168.0.95 } track_script { check_apiserver } }
sudo nano /etc/keepalived/check_apiserver.sh
#!/bin/sh #-ch- from ch-script # File: /etc/keepalived/check_apiserver.sh #- APISERVER_VIP=192.168.0.90 APISERVER_DEST_PORT=8888 PROTO=http #- errorExit() { echo "*** $*" 1>&2 exit 1 } #- curl --silent --max-time 2 --insecure ${PROTO}://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET ${PROTO}://localhost:${APISERVER_DEST_PORT}/" if ip addr | grep -q ${APISERVER_VIP}; then curl --silent --max-time 2 --insecure ${PROTO}://${APISERVER_VIP}:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET ${PROTO}://${APISERVER_VIP}:${APISERVER_DEST_PORT}/" fi
Установим атрибут, разрешающий исполнение скрипта, и запустим демона keepalived
sudo chmod +x /etc/keepalived/check_apiserver.sh sudo systemctl enable keepalived sudo systemctl start keepalived
Настроим демона haproxy
sudo nano /etc/haproxy/haproxy.cfg
# File: /etc/haproxy/haproxy.cfg #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global log /dev/log local0 log /dev/log local1 notice daemon #--------------------------------------------------------------------- # common defaults that all the 'listen' and 'backend' sections will # use if not designated in their block #--------------------------------------------------------------------- defaults mode http log global option httplog option dontlognull option http-server-close option forwardfor except 127.0.0.0/8 option redispatch retries 1 timeout http-request 10s timeout queue 20s timeout connect 5s timeout client 20s timeout server 20s timeout http-keep-alive 10s timeout check 10s #--------------------------------------------------------------------- # apiserver frontend which proxys to the control plane nodes #--------------------------------------------------------------------- frontend apiserver bind *:8888 mode tcp option tcplog default_backend apiserver #--------------------------------------------------------------------- # round robin balancing for apiserver #--------------------------------------------------------------------- backend apiserver option httpchk GET /healthz http-check expect status 200 mode tcp option ssl-hello-chk balance roundrobin server opi-node1 192.168.0.90:6443 check server opi-node2 192.168.0.91:6443 check server opi-node3 192.168.0.92:6443 check
Запустим демона и добавим в автозагрузку
sudo systemctl enable haproxy sudo systemctl restart haproxy
Проверим доступность сокета cri-dockerd
sudo crictl --runtime-endpoint unix:///var/run/cri-dockerd.sock version ## Ожидаемый примерный результат: # Version: 0.1.0 # RuntimeName: docker # RuntimeVersion: 23.0.1 # RuntimeApiVersion: v1
Перезагрузим все узлы
sudo reboot
4. Добавление узлов в кластер
Запускаем на управляющем узле
sudo kubeadm init \ --cri-socket unix:///var/run/cri-dockerd.sock \ --pod-network-cidr=10.244.0.0/16 \ --control-plane-endpoint "192.168.0.95:8888" \ --upload-certs
Ждем настройки и при успеха получаем токены и необходимые сертрификаты. Выглядеть они будут примерно так:
для подключения управляющих узлов
sudo kubeadm join 192.168.0.95:8888 --token zj3j9x.p63c8r2a7vb57cr3 \ --discovery-token-ca-cert-hash sha256:25fc69ce47192e5zcp93746ca20f67ec86dafb39f6161a0e221f53ddebbf8c2 \ --control-plane --certificate-key d30c1cad2fv765zx36d599d198172a11270550e0bc0e6d1e81792ab81b310ec0 \ --cri-socket unix:///var/run/cri-dockerd.sock
для подключения рабочих узлов
sudo kubeadm join 192.168.0.95:8888 --token h04o9e.qnon45rtyy9qhgyo \ --discovery-token-ca-cert-hash sha256:25fc69ce47192e5zcp93746ca20f67ec86dafb39f6161a0e221f53ddebbf8c2 \ --cri-socket unix:///var/run/cri-dockerd.sock
не забываем добавлять —cri-socket unix:///var/run/cri-dockerd.sock для работы с применением cri-dokerd
если потеряли токен, узнать его можно с помощью команды:
kubeadm token create --print-join-command
также при ошибка можно разрешить на чтение конфигурационный файл для всех пользователей (снижает безопасность, но если на сервере работаете только вы, то это может быть оправданной мерой при ошибках запуска)
sudo chmod +r /etc/kubernetes/admin.conf
Устанавливаем переменные окружения kubeсtl для управляющей ноды
sudo sh -c 'echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> /etc/environment' export KUBECONFIG=/etc/kubernetes/admin.conf echo "export KUBECONFIG=/etc/kubernetes/admin.conf" >> ~/.bashrc source ~/.bashrc mkdir -p $HOME/.kube sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(id -u):$(id -g) $HOME/.kube/config
Установим сетевой плагин на управляющем узле, который нужен для обеспечения связанности и изолированности сети в кластере
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
Протестируем работу кластера на управляющем узле
kubectl get nodes kubectl get pods -A kubectl describe node opi-node1.internal kubectl describe node opi-node2.internal
5. Установим дашборд кластера
Установим Helm на сервере. Вам нужно загрузить и установить Helm с помощью следующих команд:
curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
добавим репозиторий Kubernetes Dashboard
helm repo add kubernetes-dashboard https://kubernetes.github.io/dashboard/
Создадим пространство имён kubernetes-dashboard, в котором будет установлен Kubernetes Dashboard
kubectl create namespace kubernetes-dashboard
Установим Kubernetes Dashboard из Helm-чарта с помощью следующей команды
helm install kubernetes-dashboard kubernetes-dashboard/kubernetes-dashboard --namespace kubernetes-dashboard
сделаем форвадинг
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-proxy 8443:443
Проверим успешность установки Kubernetes Dashboard, выполните команды:
kubectl get pods -n kubernetes-dashboard
нужно подождать несколько минут для запуска дашборда
узнаем имя сервисного аккаунта
kubectl get sa -n kubernetes-dashboard
получим токен
kubectl -n kubernetes-dashboard create token default
дадим необходимые роли системному пользователю для работы с дашбордом
sudo tee dashboard-adminuser.yaml <<EOF #-ch- from ch-script apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: default roleRef: apiGroup: rbac.authorization.k8s.io kind: ClusterRole name: cluster-admin subjects: - kind: ServiceAccount name: default namespace: kubernetes-dashboard
и применим правила, увидев полнофункциональный дашборд!
kubectl apply -f dashboard-adminuser.yaml
Поздравляю, теперь с настроенным кластером вы можете продолжать изучение этого полезного и функционального инструмента у себя дома!
Спасибо за внимание!
ссылка на оригинал статьи https://habr.com/ru/articles/828556/
Добавить комментарий