Кластерное хранилище в Proxmox. Часть третья. Нюансы

в 7:50, , рубрики: cluster, gfs2, iscsi, openvz, proxmox, Блог компании «Alawar Entertainment», виртуализация, системное администрирование, метки: , , , ,

Здравствуйте!Кластерное хранилище в Proxmox. Часть третья. Нюансы

Третья часть статьи является своеобразным приложением к двум предыдущим, в которых я рассказывал о работе с Proxmox-кластером. В этой части я опишу проблемы, с которыми мы сталкивались в работе с Proxmox, и их решения.

Авторизованное подключение к iSCSI

Если вам понадобилось при подключении к iSCSI указать креденшиалы — лучше это делать в обход Proxmox. Почему?

  • Во-первых, потому что через web-интерфейс Proxmox невозможно создать авторизованное iSCSI-подключение.
  • Во-вторых, даже если вы решите создать в Proxmox неавторизованное подключение с тем, чтобы указать авторизационную информацию вручную, то вам придется бодаться с системой за возможность изменить конфигурационные файлы таргетов, так как при неудачной попытке подключения к iSCSI-хосту Proxmox перезаписывает информацию о таргетах и производит повторную попытку подключения.


Проще подключиться вручную:

root@srv01-vmx:~# iscsiadm -m discovery -t st -p 10.11.12.13
root@srv01-vmx:~# iscsiadm -m node --targetname "iqn.2012-10.local.alawar.ala-nas-01:pve-cluster-01" --portal "10.11.12.13:3260" --op=update --name node.session.auth.authmethod --value=CHAP
root@srv01-vmx:~# iscsiadm -m node --targetname "iqn.2012-10.local.alawar.ala-nas-01:pve-cluster-01" --portal "10.11.12.13:3260" --op=update --name node.session.auth.username --value=Admin
root@srv01-vmx:~# iscsiadm -m node --targetname "iqn.2012-10.local.alawar.ala-nas-01:pve-cluster-01" --portal "10.11.12.13:3260" --op=update --name node.session.auth.password --value=Lu4Ii2Ai

Эти команды надо выполнить для всех порталов, предоставляющих нужный нам таргет на всех нодах кластера.

Монтирование на новой ноде GFS2-FS

Для того, чтобы на новой ноде смонтировать GFS2-файловую систему, ей (файловой системе) необходимо добавить еще один журнал. Делается это следующим образом: на любой ноде кластера, на которой смонтирована нужная нам FS, выполняется команда:

root@pve01:~# gfs2_jadd -j 1 /mnt/cluster/storage01

Параметр "-j" указывает количество журналов, которое необходимо добавить к FS.

Эта команда может завершиться с ошибкой:

create: Disk quota exceeded

Причины возникновения ошибки:

Внутри GFS2-тома находится на самом деле не одна файловая система, а две. Еще одна файловая система предназначена для служебных целей. При желании ее можно смонтировать, добавив опцию "-o meta". Изменения внутри этой FS потенциально могут привести к разрушению файловой системы с данными. При добавлении журнала к FS происходит монтирование meta-файловой системы в каталог "/tmp/TEMP_RANDOM_DIR", после чего в ней создается файл журнала. По непонятным пока нам причинам, ядро иногда считает, что в примонтированной meta-FS превышена квота на создание объектов, из-за чего такая ошибка и возникает. Выйти из положения можно, перемонтировав GFS2 с данными (разумеется, для этого необходимо остановить все виртуалки, расположенные на этой FS), и еще раз выполнить команду добавления журнала. Также необходимо отмонтировать meta-FS, оставшуюся от прошлой неудачной попытки добавления журнала:

cat /proc/mounts | grep /tmp/ | grep -i gfs2 | awk '{print $2}' | xargs umount

Монтирование источника данных внутрь контейнера

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

При старте контейнера vzctl пытается выполнить следующий набор скриптов (при их наличии):

  • /etc/pve/openvz/vps.premount
  • /etc/pve/openvz/CTID.premount
  • /etc/pve/openvz/vps.mount
  • /etc/pve/openvz/CTID.mount
  • /etc/pve/openvz/CTID.start

При остановке выполняются следующие скрипты:

  • /etc/pve/openvz/CTID.stop
  • /etc/pve/openvz/CTID.umount
  • /etc/pve/openvz/vps.umount
  • /etc/pve/openvz/CTID.postumount
  • /etc/pve/openvz/CTID.postumount

, где "CTID" — это номер контейнера. Скрипты "vps.*" выполняются при операциях с любым контейнером. Скрипты "*.start" и "*.stop" выполняются в контексте контейнера, все остальные — в контексте хоста. Таким образом, мы можем заскриптовать процесс запуска / остановки контейнера, добавив в него монтирование данных. Вот несколько примеров:

Монтирование каталога с данными внутрь контейнера

Если контейнер работает с большим объемом данных, мы стараемся эти данные не держать внутри контейнера, а монтировать их с хоста. В таком подходе есть два положительных момента:

  1. Контейнер маленький, быстро бэкапится средствами Proxmox. Мы имеем возможность в любой момент быстро восстановить / клонировать функционал контейнера.
  2. Данные контейнера можно централизованно бэкапить хорошей системой бэкапа со всеми удобствами, предоставляемыми ею (разноуровневые бэкапы, ротация, статистика и так далее).

Содержимое файла "CTID.mount":

#!/bin/bash
. /etc/vz/vz.conf        # подключаем файл с глобальным описанием внутренних переменных OpenVZ. В частности, в нем определена переменная ${VE_ROOT} - корневой каталог контейнера на хосте.
. ${VE_CONFFILE}         # подключаем файл с описанием переменных контейнера

DIR_SRC=/storage/src_dir # каталог на хосте, который надо примонтировать внутрь контейнера
DIR_DST=/data            # каталог внутри контейнера, к которому будет примонтирован $DIR_SRC

mkdir -p ${VE_ROOT}/${DIR_DST} # создаем внутри контейнера каталог назначения
mount -n -t simfs ${DIR_SRC} ${VE_ROOT}/{$DIR_DST} -o /data  # монтируем каталог внутрь контейнера

Монтирование файловой системы внутрь контейнера

На хосте есть том, который надо отдать контейнеру. Содержимое файла "CTID.mount":

#!/bin/bash
. /etc/vz/vz.conf
. ${VE_CONFFILE}

UUID_SRC=3d1d8ec1-afa6-455f-8a27-5465c454e212 # UUID тома, который надо примонтировать внутрь контейнера
DIR_DST=/data

mkdir -p ${VE_ROOT}/${DIR_DST}
mount -n -U ${FS_BY_UUID} ${VE_ROOT}/{$DIR_DST}

Монтирование файловой системы, находящейся в файле, внутрь контейнера

Зачем такое может понадобиться? Если какой-нибудь хитрый продукт (например, Splunk) ни в какую не хочет работать с simfs, либо нас не устраивает скорость работы GFS2 при определенных условиях. Например, у нас есть какой-нибудь кэш на куче мелких файлов. GFS2 не очень быстро работает с большими объемами маленьких файлов. Тогда можно на хосте создать файловую систему, отличную от GFS2 (ext3), и подключить ее к контейнеру.

Монтируем loop-устройство из файла в контейнер:

Сначала создаем файл:

root@srv01:~# truncate -s 10G CTID_ext3.fs

Форматируем FS в файле:

root@srv01:~# mkfs.ext3 CTID_ext3.fs
mke2fs 1.42 (29-Nov-2011)
CTID_ext3.fs is not a block special device.
Proceed anyway? (y,n) y
...

Содержимое файла "CTID.mount":

#!/bin/bash
. /etc/vz/vz.conf
. ${VE_CONFFILE}

CFILE_SRC=/storage/CTID_ext3.fs # путь к файлу, который надо примонтировать внутрь контейнера
DIR_DST=/data

mkdir -p ${VE_ROOT}/${DIR_DST}
mount -n ${CFILE_SRC} -t ext3 ${VE_ROOT}/{$DIR_DST} -o loop

Отмонтирование внешних данных в контейнере при остановке

При остановке контейнера система пытается автоматически отмонтировать все подключенные к нему файловые системы. Но в особо экзотических конфигурациях у нее этого сделать не получается. Поэтому на всякий случай пример простого скрипта "CTID.umount":

#!/bin/bash
. /etc/vz/vz.conf
. ${VE_CONFFILE}

DIR=/data

if mountpoint -q "${VE_ROOT}${DIR}" ; then
        umount ${VE_ROOT}${DIR}
fi

Работа в кластере с не-кластерной файловой системой

Если по каким-то причинам нет желания использовать кластерную FS (не устраивает стабильность работы, не устраивает быстродействие и пр.), но хочется работать с единым хранилищем, то такой вариант возможен. Для этого нам понадобятся:

  • Отдельный логический том в CLVM для каждой ноды кластера
  • Основное хранилище для штатной работы контейнеров
  • Пустое резервное хранилище для срочного монтирования тома чужой ноды в случае ее краха / отключения

Порядок действий:

Каждой ноде кластера выделяем свой логический том в CLVM, форматируем его.

Создаем основное хранилище. Создаем каталог, имеющий одинаковое название на всех нодах кластера (например, "/storage"). Монтируем в него наш логический том. Создаем в админке Proxmox хранилище типа "Directory", называем его, например, "STORAGE", говорим, что оно не является общим.

Создаем резервное хранилище. Создаем каталог, имеющий одинаковое название на всех нодах кластера (например, "/storage2"). Создаем в админке Proxmox хранилище типа "Directory", называем его, например, "STORAGE2", говорим, что оно не является общим. В случае падения / отключения одной из нод, ее том будем монтировать в каталог "/storage2" на той ноде кластера, которая возьмет на себя нагрузку усопшей.

Что мы имеем в итоге:

  • Миграция (в том числе онлайн) контейнеров между нодами (если к контейнеру не подмонтировано никаких данных сбоку). Контейнер переносится с ноды на ноду копированием, соответственно, время миграции зависит от объема данных в контейнере. Чем больше данных, тем дольше будет переноситься контейнер между нодами. Не забываем про возрастающую дисковую нагрузку при этом.
  • (Недо-)отказоустойчивость. При падении ноды ее данные можно смонтировать на соседней ноде, и теоретически с ними можно начинать работать.

Почему "недо-", и почему "теоретически":

Виртуальные машины живут в хранилище "Storage", которое расположено в каталоге "/storage". Диск с умершей ноды у нас будет подмонтирован в каталог "/storage2", где Proxmox будет видеть контейнеры, но не сможет их оттуда запускать. Для того, чтобы поднять находящиеся в этом хранилище виртуалки, надо сделать три действия:

  1. Сообщить контейнерам-погорельцам о том, что их новый дом — не каталог "/storage", а каталог "/storage2". Для этого надо в каждом файле "*.conf" в каталоге "/etc/pve/nodes/имя_мертвой_ноды/openvz" изменить содержимое переменной VE_PRIVATE с "/storage/private/CTID" на "/storage2/private/CTID".
  2. Сообщить кластеру, что виртуалки вон той неживой ноды расположены теперь на этой, живой. Для этого достаточно всего лишь перенести все файлы из каталога "/etc/pve/nodes/имя_мертвой_ноды/openvz" в каталог "/etc/pve/nodes/имя_живой_ноды/openvz". Возможно, для этого существует какая-то правильная API-инструкция, но мы этим не заморачивались :)
  3. Сбросить квоту для каждого контейнера-погорельца:
    vzquota drop CTID
    

Все. Можно запускать контейнеры.

Если контейнеры с мертвой ноды занимают немного места, либо у нас невероятно шустрые диски, либо просто мы можем позволить себе подождать, то можно избежать выполнения этих трех шагов, просто перенеся нужные нам контейнеры из "/storage2/private" в "/storage/private".

Если кластер развалился

Кластер — существо капризное, и бывают случаи, что он встает в позу. Например, после массовых проблем с сетью, либо вследствие массового отключения питания. Поза выражается в том, что при обращении к кластерному хранилищу текущая сессия блокируется, опрос состояния fence-домена выводит тревожные сообщения, вида "wait state messages", а в dmesg сыпятся ошибки подключения.

Если никакие попытки оживить кластер не приводят к успеху, то самое простое — отключить на всех нодах кластера автоматический вход в fence-домен (файл "/etc/default/redhat-cluster-pve"), и последовательно перезагрузить все ноды. Надо быть готовым к тому, что ноды не смогут перезагрузиться самостоятельно. Когда все ноды будут перезагружены, вручную подключаемся к fence-домену, стартуем CLVM, и так далее. В предыдущих статьях написано, как это сделать.

На этом, пожалуй, все.

В следующей части я расскажу о том, как мы автоматизируем работу в кластере.

Спасибо за внимание!

Автор: winduzoid

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js