From 6132c774c32c6aed610bac6a16cf7e249b60e631 Mon Sep 17 00:00:00 2001 From: erjemin Date: Thu, 2 Jan 2025 16:21:02 +0300 Subject: [PATCH] add: keepalived (-2-) --- raspberry-and-orange-pi/k8s.md | 168 +++++++++++++++++++++++---------- 1 file changed, 120 insertions(+), 48 deletions(-) diff --git a/raspberry-and-orange-pi/k8s.md b/raspberry-and-orange-pi/k8s.md index a4ead24..7dfa573 100644 --- a/raspberry-and-orange-pi/k8s.md +++ b/raspberry-and-orange-pi/k8s.md @@ -573,9 +573,9 @@ sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin kub #### Установка CRI (Container Runtime Interface -Так же нам надо **на каждый узел** установить `cri-dockerd` -- демон, который позволяет Kubernetes использовать +Так же нам надо **на каждый узел** установить `cri-dockerd` — демон, который позволяет Kubernetes использовать Docker в качестве контейнерного рантайма. Начиная с версии 1.20, Kubernetes прекратил прямую поддержку Docker -и для взаимодействия появился `cri-dockerd` -- интерфейс Container Runtime Interface (CRI) для Docker, +и для взаимодействия появился `cri-dockerd` — интерфейс Container Runtime Interface (CRI) для Docker, выступающий в роли моста между Kubernetes и Docker. Он позволяет Kubernetes управлять контейнерами. Найти самый свежий релиз `cri-dockerd` можно на [странице релизов](https://github.com/Mirantis/cri-dockerd/releases). @@ -629,29 +629,29 @@ KillMode=process WantedBy=multi-user.target ``` Где: -* [Unit] -- Описывает службу. - * `Description` -- Описание службы. - * `Documentation` -- Ссылка на документацию. - * `After` -- Указывает, что служба должна быть запущена после указанных служб. - * `Wants` -- Указывает, что служба требует наличия указанных служб. - * `Requires` -- Указывает зависимость от сокета `cri-docker.socket`. -* [Service] -- Конфигурация службы. - * `Type` -- Определяет тип службы. - * `ExecStart` -- Указывает команду, которая будет запущена при старте службы. - * `ExecReload` -- Указывает команду, которая будет запущена при перезагрузке службы. - * `TimeoutSec` -- Устанавливает время ожидания завершения службы. - * `RestartSec` -- Устанавливает время между перезапусками службы. - * `Restart` -- Указывает, как ведет себя сервис в случае ошибки. `always` -- перезапускать всегда. - * `StartLimitBurst` -- Устанавливает количество попыток запуска службы. - * `StartLimitInterval` -- Устанавливает интервал между попытками запуска службы. - * `LimitNOFILE` -- Устанавливает максимальное количество открытых файлов. `infinity` -- неограничено. - * `LimitNPROC` -- Устанавливает максимальное количество процессов. - * `LimitCORE` -- Устанавливает максимальный размер ядра. - * `TasksMax` -- Устанавливает максимальное количество задач. - * `Delegate` -- Указывает, что служба может делегировать свои привилегии. - * `KillMode` -- Устанавливает режим завершения процесса. -* [Install] -- Указывает, когда и как служба должна быть активирована. - * `WantedBy` -- Указывает, что служба должна быть активирована вместе с ёmulti-user.targetё. +* [Unit] — Описывает службу. + * `Description` — Описание службы. + * `Documentation` — Ссылка на документацию. + * `After` — Указывает, что служба должна быть запущена после указанных служб. + * `Wants` — Указывает, что служба требует наличия указанных служб. + * `Requires` — Указывает зависимость от сокета `cri-docker.socket`. +* [Service] — Конфигурация службы. + * `Type` — Определяет тип службы. + * `ExecStart` — Указывает команду, которая будет запущена при старте службы. + * `ExecReload` — Указывает команду, которая будет запущена при перезагрузке службы. + * `TimeoutSec` — Устанавливает время ожидания завершения службы. + * `RestartSec` — Устанавливает время между перезапусками службы. + * `Restart` — Указывает, как ведет себя сервис в случае ошибки. `always` — перезапускать всегда. + * `StartLimitBurst` — Устанавливает количество попыток запуска службы. + * `StartLimitInterval` — Устанавливает интервал между попытками запуска службы. + * `LimitNOFILE` — Устанавливает максимальное количество открытых файлов. `infinity` — неограничено. + * `LimitNPROC` — Устанавливает максимальное количество процессов. + * `LimitCORE` — Устанавливает максимальный размер ядра. + * `TasksMax` — Устанавливает максимальное количество задач. + * `Delegate` — Указывает, что служба может делегировать свои привилегии. + * `KillMode` — Устанавливает режим завершения процесса. +* [Install] — Указывает, когда и как служба должна быть активирована. + * `WantedBy` — Указывает, что служба должна быть активирована вместе с ёmulti-user.targetё. Создадим конфигурацию сокета `cri-docker.socket` для службы `cri-dockerd`. Она определяет, как и где сервис будет слушать входящие соединения и управлять доступом к нему. Создадим файл: @@ -676,16 +676,16 @@ WantedBy=sockets.target ``` Где: -* [Unit] -- Описывает службу. - * `Description` -- Описание сокета. - * `PartOf` -- Указывает, что этот сокет является частью службы cri-docker.service. -* [Socket] -- Конфигурация сокета. - * `ListenStream` -- Указывает путь к сокету, который будет использоваться для связи. - * `SocketMode` -- Устанавливает права доступа к сокету (0660 -- чтение и запись для владельца и группы, чтение для остальных). - * `SocketUser` -- Устанавливает владельца сокета. - * `SocketGroup` -- Устанавливает группу, которой принадлежит сокет. +* [Unit] — Описывает службу. + * `Description` — Описание сокета. + * `PartOf` — Указывает, что этот сокет является частью службы cri-docker.service. +* [Socket] — Конфигурация сокета. + * `ListenStream` — Указывает путь к сокету, который будет использоваться для связи. + * `SocketMode` — Устанавливает права доступа к сокету (0660 — чтение и запись для владельца и группы, чтение для остальных). + * `SocketUser` — Устанавливает владельца сокета. + * `SocketGroup` — Устанавливает группу, которой принадлежит сокет. * [Install]: Указывает, когда и как сокет должен быть активирован. - * `WantedBy` -- Указывает, что сокет должен быть активирован вместе с sockets.target. + * `WantedBy` — Указывает, что сокет должен быть активирован вместе с sockets.target. * Этот файл гарантирует, что cri-dockerd будет слушать на указанном сокете . Теперь перезагрузим службы, настроим их на автозапуск и запустим их: @@ -718,25 +718,29 @@ RuntimeApiVersion: v1 #### Настройка балансировщика нагрузки Для обеспечения высокой доступности и автоматического переключения узлов в случае сбоя используется `keepalived`. -Он нужен только на мастер-узлах, используется для настройки виртуальных IP-адресов (VIP) и в качестве -балансировки нагрузки. +Он используется для настройки виртуальных IP-адресов (VIP) и в качестве балансировки нагрузки. VIP будет перемещаться +между узлами в зависимости от их состояния и приоритетов. Это означает, что в любой момент времени только один узел +будет отвечать на запросы, направленные на VIP. Когда этот узел выходит из строя, резервный узел с наивысшим +приоритетом берет на себя VIP и начинает отвечать на запросы. Это достигается с помощью протокола VRRP (Virtual Router +Redundancy Protocol), который обеспечивает автоматическое переключение VIP между узлами. -На Ubuntu для Orange Pi 5 `keepalived` уже установлен. Но можно проверить его наличие: +На предыдущейм шаге мы уже установили `keepalived` и можно проверить его наличие: ```shell dpkg -l | grep keepalived ``` -и в случае отсутствия установить: -```shell -sudo apt install keepalived -``` - -Настройка `keepalived` осуществляется через файл конфигурации `/etc/keepalived/keepalived.conf`. Создадим его: +Настройка `keepalived` осуществляется через файл конфигурации `/etc/keepalived/keepalived.conf`. Этот конфиг +настраивает мониторинг состояния API-сервера и переключения на резервный узел в случае сбоя основного узла. Создадим +файл конфигурации: ```shell sudo nano /etc/keepalived/keepalived.conf ``` -Пример конфигурации для мастер-узла `opi5plus-1`: +Пример конфигурации для мастер-узла `opi5plus-1`. Он будет называться -- +**Betelgeuse** (_звезда спектрального класса M, т.е. оранжевая звезда, так же как и апельсинка Orange Pi_), и иметь +VIP `192.168.1.250` (поменяйте на свой). Так же надо указать пароль для аутентификации между узлами, +участвующими в VRRP (вместо `********`) и чтобы узлы могли корректно взаимодействовать между собой этот пароль должен +быть одинаковым на всех узлах. ``` global_defs { enable_script_security @@ -745,11 +749,11 @@ global_defs { vrrp_script check_apiserver { script "/etc/keepalived/check_apiserver.sh" - interval 3 + interval 4 } -vrrp_instance VI_1 { - state BACKUP +vrrp_instance ORANGENET { + state MASTER interface enP4p65s0 virtual_router_id 5 priority 100 @@ -766,4 +770,72 @@ vrrp_instance VI_1 { check_apiserver } } -``` \ No newline at end of file +``` + +Вот что делает каждая часть конфигурации: +* `global_defs` — Глобальные настройки. + * `enable_script_security` — Включает безопасность скриптов. + * `script_user nobody` — Указывает пользователя, от имени которого будут выполняться скрипты, `noboby` -- + минимальные привилегии. +* `vrrp_script check_apiserver` — Определяет скрипт для проверки состояния API-сервера. + * `script "/etc/keepalived/check_apiserver.sh"` — Указывает путь к скрипту. + * `interval 4` — Интервал выполнения скрипта в секундах. +* `vrrp_instance MilkyWay` — Определяет экземпляр VRRP (Virtual Router Redundancy Protocol). + * `state MASTER` — Указывает, что этот узел находится в резервном состоянии. + * `interface enP4p65s0` — Указывает сетевой интерфейс (у нас `enP4p65s0`). + * `virtual_router_id 5` — Идентификатор виртуального маршрутизатора (от 1 до 255) + * `priority 100` — Приоритет узла (чем выше значение, тем выше приоритет). + * `advert_int 1` — Интервал объявлений VRRP в секундах. + * `nopreempt` — Запрещает узлу с более высоким приоритетом вытеснять активный узел, даже если он становится + доступным. Это означает, что текущий MASTER узел останется активным до тех пор, пока он работает корректно, + и только в случае его сбоя резервный узел с более высоким приоритетом станет MASTER. Другое значения `preempt` + (и это значение по умолчанию) указывает, что если узел с более высоким приоритетом становится доступным, то он + вытеснит текущий активный MASTER-узел. Т.е. если узел с более высоким приоритетом восстанавливается, + он автоматически снова станет MASTER. + * `authentication` — Настройки аутентификации. + * `auth_type PASS` — Тип аутентификации (пароль). + * `auth_pass ********` — Пароль для аутентификации. + * `virtual_ipaddress` — Виртуальный IP-адрес, по которому будет доступны узлы кластера. + * `192.168.1.250` — Виртуальный IP-адрес, который будет использоваться. + * `track_script` — Настройки отслеживания скрипта. + * `check_apiserver` — Указывает скрипт для проверки состояния. + +Теперь создадим скрипт `/etc/keepalived/check_apiserver.sh` для проверки состояния API-сервера. Он будет проверять +доступность API-сервера Kubernetes: +```shell +sudo nano /etc/keepalived/check_apiserver.sh +``` + +Содержимое скрипта: +```shell +#!/bin/bash +# File: /etc/keepalived/check_apiserver.sh + +# Задаем переменные: VIP-адрес API-сервера, порт и протокол +APISERVER_VIP=192.168.1.250 +APISERVER_DEST_PORT=8888 +PROTO=http + +# Определение функции errorExit +errorExit() { + # $* — это специальная переменная в shell, которая представляет все позиционные параметры, переданные в скрипт. + # 1>&2 — это перенаправление стандартного вывода (file descriptor 1) в стандартный поток ошибок (file descriptor 2). + echo "*** $*" 1>&2 + # "код завершения" 1. + exit 1 +} + +# Проверка доступности API-сервера на localhost +curl --silent --max-time 2 --insecure ${PROTO}://localhost:${APISERVER_DEST_PORT}/ -o /dev/null || errorExit "Error GET ${PROTO}://localhost:${APISERVER_DEST_PORT}/" + +# Если в сетевом интерфейсе узла есть VIP-адрес, то проверяем доступность API-сервера по VIP-адресу +if ip ad | 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 + +# Если все проверки прошли успешно, то "код завершения" 0 +exit 0 +``` + +`keepalived` будет отслеживать код завершения и если скрипт завершится с ненулевым кодом, он интерпретирует это +как сбой и инициирует переключение виртуального IP-адреса (VIP) на другой узел с более высоким приоритетом. \ No newline at end of file