[size=200]Автоматический mount GlusterFS после перезагрузки[/size]
[size=150]
Проблема[/size]
Есть кластер из трёх Docker Swarm-нод:
Docker-HUB — 10.110.10.46
Docker-HUB-2 — 10.110.10.47
Docker-HUB-3 — 10.110.10.48
GlusterFS volume:
docker-data
Тип volume:
Replicate
Три brick:
10.110.10.46:/gluster/data
10.110.10.47:/gluster/data
10.110.10.48:/gluster/data
Общий mount:
/mnt/gluster-storage
В
/etc/fstab:
localhost:/docker-data /mnt/gluster-storage glusterfs defaults,_netdev,backupvolfile-server=10.110.10.47:10.110.10.48,log-level=WARNING 0 0
После одновременной перезагрузки всех трёх нод (например, после отключения питания) GlusterFS мог не успеть полностью поднять brick-процессы к моменту запуска mount.
В результате:
Mount failed
В логе появлялось:
Client-quorum is not met
All subvolumes are down. Going offline until at least one of them comes back up.
При этом сам GlusterFS через некоторое время полностью запускался, и обычная команда:
mount -a
сразу успешно монтировала volume.
Причина: проблема была не в самом GlusterFS и не в /etc/fstab, а в порядке запуска сервисов после загрузки системы.
[size=150]
Решение[/size]
Создаём отдельный systemd service, который ждёт готовности GlusterFS volume
docker-data.
После этого mount зависит от этого service.
Итоговый порядок запуска:
network
↓
glusterd
↓
gluster-storage-ready.service
↓
mnt-gluster-storage.mount
↓
Docker
[size=150]
1. Проверяем GlusterFS[/size]
Проверяем volume:
gluster volume info docker-data
Проверяем состояние brick:
gluster volume status docker-data
В рабочем состоянии:
Brick 10.110.10.46:/gluster/data ... Y
Brick 10.110.10.47:/gluster/data ... Y
Brick 10.110.10.48:/gluster/data ... Y
Y в колонке Online означает, что brick доступен.
[size=150]
2. Создаём systemd service[/size]
На каждой Docker Swarm-ноде:
vi /etc/systemd/system/gluster-storage-ready.service
Содержимое файла:
[Unit]
Description=Wait for GlusterFS docker-data volume
Requires=glusterd.service
After=glusterd.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/sh -c 'until gluster volume status docker-data 2>/dev/null | grep -qE "Brick .* [0-9]+ +0 +Y"; do sleep 2; done'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Что здесь происходит:Requires=glusterd.service
Требует запущенный glusterd.
After=glusterd.service
Говорит systemd сначала запустить glusterd.
Проверка:
gluster volume status docker-data
повторяется каждые 2 секунды до тех пор, пока не будет найден работающий brick.
После готовности volume service завершается успешно:
Active: active (exited)
status=0/SUCCESS
Это нормальное поведение для
Type=oneshot.
[size=150]
3. Включаем service[/size]
После создания файла:
systemctl daemon-reload
systemctl enable gluster-storage-ready.service
Проверяем:
systemctl is-enabled gluster-storage-ready.service
Ожидаемый результат:
enabled
Запускаем:
systemctl start gluster-storage-ready.service
Проверяем:
systemctl status gluster-storage-ready.service --no-pager
При работающем Gluster:
Active: active (exited)
и:
status=0/SUCCESS
[size=150]
4. Добавляем зависимость mount от GlusterFS[/size]
Так как unit
mnt-gluster-storage.mount генерируется systemd из /etc/fstab, сам unit редактировать не нужно.
Создаём drop-in:
mkdir -p /etc/systemd/system/mnt-gluster\x2dstorage.mount.d
Создаём файл:
vi /etc/systemd/system/mnt-gluster\x2dstorage.mount.d/gluster.conf
Содержимое:
[Unit]
Requires=gluster-storage-ready.service
After=gluster-storage-ready.service
[size=150]
5. Перечитываем конфигурацию systemd[/size]
systemctl daemon-reload
Проверяем:
systemctl cat mnt-gluster\x2dstorage.mount
В конце должно присутствовать:
# /etc/systemd/system/mnt-gluster\x2dstorage.mount.d/gluster.conf
[Unit]
Requires=gluster-storage-ready.service
After=gluster-storage-ready.service
Проверяем зависимости:
systemctl show mnt-gluster\x2dstorage.mount -p Requires -p After
В выводе должен присутствовать:
gluster-storage-ready.service
[size=150]
6. Проверяем mount вручную[/size]
Проверяем, смонтирован ли volume:
mountpoint -q /mnt/gluster-storage && echo "MOUNTED" || echo "NOT MOUNTED"
Если:
NOT MOUNTED
запускаем:
systemctl start mnt-gluster\x2dstorage.mount
Проверяем:
systemctl status mnt-gluster\x2dstorage.mount --no-pager
Ожидаем:
Active: active (mounted)
И:
ls /mnt/gluster-storage/
должен показать содержимое общего GlusterFS-хранилища.
[size=150]
7. Проверяем порядок запуска[/size]
Для mount:
systemctl show mnt-gluster\x2dstorage.mount
-p Requires
-p After
Должен присутствовать:
gluster-storage-ready.service
Для service:
systemctl show gluster-storage-ready.service
-p Before
-p After
Должен присутствовать:
glusterd.service
Таким образом получается:
glusterd.service
↓
gluster-storage-ready.service
↓
mnt-gluster-storage.mount
[size=150]
8. Настройка на всех трёх нодах[/size]
Одинаковая конфигурация должна находиться на:
Docker-HUB
Docker-HUB-2
Docker-HUB-3
На каждой ноде:
/etc/systemd/system/gluster-storage-ready.service
/etc/systemd/system/mnt-gluster\x2dstorage.mount.d/gluster.conf
В
/etc/fstab остаётся:
localhost:/docker-data /mnt/gluster-storage glusterfs defaults,_netdev,backupvolfile-server=10.110.10.47:10.110.10.48,log-level=WARNING 0 0
[size=150]
9. Проверка после перезагрузки[/size]
После перезагрузки проверяем:
mountpoint /mnt/gluster-storage
Ожидаем:
/mnt/gluster-storage is a mountpoint
Проверяем содержимое:
ls /mnt/gluster-storage/
Проверяем GlusterFS:
gluster volume status docker-data
Все три brick должны иметь:
Online Y
Проверяем service:
systemctl status gluster-storage-ready.service --no-pager
Ожидаем:
Active: active (exited)
Проверяем mount:
systemctl status mnt-gluster\x2dstorage.mount --no-pager
Ожидаем:
Active: active (mounted)
[size=150]
10. Почему это работает[/size]
Раньше при холодной загрузке мог происходить такой порядок:
boot
↓
glusterd запускается
↓
mount пытается подключиться
↓
Gluster bricks ещё не готовы
↓
mount падает
↓
Gluster через несколько секунд полностью готов
↓
mount автоматически не повторяется
После добавления зависимости:
boot
↓
glusterd запускается
↓
gluster-storage-ready.service
↓
ждёт готовности docker-data
↓
brick становится Online
↓
service завершается успешно
↓
mnt-gluster-storage.mount
↓
GlusterFS подключён
[size=150]
Итог[/size]
После настройки всех трёх нод была выполнена одновременная перезагрузка.
После загрузки:
ls /mnt/gluster-storage/
сразу показал содержимое общего хранилища.
Ручной:
mount -a
больше не потребовался.
Таким образом, при одновременной перезагрузке всех трёх Docker Swarm-нод systemd сначала дожидается готовности GlusterFS volume
docker-data, и только после этого выполняет mount общего хранилища.
Важно: настраивать нужно одинаково на всех трёх нодах. Отдельная зависимость от glusterd в
docker.service для этой схемы не требуется — Docker уже стартует после готового mount, если соответствующая зависимость настроена в системе.