GlusterFS как внешнее хранилище для Kubernetes

от автора

image
Поиск оптимального хранилища — это довольно сложный процесс, у всего есть плюсы и минусы. Разумеется, лидером в данной категории является CEPH, но это довольно сложная система, хотя и с очень богатым функционалом. Для нас такая система избыточна, учитывая то, что нам нужно было простое реплицируемое хранилище в режиме master-master на пару терабайт. Изучив много материала, было принято решение протестировать наиболее модный на рынке продукт для интересующей нас схемы. В связи с тем, что готового решения подобного плана найдено не было, хочется поделиться своими наработками по данной теме и описать проблемы, с которыми мы столкнулись в процессе развертывания.

Цели

Что мы ждали от нового хранилища:

  • Возможность работы с четным числом нод для репликации.
  • Простая установка, настройка, поддержка
  • Система должна быть взрослой, проверенной временем и пользователями
  • Возможность расширения места на хранилище без простоя системы
  • Хранилище должно быть совместимо с Kubernetes
  • Должен быть автоматический Failover при падениях одного из узлов

Именно по последнему пункту у нас и возникло много вопросов.

Развертывание

Для развертывания было создано две виртуалки на CentOs 8. К каждой подключено по дополнительному диску с СХД.

Предварительная подготовка

Для GlusterFS нужно выделить отдельный диск с XFS, чтобы он никак не влиял на систему.

Выделяем партицию:

$ fdisk /dev/sdb Command (m for help): n Partition type    p   primary (0 primary, 0 extended, 4 free)    e   extended (container for logical partitions) Select (default p): p Partition number (1-4, default 1):  1 First sector (2048-16777215, default 2048):  Last sector, +sectors or +size{K,M,G,T,P} (2048-16777215, default 16777215):    Created a new partition 1 of type ‘Linux’ and of size 8 GiB. Command (m for help): w   The partition table has been altered. Calling ioctl() to re-read partition table. Syncing disks. 

Форматируем в XFS и монтируем:

$ mkfs.xfs /dev/sdb1 $ mkdir /gluster $ mount /dev/sdb1 /gluster

И в довершении закидываем запись в /etc/fstab для автоматического монтирования директории при запуске системы:

/dev/sdb1       /gluster        xfs     defaults        0       0

Установка

По поводу установки написано много статей, в связи с этим сильно углубляться в процесс не будем, просто рассмотрим то, на что стоит обратить внимание.

На обеих нодах ставим и запускаем glusterfs последней версии:

$ wget -P /etc/yum.repos.d  https://download.gluster.org/pub/gluster/glusterfs/LATEST/CentOS/glusterfs-rhel8.repo $ yum -y install yum-utils $ yum-config-manager --enable PowerTools $ yum install -y glusterfs-server $ systemctl start glusterd 

Дальше надо сказать гластеру где его соседняя нода. Делается только с одной ноды. Важный момент: если у вас доменная сеть, то тут обязательно указывать имя сервера с доменом, иначе в будущем придется все переделывать.

$ gluster peer probe gluster-02.example.com

Если прошло успешно, то проверяем связь командой с обоих серверов:

$ gluster peer status Number of Peers: 1  Hostname: gluster-02.example.com Uuid: a6de3b23-ee31-4394-8bff-0bd97bd54f46 State: Peer in Cluster (Connected) Other names: 10.10.6.72 

Теперь можно создать Volume в который мы будем писать.

gluster volume create main replica 2 gluster-01.example.com:/gluster/main gluster-02.example.com:/gluster/main force

Где:

Запускаем Volume и проверяем его работоспособность:

gluster volume start main gluster volume status main

Для реплицируемых Volume рекомендуется установить следующие параметры:

$ gluster volume set main network.ping-timeout 5 $ gluster volume set main cluster.quorum-type fixed $ gluster volume set main cluster.quorum-count 1 $ gluster volume set main performance.quick-read on

Этими простыми действиями мы собрали кластер GlusterFS. Осталось подключиться к нему и проверить работоспособность. На клиентской машине установлена Ubuntu, для монтирования нужно установить клиент:

$ add-apt-repository ppa:gluster/glusterfs-7 $ apt install glusterfs-client $ mkdir /gluster $ mount.glusterfs gluster-01.example.com:/main /gluster

Gluster при подключении к одной из нод, отдает адреса всех нод и автоматически подключается ко всем. Если клиент уже подключился, то отказ одной из нод не приведет к остановке работы. Но вот если будет недоступен первый узел, подключиться в случае разрыва сессии уже не получится. Для этого при монтировании можно передать параметр backupvolfile с указанием второй ноды.

mount.glusterfs gluster-01.example.com:/main /gluster -o backupvolfile-server=gluster-02.example.com

Важный момент: gluster синхронизирует файлы между нодами только если их изменение было через монтированный volume. Если делать изменения напрямую на нодах, будет рассинхрон файлов.

Подключение к Kubernetes

На этом этапе и начались вопросы: «А как это подключить?». И здесь есть несколько вариантов. Рассмотрим их.

Heketi

Самый популярный и рекомендуемый — использовать внешний сервис: heketi. heketi — это прослойка между kubernetes и gluster, которая позволяет управлять хранилищем через http и работать с ним. Но heketi и будет той самой единой точкой отказа, т.к. сервис не кластеризуется. Второй инстанс данного сервиса не сможет самостоятельно работать, т.к. любые изменения хранятся в локальной БД. Запуск в kubernetes данного сервиса также не подходит, т.к. ему нужен статичный диск, на котором будет хранится его БД. В связи с этим данный вариант оказался самым не подходящим.

Endpoint в Kubernetes

Если у вас Kubernetes на системах с пакетными менеджерами, то это очень удобный вариант. Смысл заключается в том, что для всех серверов GlusteFS в Kubernetes создается общий Endpoint. На этот Endpoint вешается сервис и к этому сервису мы уже будем монтироваться. Для работы данного варианта необходимо на каждой ноде Kubernetes установить glusterfs-client и убедиться в возможности монтирования. В Kubernetes деплоим следующий конфиг:

apiVersion: v1 kind: Endpoints metadata:    name: glusterfs-cluster subsets:   - addresses:       #Тут указываем ip наших серверов       - ip: 10.10.6.71     ports:       #Тут просто можно оставить 1, порт роли не играет       - port: 1   - addresses:       - ip: 10.10.6.72     ports:       - port: 1  --- apiVersion: v1 kind: Service metadata:   name: glusterfs-cluster spec:   ports:   - port: 1 

Теперь мы можем создать простой тестовый деплоймент и проверить как происходит монтирование. Ниже пример простого тестового деплоймента:

apiVersion: apps/v1 kind: Deployment metadata:   name: gluster-test spec:   replicas: 1   selector:     matchLabels:       app: gluster-test   template:     metadata:       labels:         app: gluster-test     spec:       volumes:       - name: gluster         glusterfs:           endpoints: glusterfs-cluster           path: main       containers:       - name: gluster-test         image: nginx         volumeMounts:         - name: gluster           mountPath: /gluster

Данный вариант нам не подошел, потому что у нас на всех нодах Kubernetes стоит container-linux. Пакетного менеджера там нет, поэтому установить gluster-client для монтирования не удалось. В связи с этим был найден третий вариант, который и было решено использовать.

GlusterFS + NFS + keepalived

GlusterFS до недавнего времени предлагал собственный NFS сервер, но теперь для NFS используется внешний сервис nfs-ganesha. Об этом написано довольно немного, в связи с этим разберем как это настроить.

Репозиторий нужно прописать вручную. Для этого в файле /etc/yum.repos.d/nfs-ganesha.repo вносим:

[nfs-ganesha] name=nfs-ganesha baseurl=https://download.nfs-ganesha.org/2.8/2.8.0/RHEL/el-8/$basearch/ enabled=1 gpgcheck=1 [nfs-ganesha-noarch] name=nfs-ganesha-noarch baseurl=https://download.nfs-ganesha.org/2.8/2.8.0/RHEL/el-8/noarch/ enabled=1 gpgcheck=1 

И устанавливаем:

yum -y install nfs-ganesha-gluster --nogpgcheck 

После установки проводим базовую конфигурацию в файле /etc/ganesha/ganesha.conf.

# create new NFS_CORE_PARAM {     # possible to mount with NFSv3 to NFSv4 Pseudo path     mount_path_pseudo = true;     # NFS protocol     Protocols = 3,4; } EXPORT_DEFAULTS {     # default access mode     Access_Type = RW; } EXPORT {     # uniq ID     Export_Id = 101;     # mount path of Gluster Volume     Path = "/gluster/main";     FSAL {         # any name         name = GLUSTER;         # hostname or IP address of this Node         hostname="gluster-01.example.com";         # Gluster volume name         volume="main";     }     # config for root Squash     Squash="No_root_squash";     # NFSv4 Pseudo path     Pseudo="/main";     # allowed security options     SecType = "sys"; } LOG {     # default log level     Default_Log_Level = WARN; } 

Нужно стартовать сервис, включить nfs для нашего volume и проверить то, что он включился.

$ systemctl start nfs-ganesha $ systemctl enable nfs-ganesha $ gluster volume set main nfs.disable off $ gluster volume status main 

В результате статус должен показать что запустился nfs сервер для нашего volume. Нужно сделать mount и проверить.

mkdir /gluster-nfs mount.nfs gluster-01.example.com:/main /gluster-nfs

Но данный вариант не отказоустойчив, поэтому нужно сделать VIP адрес, который будет ездить между двумя нашими нодами и помогать переключать трафик в случае падения одной из нод.

Установка keepalived в CentOs производится сразу через пакетный менеджер.

$ yum install -y keepalived

Производим конфигурацию сервиса в файле /etc/keepalived/keepalived.conf:

global_defs {     notification_email {         admin@example.com     }     notification_email_from alarm@example.com     smtp_server mail.example.com     smtp_connect_timeout 30      vrrp_garp_interval 10     vrrp_garp_master_refresh 30 }  #Cкрипт для проверки того, что гластер запущен. Если проверка не пройдет, VIP переедет. vrrp_script chk_gluster {     script "pgrep glusterd"     interval 2 }  vrrp_instance gluster {     interface ens192     state MASTER #Для второй ноды тут будет BACKUP     priority 200 #Для второй ноды тут будет число меньше, например 100     virtual_router_id 1     virtual_ipaddress {         10.10.6.70/24     }      unicast_peer {         10.10.6.72 #на второй ноде тут надо указать будет адрес первой     }      track_script {         chk_gluster     } } 

Теперь мы можем запустить сервис и проверить что VIP на ноде появился:

$ systemctl start keepalived $ systemctl enable keepalived $ ip addr 1: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000     link/ether 00:50:56:97:55:eb brd ff:ff:ff:ff:ff:ff     inet 10.10.6.72/24 brd 10.10.6.255 scope global noprefixroute ens192        valid_lft forever preferred_lft forever     inet 10.10.6.70/24 scope global secondary ens192        valid_lft forever preferred_lft forever 

Если у нас все заработало, то осталось внести PersistentVolume в Kubernetes и создать тестовый сервис для проверки работы.

--- apiVersion: v1 kind: PersistentVolume metadata:   name: gluster-nfs spec:   capacity:     storage: 10Gi   accessModes:     - ReadWriteMany   persistentVolumeReclaimPolicy: Retain   nfs:     server: 10.10.6.70     path: /main  --- apiVersion: v1 kind: PersistentVolumeClaim metadata:  name: gluster-nfs spec:  accessModes:  - ReadWriteMany  resources:    requests:      storage: 10Gi  volumeName: "gluster-nfs"  --- apiVersion: apps/v1 kind: Deployment metadata:   name: gluster-test   labels:     app: gluster-test spec:   replicas: 1   selector:     matchLabels:       app: gluster-test   template:     metadata:       labels:         app: gluster-test     spec:       volumes:       - name: gluster         persistentVolumeClaim:           claimName: gluster-nfs       containers:       - name: gluster-test         image: nginx         volumeMounts:         - name: gluster           mountPath: /gluster

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

Итоги

В данной статье мы рассмотрели 3 возможных варианта подключения GlusterFS к Kubernetes, в нашем варианте возможно добавить provisioner в Kubernetes, но он пока нам не нужен. Осталось добавить результаты тестов производительности между NFS и Gluster на одних и тех же нодах.

Файлы по 1Mb:

sync; dd if=/dev/zero of=tempfile bs=1M count=1024; sync Gluster: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 2.63496 s, 407 MB/s NFS: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 5.4527 s, 197 MB/s 

Файлы по 1Kb:

sync; dd if=/dev/zero of=tempfile bs=1K count=1048576; sync Gluster: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 70.0508 s, 15.3 MB/s NFS: 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 6.95208 s, 154 MB/s 

NFS работает одинаково при любых размерах файлов, разница в скорости особенно не ощущается, в отличии от GlusterFS, которые при маленьких файлах деградирует очень сильно. Но при этом, при больших размерах файлов NFS показывает производительность в 2-3 раза ниже, чем Gluster.

ссылка на оригинал статьи https://habr.com/ru/post/498160/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *