CI/CD Kubernetes платформа Gitorion. Реплицируемый NAS для Highly Available кластера Kubernetes

Привет всем! В данной статье мы расскажем о том, как Statefull приложения хранят свои данные в Highly Available варианте CI/CD платформы Gitorion. В составе платформы Gitorion работает три Statefull приложения:

  • Gitea/Forgejo — хранит git-репозитории с кодом приложений;

  • Jenkins — хранит свои настройки и пайплайны;

  • Docker-registry — хранит Docker-образы пользовательских микросервисов.

Также свои данные могут хранить пользовательские приложения, которые будут разрабатывать на платформе и деплоить в продакшен.

Абстрактная постановка задачи

Для Highly Avalable кластера Kubernetes, территориально разнесенного в два дата центра, разработать хранилище данных, в котором Statefull приложения могли бы хранить свои файлы и директории. На случай падения одного из дата центров, во втором дата центре должна быть актуальная копия данных Statefull приложений. Модули Statefull приложений должны подключаться к хранилищу по сети, чтобы обеспечить возможность горизонтального масштабирования.

Дисковая система и менеджмент разделов

В каждом из двух дата центров выделяем по одному узлу, который будет выполнять роль NAS. В роли NAS может выступать отдельный VPS или выделенный сервер с серверными дисками. Зависит от вашего бюджета и предпочтений. Важно, чтобы была возможность подключать новые диски, когда закончится свободное место.

Для менеджмента разделов мы используем LVM.

Дисковая система и менеджмент разделов

Дисковая система и менеджмент разделов

Следующие ниже действия выполняем зеркально на обоих NAS в каждом дата центре. Создаем отдельный Volume Group с именем «nas». Отдельный VG позволит решить две задачи:

  • хранить данные приложений отдельно от операционной системы, чтобы в случае падения, операционная система не утянула за собой данные хранилища;

  • добавить в VG новые диски и расширить разделы Logical 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

Кластер DRBD

Конфигурационный файл DRBD:

resource r0 {
  volume 0 {
    device    /dev/drbd1;
    disk      /dev/nas/forgejo;
    meta-disk internal;
  }
  volume 1 {
    device    /dev/drbd2;
    disk      /dev/nas/jenkins;
    meta-disk internal;
  }
  volume 2 {
    device    /dev/drbd3;
    disk      /dev/nas/registry;
    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-forgejo           254:0    0      1G  0 lvm
│ └─drbd1               147:1    0 1023.9M  0 disk
├─nas-jenkins           254:2    0      1G  0 lvm
│ └─drbd2               147:2    0 1023.9M  0 disk
├─nas-registry          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/forgejo
mount /dev/drbd2 /mnt/jenkins
mount /dev/drbd3 /mnt/registry

Устанавливаем NFS-сервер и экспортируем смонтированные файловые системы в сеть по протоколу NFS. Файл /etc/exports

/mnt/forgejo/ 3.3.3.3(rw,sync,no_subtree_check,all_squash)
/mnt/jenkins/ 3.3.3.3(rw,sync,no_subtree_check,all_squash)
/mnt/registry/ 3.3.3.3(rw,sync,no_subtree_check,all_squash)

Схема NAS

Схема NAS

В итоге мы получили NAS в ведущем дата центре, который отдает по NFS в сеть директории, смонтированные на виртуальные блочные устройства DRBD. А DRBD реплицирует данные на Seconrady DRBD ноду в ведомый дата центр.

Подключение модулей Kubernetes к NAS

В Kubernetes мы создали тома Persistent Volume типа NFS которые подключаются по сети к NAS. А уже Persistent Volume подключаются к Statefull модулям Kubernetes.

Схема подключения модулей Kubernetes к NAS

Схема подключения модулей Kubernetes к NAS

Падение ведомого дата центра

В случае падения ведомого дата центра, модули Statefull просто продолжают свою работу в ведущем дата центре. Единственное, что нужно сделать, это в ведущем дата центре отключить Primary ноду из кластера DRBD и перевести в Stand Alone режим пока будут чинить упавший дата центр. Как только починят ведомый дата центр, нужно подключить Primary ноду обратно в кластер DRBD, и накопившаяся дельта данных реплицируется на Secondary ноду DRBD.

Падение ведомого дата центра

Падение ведомого дата центра

Падение ведущего дата центра

В случае падения ведущего дата центра Kubernetes запустит модули Statefull приложений в выжившем ведомом дата центре. А тома Persistent Volume модулей Gitea/Forgejo, Jenkins, Docker-registry подключатся к NAS в выжившем дата центре и Statefull приложения продолжат работать с данным, которые реплицировал RDBD из упавшего дата центра на момент падения.

Падение ведущего дата центра

Падение ведущего дата центра

Отдельно осветим механизм переключение Persistent Volume c одного NAS на другой. В спецификации Persistent Volume мы задали доменное имя NFS-сервера nas.gitorion.ru

apiVersion: v1
kind: PersistentVolume
metadata:
  name: forgejo
spec:
  accessModes:
  - ReadWriteOnce
  capacity:
    storage: 50Gi
  nfs:
    path: /mnt/forgejo
    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

В итоге модули Statefull приложений, используя одно и то же доменное имя NFS-сервера nas.gitorion.ru, в спецификации Persistent Volume подключаются к NAS в дата центре, в котором будут запущены.

После восстановления упавшего дата центра репликацию DRBD нужно развернуть в обратном направлении — ноду DRBD в выжившем дата центре сделать Primary, а в восстановленном дата центре Secondary.

Split-brain

Это ситуация, при которой оба дата центра живы, но пропадает связь между ними. Мы используем только однонаправленную DRBD репликацию. В любой момент времени модули Statefull запущены только в ведущем дата центре и подключены к NAS и Primary ноде DRBD, являющейся источником репликации. Второй NAS всегда в роли ведомого, DRBD нода на нем работает в режиме Secondary и просто хранит копию данных на случай падения ведущего дата центра. Поэтому ситуация одновременной записи в оба NAS исключена.

Горизонтальное масштабирование

Наличие реплицируемых NAS в двух дата центрах открывает возможность горизонтального масштабирования пользовательских Statefull приложений, когда мощностей имеющихся дата центров станет не хватать.

В этом случае можно подключить в кластер Kubernetes дополнительные worker-ы из других дата центров и запустить на них дополнительные реплики пользовательских Statefull приложений, которые будут по NFS подключаться к ведущему NAS.

Горизонтальное масштабирование кластера Kubernetes

Горизонтальное масштабирование кластера Kubernetes

Однако, не стоит забывать, что Statefull приложения будут подключаться к NAS через Интернет, и могут существенно возрасти задержки по сравнению с подключением к NAS в пределах одного дата центра.

Заключение

В итоге мы получили внешнее файловое хранилище для Highly Available кластера Kubernetes, разнесенного на два дата центра. Файловое хранилище подключается к кластеру Kubernetes как NAS по сетевому протоколу NFS, что позволяет горизонтально масштабировать Statefull приложения. В каждом дата центре имеется свой NAS, данные между которыми реплицирует DRBD, что дает возможность останавливать Statefull приложения в одном дата центре и запускать в другом в случае аварий. Спасибо за внимание!

© Habrahabr.ru