From a86d2d5ed78dec5558c0e8cd1bf1f771b279c040 Mon Sep 17 00:00:00 2001 From: erjemin Date: Sun, 2 Mar 2025 20:00:06 +0300 Subject: [PATCH] =?UTF-8?q?add:=20k3s=20(=D0=BF=D0=BE=D0=B4=D0=BA=D0=BB?= =?UTF-8?q?=D1=8E=D1=87=D0=B5=D0=BD=D0=B8=D0=B5=20=D0=B2=D0=BD=D0=B5=D1=88?= =?UTF-8?q?=D0=BD=D0=B5=D0=B3=D0=BE=20=D1=83=D0=B7=D0=BB=D0=B0,=20part-1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- raspberry-and-orange-pi/k3s.md | 164 +++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/raspberry-and-orange-pi/k3s.md b/raspberry-and-orange-pi/k3s.md index 0729178..3a06484 100644 --- a/raspberry-and-orange-pi/k3s.md +++ b/raspberry-and-orange-pi/k3s.md @@ -461,3 +461,167 @@ kube-dns 10.42.1.8:53,10.42.2.6:53,10.42.1.8:53 + 3 more... 5d23h ### Разные архитектуры на узлах кластера (гетерогенность) +Когда мы подключили узлы (мастеры и воркеры) к кластеру, мы использовали одинаковые Orange Pi 5 Plus. Но, в реальности, +кластеры Kubernetes часто состоят из узлов с разными архитектурами и характеристиками. Например, если подключить к +к кластеру Raspberry Pi 3B увидим примерно такую картину: +```text +NAME STATUS ROLES AGE VERSION +opi5plus-1 Ready control-plane,etcd,master 3d3h v1.31.5+k3s1 +opi5plus-2 Ready control-plane,etcd,master 6d3h v1.31.5+k3s1 +opi5plus-3 Ready control-plane,etcd,master 5d1h v1.31.5+k3s1 +rpi3b Ready 27s v1.31.6+k3s1 +``` + +Но надо помнить, что разные архитектуры могут быть оказаться несовместимы с некоторыми приложениями и образами. +Например, Raspberry Pi 3B — это 32-битный ARMv7 (armv7l), а Orange Pi 5 Plus — 64-битный ARMv8 (aarch64). Если в +подах используются бинарные файлы, скомпилированные под определённую архитектуру, то они могут не работать на узлах +с другой архитектурой. Также, некоторые образы Docker могут быть доступны только для определённых архитектур. + +В ограниченном объеме можно подключать узлы на других платформах. Например, Windows, может иметь только воркер-узлы на k8s +(начиная с версии 1.14), а в k3s экспериментальная поддержка Windows-воркеров (начиная с с версии 1.24). На macOS нет +официальной поддержки Kubernetes/k3s для узлов на macOS (можно использовать обходные пути с использованием виртуальныех +машин). + +### Добавление узлов во "внешнем" интернете + +В моем проекте (специализированном поисковике) будет нужно парсить и интернет сайты, включая заблокированные сайты. +К сожалению современный интернет имеет взаимные региональные блокировки и просто использовать VPN интернет-соединения +не сработает. Выходом может стать использование воркер-узлов во внешнем интернете. Идея в том, что если какой-нибудь +URL не получится обработать на поде одного узла, то можно попробовать обработать его на другом узле, в другой локации. + +Так как узлы k3s взаимодействуют через API на 6443-порте, то для доступа к кластеру из внешнего интернета нужно будет +обеспечить проброс трафика через роутер сети на один из мастер-узлов. НО у нас три мастер-узла, а значит если упадет +узел на который происходит проброс, то удаленный воркер-узел "отвелится" и потеряет доступ к кластеру. Объединить +IP всеx мастер-узлов в один можно с помощью балансировщика нагрузки **Keepalived**. Он создает виртуальный IP-адрес +(VIP), c которого перенапрвляет трафик на один из мастер-узлов, и если этот узел упадет, то трафик перенаправится +на другой и так далее. + +Установи `Keepalived` на все мастер-ноды: +```bash +sudo apt update +sudo apt install keepalived +``` + +Настроим `Keepalived` последовательно на каждом мастере. Для этого отредактируем (создадим) файл конфигурации +`/etc/keepalived/keepalived.conf`: +```bash +sudo nano /etc/keepalived/keepalived.conf +``` + +На первом мастер-узле (хост -- `opi5plus-1`, IP -- `192.168.1.26`): +```text +vrrp_instance VI_1 { + state MASTER # ЭТО ГЛАВНЫЙ ХОСТ. ПО УМОЛЧАНИЮ ТРАФИК С VIP БУДЕТ ПЕРЕНАПРАВЛЯТЬСЯ НА ЭТОТ ХОСТ + interface enP4p65s0 # У Orange Pi 5 plus два интерфейса, и хост подключен по интерфейсу enP4p65s0 + virtual_router_id 51 + priority 100 # Самый высокий приоритет + advert_int 1 + unicast_src_ip 192.168.1.26 # IP текущего хоста (opi5plus-1) + unicast_peer { + 192.168.1.27 # IP второго хоста (opi5plus-2) + 192.168.1.28 # IP третьего хоста (opi5plus-3) + } + virtual_ipaddress { + 192.168.1.200 # Виртуальный IP (VIP), он должен быть исключен из диапазона DHCP + } +} +``` + +На втором мастер-узле (хост -- `opi5plus-2`, IP -- `192.168.1.27`): +```text +vrrp_instance VI_1 { + state BACKUP # ЭТО ВТОРОЙ ХОСТ. ОН БУДЕТ ПОЛУЧАТЬ ТРАФИК С VIP, ЕСЛИ ГЛАВНЫЙ ХОСТ УПАДЕТ + interface enP4p65s0 # У Orange Pi 5 plus два интерфейса, и хост подключен по интерфейсу enP4p65s0 + virtual_router_id 51 + priority 90 # Меньший приоритет + advert_int 1 + unicast_src_ip 192.168.1.27 # IP текущего хоста (opi5plus-2) + unicast_peer { + 192.168.1.26 # IP первого хоста (opi5plus-1) + 192.168.1.28 # IP третьего хоста (opi5plus-3) + } + virtual_ipaddress { + 192.168.1.200 # Виртуальный IP + } +} +``` + +И, наконец, на третьем мастер-узле (хост -- `opi5plus-3`, IP -- `192.168.1.28`): +```text +vrrp_instance VI_1 { + state BACKUP # ЭТО ТРЕТИЙ ХОСТ. ОН БУДЕТ ПОЛУЧАТЬ ТРАФИК С VIP, ЕСЛИ ГЛАВНЫЙ- И БЭКАП-ХОСТ УПАДЕТ + interface enP4p65s0 # У Orange Pi 5 plus два интерфейса, и этот узел подключен по enP4p65s0 + virtual_router_id 51 + priority 80 # Еще меньший приоритет + advert_int 1 + unicast_src_ip 192.168.1.28 # IP текущего хоста (opi5plus-3) + unicast_peer { + 192.168.1.27 # IP первого хоста (opi5plus-1) + 192.168.1.28 # IP второго хоста (opi5plus-2) + } + virtual_ipaddress { + 192.168.1.200 # Виртуальный IP + } +} +``` + +Добавим `Keepalived` в автозагрузку на всех мастер-узлах и запустим его: +```bash +sudo systemctl enable keepalived +sudo systemctl start keepalived +``` + +Теперь, если вы на первом мастер-узле (opi5plus-1) проверить доступные IP-адреса: +```bash +ip addr show +``` + +то увидим: +```text +... +... +2: enP4p65s0: mtu 1500 qdisc fq_codel state UP group default qlen 1000 + link/ether c0:74:2b:fd:42:3c brd ff:ff:ff:ff:ff:ff + inet 192.168.1.26/24 brd 192.168.1.255 scope global dynamic noprefixroute enP4p65s0 + valid_lft 68779sec preferred_lft 68779sec + inet 192.168.1.200/32 scope global enP4p65s0 + valid_lft forever preferred_lft forever +... +``` +Обратите внимание на виртуальный IP-адрес `192.168.1.200` находится в другой подсети (CIDR) и имеет маску `/32` (то +есть с маской подсети `255.255.255.255`). Это "точечная" подсеть, содержащая только один адрес, не привязан к основной +подсети интерфейса (/24) и это позволяет VIP "плавать" между узлами, не вызывая конфликтов с основными IP-адресами +и не требуя изменения подсети на каждом узле. VIP рассматривается как уникальный адрес, не требующий маршрутизации, +он просто "привязан" к интерфейсу. + +Теперь панель `Traefik` доступна по VIP-адресу `http://192.168.1.200:9000/dashboard/#`, т.к. трафик с этого адреса +будет перенаправлен на один из мастер-узлов. + +API Kubernetes тоже теперь доступен по VIP-адресу. Все воркер-узлы, подключенные к кластеру, лучше подключать к +кластеру через VIP-адрес. Сами мастер узлы знают свои IP и взаимодействую через `etcd`, но воркеры подключаясь +через VIP будут более устойчивы к сбоям мастер-узлов. Подсоединить удаленный воркер-узел к кластеру лучше через VIP. +Для этого нужно на роутере сети настроить проброс порта `6443` с внешнего IP роутера, на виртуальный IP-адрес внутри +сети (тоже на `6443` порт). После проверить, что с внешнего хоста API Kubernetes доступно: +```bash +curl -k https://:6443 +``` + +Если отклик есть (например, `Unauthorized`), то можно подключить удаленый воркер-узел к кластеру: +```bash +curl -sfL https://get.k3s.io | sh -s - agent --server https://:6443 --token +``` + +Когда процесс завершится, на любом мастер-узле можно проверить, что воркер-узел подключился: +```bash +sudo k3s kubectl get nodes +``` + +Получим, например: +```text +NAME STATUS ROLES AGE VERSION +opi5plus-1 Ready control-plane,etcd,master 5d4h v1.31.5+k3s1 +opi5plus-2 Ready control-plane,etcd,master 8d v1.31.5+k3s1 +opi5plus-3 Ready control-plane,etcd,master 7d2h v1.31.5+k3s1 +rpi3b Ready 25h v1.31.6+k3s1 +vps-sw-eye Ready 7h35m v1.31.6+k3s1 +``` \ No newline at end of file