- PVSM.RU - https://www.pvsm.ru -

Мы уже рассказывали [1], как/почему нам нравится Rook: в заметной мере он упрощает работу с хранилищами в кластерах Kubernetes. Однако с этой простотой приходят и определённые сложности. Надеемся, новый материал поможет лучше разбираться в таких сложностях ещё до того, как они себя проявят.
А чтобы читать было интереснее, начнём с последствий гипотетической проблемы в кластере.
Представьте себе, что вы однажды настроили и запустили в своем K8s-кластере Rook, он радовал своей работой, однако в какой-то «прекрасный» момент происходит следующее:
lsblk и df не отрабатывают на узлах Kubernetes. Это автоматически означает: «что-то не так» с примонтированными на узлы RBD-образами. Не получается их прочитать, что указывает на недоступность мониторов…
Когда был запущен pod rook-ceph-operator? Не так давно, как его деплоили. Почему? Rook-operator решил сделать новый кластер… Как же нам теперь восстановить работу кластера и данные в нём?
Для начала пойдем более длинным интересным путем, проведя вдумчивое расследование по «внутренностям» Rook и пошаговое восстановление его компонентов. Конечно, есть и более короткий правильный путь: использование бэкапов. Как известно, админы делятся на два типа: на тех, кто не делает бэкапы, и тех, кто их уже делает… Но об этом — после расследования.
Итак, посмотрим на список ConfigMap’ов: там есть необходимые для резервирования rook-ceph-config и rook-config-override. Они появляются при успешном деплое кластера.
NB: В новых версиях, после принятия этого PR [2], 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)
Посмотрим, что в секрете rook-ceph-mons-keyring:
kind: Secret
data:
keyring: LongBase64EncodedString=
Декодируем и получим обычный keyring с правами для админа и мониторов:
[mon.]
key = AQAhT19dlUz0LhBBINv5M5G4YyBswyU43RsLxA==
caps mon = "allow *"
[client.admin]
key = AQAhT19d9MMEMRGG+wxIwDqWO1aZiZGcGlSMKp==
caps mds = "allow *"
caps mon = "allow *"
caps osd = "allow *"
caps mgr = "allow *"
Запомним. А теперь посмотрим на keyring в секрете rook-ceph-admin-keyring:
kind: Secret
data:
keyring: anotherBase64EncodedString=
Что в нём?
[client.admin]
key = AQAhT19d9MMEMRGG+wxIwDqWO1aZiZGcGlSMKp==
caps mds = "allow *"
caps mon = "allow *"
caps osd = "allow *"
caps mgr = "allow *"
Тот же. Посмотрим ещё… Вот, например, секрет rook-ceph-mgr-a-keyring:
[mgr.a]
key = AQBZR19dbVeaIhBBXFYyxGyusGf8x1bNQunuew==
caps mon = "allow *"
caps mds = "allow *"
caps osd = "allow *"
В конечном итоге мы находим ещё несколько секретов в ConfigMap’е rook-ceph-mon:
kind: Secret
data:
admin-secret: AQAhT19d9MMEMRGG+wxIwDqWO1aZiZGcGlSMKp==
cluster-name: a3ViZS1yb29r
fsid: ZmZiYjliZDMtODRkOS00ZDk1LTczNTItYWY4MzZhOGJkNDJhCg==
mon-secret: AQAhT19dlUz0LhBBINv5M5G4YyBswyU43RsLxA==
И это изначальный список с keyring’ами, откуда берутся все описанные выше секреты.
Как известно (см. dataDirHostPath в документации [3]), Rook хранит такие данные в двух местах. Поэтому давайте сходим на узлы, чтобы посмотреть на keyring’и, лежащие в каталогах, что примонтированы в pod’ы с мониторами и OSD. Для этого найдём на узлах /var/lib/rook/mon-a/data/keyring и увидим:
# cat /var/lib/rook/mon-a/data/keyring
[mon.]
key = AXAbS19d8NNUXOBB+XyYwXqXI1asIzGcGlzMGg==
caps mon = "allow *"
Внезапно тут секрет оказался другим — не как в ConfigMap’ах.
А что насчет админского keyring’а? Он тоже у нас есть:
# cat /var/lib/rook/kube-rook/client.admin.keyring
[client.admin]
key = AXAbR19d8GGSMUBN+FyYwEqGI1aZizGcJlHMLgx=
caps mds = "allow *"
caps mon = "allow *"
caps osd = "allow *"
caps mgr = "allow *"
Вот тут и проблема. Произошел некий сбой: кластер пересоздался… но в действительности нет.
Становится понятно, что в секретах хранятся заново сгенерированные keyring’и, и они не от нашего старого кластера. Поэтому:
/var/lib/rook/mon-a/data/keyring (либо из бекапа);rook-ceph-mons-keyring;rook-ceph-mon;Чудо не заставит себя долго ждать: мониторы появятся и запустятся. Ура, начало положено!
Заходим в 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. Посмотрим в них:
kind: ConfigMap
data:
osd-dirs: '{"/mnt/osd1":16,"/mnt/osd2":18}'
Всё не так, всё перепутано!
Отскейлим в нуль 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 [4].)
Шаг за шагом проверяем все узлы и правим ConfigMap’ы. После всех указаний можно запустить pod Rook-оператора и прочитать его логи. А в них всё замечательно:
Снова зайдем в pod оператора Rook и проверим живость кластера… да, мы немного ошиблись с выводами про имена OSD на некоторых узлах! Не беда: снова поправили ConfigMap’ы, удалили лишние каталоги от новых OSD и пришли к долгожданному состоянию HEALTH_OK!
Проверим образы в пуле:
# rbd ls -p kube
pvc-9cfa2a98-b878-437e-8d57-acb26c7118fb
pvc-9fcc4308-0343-434c-a65f-9fd181ab103e
pvc-a6466fea-bded-4ac7-8935-7c347cff0d43
pvc-b284d098-f0fc-420c-8ef1-7d60e330af67
pvc-b6d02124-143d-4ce3-810f-3326cfa180ae
pvc-c0800871-0749-40ab-8545-b900b83eeee9
pvc-c274dbe9-1566-4a33-bada-aabeb4c76c32
…
Всё на месте — кластер спасён!
Если бэкапы для Rook делались, то процедура восстановления становится значительно проще и сводится к следующей:
/var/lib/rook/mon-* на узлах;CephCluster, CephFilesystem, CephBlockPool, CephNFS, CephObjectStore;Делайте бэкапы!
А чтобы избегать ситуаций, когда понадобится восстановление из них:
ROOK_MON_HEALTHCHECK_INTERVAL и ROOK_MON_OUT_TIMEOUT. Нет смысла спорить, что Rook, будучи дополнительной «прослойкой» (в общей схеме организации хранилищ в Kubernetes), как многое упрощает, так и добавляет и новые сложности и потенциальные проблемы в инфраструктуре. Дело остаётся за «малым»: сделать взвешенный, обоснованный выбор между этими рисками с одной стороны и той пользой, которую решение приносит в вашем конкретном случае, — с другой.
Кстати, недавно в документацию Rook был добавлен [7] раздел «Adopt an existing Rook Ceph cluster into a new Kubernetes cluster». В нём более подробно расписано, что нужно делать, чтобы переехать имеющимися данными в новый кластер Kubernetes или же восстановить работу кластера, развалившегося по той или иной причине.
Читайте также в нашем блоге:
Автор: broken-ufa
Источник [11]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/sistemnoe-administrirovanie/338644
Ссылки в тексте:
[1] уже рассказывали: https://habr.com/ru/company/flant/blog/451818/
[2] этого PR: https://github.com/rook/rook/pull/3573
[3] документации: https://rook.github.io/docs/rook/master/ceph-cluster-crd.html#cluster-settings
[4] directory based osd: https://github.com/rook/rook/issues/3379
[5] добавляйте nodeAffinity: https://github.com/rook/rook/blob/master/Documentation/ceph-cluster-crd.md#placement-configuration-settings
[6] настройке таймаутов: https://github.com/rook/rook/blob/master/design/ceph/mon-health.md
[7] был добавлен: https://github.com/rook/rook/commit/b651239d3f9a793c95b5c06668b7f28771254082#diff-8c0c983d538cce2b49678395777c3cb9
[8] Rook — „самообслуживаемое“ хранилище данных для Kubernetes: https://habr.com/ru/company/flant/blog/348044/
[9] Longhorn, распределённое хранилище для K8s от Rancher, передано в CNCF: https://habr.com/ru/company/flant/blog/474208/
[10] Создаём постоянное хранилище с provisioning в Kubernetes на базе Ceph: https://habr.com/ru/company/flant/blog/329666/
[11] Источник: https://habr.com/ru/post/477680/?utm_source=habrahabr&utm_medium=rss&utm_campaign=477680
Нажмите здесь для печати.