Привет всем! В данной статье мы расскажем о том, как Stateful приложения хранят свои данные в Highly Available варианте CI/CD платформы Gitorion. В составе платформы Gitorion работает три Stateful приложения:
Gitea/Forgejo — хранит git‑репозитории с кодом приложений;
Jenkins — хранит свои настройки и пайплайны;
Docker‑registry — хранит Docker‑образы пользовательских микросервисов.
Также свои данные могут хранить пользовательские приложения, которые будут разрабатывать на платформе и деплоить в продакшен.
Абстрактная постановка задачи
Для Highly Avalable кластера Kubernetes, территориально разнесенного в два дата центра, разработать хранилище данных, в котором Stateful приложения могли бы хранить свои файлы и директории. На случай падения одного из дата центров, во втором дата центре должна быть актуальная копия данных Stateful приложений. Модули Stateful приложений должны подключаться к хранилищу по сети, чтобы обеспечить возможность горизонтального масштабирования.
Дисковая система и менеджмент разделов
В каждом из двух дата центров выделяем по одному узлу, который будет выполнять роль NAS. В роли NAS может выступать отдельный VPS или выделенный сервер с серверными дисками. Зависит от вашего бюджета и предпочтений. Важно, чтобы была возможность подключать новые диски, когда закончится свободное место.
Для менеджмента разделов мы используем LVM.
Следующие ниже действия выполняем зеркально на обоих NAS в каждом дата центре. Создаем отдельный Volume Group с именем «nas». Отдельный VG позволит решить три задачи:
хранить данные приложений отдельно от операционной системы, чтобы в случае падения, операционная система не утянула за собой данные хранилища;
добавить в Volume Group новые накопители и расширить разделы Logical Volume, когда на них закончится свободное место;
создавать новые Logical Volume и подключать к ним новые Presistent Volume по мере необходимости.
Для инстансов Gitea/Forgejo, Jenkins и Docker‑registry создаем отдельные Logical Volume в Volume Group «nas», созданном выше. Забегая вперед, отметим, что для репликации потребуются LV одинакового размера в каждом из дата центров для конкретно взятого инстанса.
Репликация данных между дата центрами
Для репликации данных мы выбирали между Ceph, GlusterFS и DRBD. Ceph отмели из‑за требовательности к ресурсам и требований к наличию отдельной ноды для хранения метаданных. GlusterFS оказался неплох для репликации в пределах одного дата центра при небольших задержках по сети между реплицируемыми нодами и непригоден для репликации между географически разнесенными нодами и при высоких задержках по сети. В итоге наш выбор пал на DRBD — проверенный временем инструмент, включенный в ядро Linux c 2009 года.
DRBD выполняет репликацию локального блочного устройства по сети на удаленное блочное устройство. Своего рода сетевое зеркало RAID1. В роли реплицируемых блочных устройств в нашем случае выступают Logical Volume, созданные в предыдущем пункте. DRBD создает виртуальные блочные устройства /dev/drbd1, /dev/drbd2, /dev/drbd3... /dev/drbdX и ассоциирует их с реплицируемыми блочными устройствами. Впоследствии на виртуальном блочном устройстве /dev/drbdX создается файловая система, монтируется и используется приложениями.
Конфигурационный файл DRBD:
resource r0 {
volume 0 {
device /dev/drbd1;
disk /dev/nas/disk1;
meta-disk internal;
}
volume 1 {
device /dev/drbd2;
disk /dev/nas/disk2;
meta-disk internal;
}
volume 2 {
device /dev/drbd3;
disk /dev/nas/disk3;
meta-disk internal;
}
on dc1-nas {
address 1.1.1.1:7789;
}
on dc2-nas {
address 2.2.2.2:7789;
}
}
Список блочных устройств:
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
sda 8:0 0 5G 0 disk
├─sda1 8:1 0 487M 0 part /boot
├─sda2 8:2 0 1K 0 part
└─sda5 8:5 0 4.5G 0 part
├─template--vg-root 254:1 0 3.6G 0 lvm /
└─template--vg-swap_1 254:3 0 980M 0 lvm
sdb 8:16 0 5G 0 disk
├─nas-disk1 254:0 0 1G 0 lvm
│ └─drbd1 147:1 0 1023.9M 0 disk
├─nas-disk2 254:2 0 1G 0 lvm
│ └─drbd2 147:2 0 1023.9M 0 disk
├─nas-disk3 254:4 0 1G 0 lvm
└─drbd3 147:3 0 1023.9M 0 disk
Превращаем файловое хранилище в NAS
Существует несколько вариантов подключения внешних томов Persistent Volume к модулям Kubernetes. Мы выбрали сетевой том Persistent Volume типа NFS. Данное архитектурное решение позволяет горизонтально масштабировать кластер Kubernetes, о чем мы расскажем чуть позже.
А пока превратим наше файловое хранилище в NAS. Дальнейшие действия выполняем только на Primary ноде, являющейся источником репликации DRBD в ведущем дата центре. Форматируем виртуальные блочные устройства DRBD и монтируем в директорию /mnt
mkfs.ext4 /dev/drbd1
mkfs.ext4 /dev/drbd2
mkfs.ext4 /dev/drbd3
mount /dev/drbd1 /mnt/disk1
mount /dev/drbd2 /mnt/disk2
mount /dev/drbd3 /mnt/disk3
Устанавливаем NFS-сервер и экспортируем смонтированные файловые системы в сеть по протоколу NFS. Файл /etc/exports
/mnt/disk1/ 3.3.3.3(rw,sync,no_subtree_check,all_squash)
/mnt/disk2/ 3.3.3.3(rw,sync,no_subtree_check,all_squash)
/mnt/disk3/ 3.3.3.3(rw,sync,no_subtree_check,all_squash)
В итоге мы получили NAS в ведущем дата центре, который отдает по NFS в сеть директории, смонтированные на виртуальные блочные устройства DRBD. А DRBD реплицирует данные на Seconrady DRBD ноду в ведомый дата центр.
Подключение модулей Kubernetes к NAS
В Kubernetes мы создали тома Persistent Volume типа NFS которые подключаются по сети к NAS. А уже Persistent Volume подключаются к Stateful модулям Kubernetes.
Падение ведомого дата центра
В случае падения ведомого дата центра, модули Stateful просто продолжают свою работу в ведущем дата центре. Единственное, что нужно сделать, это в ведущем дата центре отключить Primary ноду из кластера DRBD и перевести в Stand Alone режим пока будут чинить упавший дата центр. Как только починят ведомый дата центр, нужно подключить Primary ноду обратно в кластер DRBD, и накопившаяся дельта данных реплицируется на Secondary ноду DRBD.
Падение ведущего дата центра
В случае падения ведущего дата центра Kubernetes запустит модули Stateful приложений в выжившем ведомом дата центре. А тома Persistent Volume модулей Gitea/Forgejo, Jenkins, Docker‑registry подключатся к NAS в выжившем дата центре и Stateful приложения продолжат работать с данным, которые реплицировал RDBD из упавшего дата центра на момент падения.
Отдельно осветим механизм переключение Persistent Volume c одного NAS на другой. В спецификации Persistent Volume мы задали доменное имя NFS-сервера nas.gitorion.ru
apiVersion: v1
kind: PersistentVolume
metadata:
name: disk1
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 50Gi
nfs:
path: /mnt/disk1
server: nas.gitorion.ru
persistentVolumeReclaimPolicy: Retain
storageClassName: net-disks
А на worker-ах доменное имя NFS-сервера nas.gitorion.ru статикой в /etc/hosts связываем с IP-адресом NAS в том же дата центре, в котором расположен worker:
Файл /etc/hosts на dc1-worker:
127.0.0.1 localhost
1.1.1.1 nas.gitorion.ru
Файл /etc/hosts на dc2-worker:
127.0.0.1 localhost
2.2.2.2 nas.gitorion.ru
В итоге модули Stateful приложений, используя одно и то же доменное имя NFS-сервера nas.gitorion.ru, в спецификации Persistent Volume подключаются к NAS в дата центре, в котором будут запущены.
После восстановления упавшего дата центра репликацию DRBD нужно развернуть в обратном направлении - ноду DRBD в выжившем дата центре сделать Primary, а в восстановленном дата центре Secondary.
Split-brain
Это ситуация, при которой оба дата центра живы, но пропадает связь между ними. Мы используем только однонаправленную DRBD репликацию. В любой момент времени модули Stateful запущены только в ведущем дата центре и подключены к NAS и Primary ноде DRBD, являющейся источником репликации. Второй NAS всегда в роли ведомого, DRBD нода на нем работает в режиме Secondary и просто хранит копию данных на случай падения ведущего дата центра. Поэтому ситуация одновременной записи в оба NAS исключена.
Горизонтальное масштабирование
Наличие реплицируемых NAS в двух дата центрах открывает возможность горизонтального масштабирования пользовательских Stateful приложений, когда мощностей имеющихся дата центров станет не хватать.
В этом случае можно подключить в кластер Kubernetes дополнительные worker‑ы из других дата центров и запустить на них дополнительные реплики пользовательских Stateful приложений, которые будут по NFS подключаться к ведущему NAS.
Однако, не стоит забывать, что Stateful приложения будут подключаться к NAS через Интернет, и могут существенно возрасти задержки по сравнению с подключением к NAS в пределах одного дата центра.
Заключение
В итоге мы получили внешнее файловое хранилище для Highly Available кластера Kubernetes, разнесенного на два дата центра. Файловое хранилище подключается к кластеру Kubernetes как NAS по сетевому протоколу NFS, что позволяет горизонтально масштабировать Stateful приложения. В каждом дата центре имеется свой NAS, данные между которыми реплицирует DRBD, что дает возможность останавливать Stateful приложения в одном дата центре и запускать в другом в случае аварий. Спасибо за внимание!