Наши руки не для скуки: восстановление кластера Rook в K8s
Мы уже рассказывали, как/почему нам нравится Rook: в заметной мере он упрощает работу с хранилищами в кластерах Kubernetes. Однако с этой простотой приходят и определённые сложности. Надеемся, новый материал поможет лучше разбираться в таких сложностях ещё до того, как они себя проявят.
А чтобы читать было интереснее, начнём с последствий гипотетической проблемы в кластере.
«Всё пропало!»
Представьте себе, что вы однажды настроили и запустили в своем K8s-кластере Rook, он радовал своей работой, однако в какой-то «прекрасный» момент происходит следующее:
Новые pod’ы не могут примонтировать RBD-образы из Ceph.
Команды вроде lsblk и df не отрабатывают на узлах Kubernetes. Это автоматически означает: «что-то не так» с примонтированными на узлы RBD-образами. Не получается их прочитать, что указывает на недоступность мониторов…
Да, в кластере нет рабочих мониторов. Более того — нет даже ни pod’ов с OSD, ни pod’а MGR.
Когда был запущен pod rook-ceph-operator? Не так давно, как его деплоили. Почему? Rook-operator решил сделать новый кластер… Как же нам теперь восстановить работу кластера и данные в нём?
Для начала пойдем более длинным интересным путем, проведя вдумчивое расследование по «внутренностям» Rook и пошаговое восстановление его компонентов. Конечно, есть и более короткий правильный путь: использование бэкапов. Как известно, админы делятся на два типа: на тех, кто не делает бэкапы, и тех, кто их уже делает… Но об этом — после расследования.
Немного практики, или Длинный путь
Осмотримся и восстановим мониторы
Итак, посмотрим на список ConfigMap’ов: там есть необходимые для резервирования rook-ceph-config и rook-config-override. Они появляются при успешном деплое кластера.
NB: В новых версиях, после принятия этого PR, ConfigMap’ы перестали быть показателем успешности деплоя кластера.
Для выполнения дальнейших действий нам необходим жёсткий ребут всех серверов, на которых присутствуют примонтированные RBD-образы (ls /dev/rbd*). Его надо произвести через sysrq (или «пешком» в ЦОД). Это требование вызвано задачей отсоединить примонтированные RBD, для чего штатный ребут не подойдет (будет безуспешно пытаться отмонтировать их нормально).
Театр начинается с вешалки, а Ceph-кластер — с мониторов. Посмотрим на них.
Rook монтирует в pod монитора вот такие сущности:
Volumes:
rook-ceph-config:
Type: ConfigMap (a volume populated by a ConfigMap)
Name: rook-ceph-config
rook-ceph-mons-keyring:
Type: Secret (a volume populated by a Secret)
SecretName: rook-ceph-mons-keyring
rook-ceph-log:
Type: HostPath (bare host directory volume)
Path: /var/lib/rook/kube-rook/log
ceph-daemon-data:
Type: HostPath (bare host directory volume)
Path: /var/lib/rook/mon-a/data
Mounts:
/etc/ceph from rook-ceph-config (ro)
/etc/ceph/keyring-store/ from rook-ceph-mons-keyring (ro)
/var/lib/ceph/mon/ceph-a from ceph-daemon-data (rw)
/var/log/ceph from rook-ceph-log (rw)
И это изначальный список с keyring’ами, откуда берутся все описанные выше секреты.
Как известно (см. dataDirHostPath в документации), Rook хранит такие данные в двух местах. Поэтому давайте сходим на узлы, чтобы посмотреть на keyring’и, лежащие в каталогах, что примонтированы в pod’ы с мониторами и OSD. Для этого найдём на узлах /var/lib/rook/mon-a/data/keyring и увидим:
Вот тут и проблема. Произошел некий сбой: кластер пересоздался… но в действительности нет.
Становится понятно, что в секретах хранятся заново сгенерированные keyring’и, и они не от нашего старого кластера. Поэтому:
берём keyring от монитора из файла /var/lib/rook/mon-a/data/keyring (либо из бекапа);
изменяем keyring в секрете rook-ceph-mons-keyring;
прописываем keyring от админа и монитора в ConfigMap’е rook-ceph-mon;
удаляем контроллеры pod’ов с мониторами.
Чудо не заставит себя долго ждать: мониторы появятся и запустятся. Ура, начало положено!
Восстановим OSD
Заходим в pod rook-operator: вызов ceph mon dump показывает, что все мониторы на месте, а ceph -s — на то, что они в кворуме. Однако, если посмотреть на дерево OSD (ceph osd tree), увидим в нём нечто странное: OSD’шки начали появляться, но они пусты. Получается, их тоже нужно как-то восстановить. Но как?
Тем временем, в ConfigMap’ах появились так нужные нам rook-ceph-config и rook-config-override, а также множество других ConfigMap’ов с именами вида rook-ceph-osd-$nodename-config. Посмотрим в них:
Отскейлим в нуль pod оператора, удалим сгенерированные Deployment’ы pod’ов с OSD и исправим эти ConfigMap’ы. Но откуда взять правильную карту OSD по узлам?
Попробуем снова покопаться в директориях /mnt/osd[1-2] на узлах — в надежде, что сможем там за что-то зацепиться.
В каталоге /mnt/osd1 есть 2 подкаталога: osd0 и osd16. Последний — это ведь как раз тот ID, что указан в ConfigMap (16)?
Проверим по размерам и увидим, что osd0 намного больше osd16.
Приходим к выводу, что osd0 — это и есть нужный OSD, что был указан как /mnt/osd1 в ConfigMap (ведь мы используем directory based osd.)
Шаг за шагом проверяем все узлы и правим ConfigMap’ы. После всех указаний можно запустить pod Rook-оператора и прочитать его логи. А в них всё замечательно:
я оператор кластера;
я нашел диски на узлах;
я нашел мониторы;
мониторы подружились, т.е. образовали кворум;
запускаю деплойменты OSD…
Снова зайдем в pod оператора Rook и проверим живость кластера… да, мы немного ошиблись с выводами про имена OSD на некоторых узлах! Не беда: снова поправили ConfigMap’ы, удалили лишние каталоги от новых OSD и пришли к долгожданному состоянию HEALTH_OK!
Уделите внимание предварительной настройке таймаутовROOK_MON_HEALTHCHECK_INTERVAL и ROOK_MON_OUT_TIMEOUT.
Вместо заключения
Нет смысла спорить, что Rook, будучи дополнительной «прослойкой» (в общей схеме организации хранилищ в Kubernetes), как многое упрощает, так и добавляет и новые сложности и потенциальные проблемы в инфраструктуре. Дело остаётся за «малым»: сделать взвешенный, обоснованный выбор между этими рисками с одной стороны и той пользой, которую решение приносит в вашем конкретном случае, — с другой.
Кстати, недавно в документацию Rook был добавлен раздел «Adopt an existing Rook Ceph cluster into a new Kubernetes cluster». В нём более подробно расписано, что нужно делать, чтобы переехать имеющимися данными в новый кластер Kubernetes или же восстановить работу кластера, развалившегося по той или иной причине.