company_banner

Наши руки не для скуки: восстановление кластера 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)

    Посмотрим, что в секрете 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 в документации), 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’и, и они не от нашего старого кластера. Поэтому:

    • берём 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. Посмотрим в них:

    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.)

    Шаг за шагом проверяем все узлы и правим ConfigMap’ы. После всех указаний можно запустить pod Rook-оператора и прочитать его логи. А в них всё замечательно:

    • я оператор кластера;
    • я нашел диски на узлах;
    • я нашел мониторы;
    • мониторы подружились, т.е. образовали кворум;
    • запускаю деплойменты OSD…

    Снова зайдем в 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 делались, то процедура восстановления становится значительно проще и сводится к следующей:

    1. Масштабируем в нуль deployment Rook-оператора;
    2. Удаляем все деплойменты, кроме Rook-оператора;
    3. Восстанавливаем из бэкапа все secret’ы и ConfigMap’ы;
    4. Восстанавливаем содержимое директорий /var/lib/rook/mon-* на узлах;
    5. Восстанавливаем (если вдруг потеряли) CRD CephCluster, CephFilesystem, CephBlockPool, CephNFS, CephObjectStore;
    6. Обратно масштабируем deployment Rook-оператора в 1.

    Полезные советы


    Делайте бэкапы!

    А чтобы избегать ситуаций, когда понадобится восстановление из них:

    1. Перед масштабными работами с кластером, заключающимися в перезагрузках серверов, масштабируйте в нуль Rook-оператора, чтобы он не делал лишнего.
    2. На мониторы заранее добавляйте nodeAffinity.
    3. Уделите внимание предварительной настройке таймаутов ROOK_MON_HEALTHCHECK_INTERVAL и ROOK_MON_OUT_TIMEOUT.

    Вместо заключения


    Нет смысла спорить, что Rook, будучи дополнительной «прослойкой» (в общей схеме организации хранилищ в Kubernetes), как многое упрощает, так и добавляет и новые сложности и потенциальные проблемы в инфраструктуре. Дело остаётся за «малым»: сделать взвешенный, обоснованный выбор между этими рисками с одной стороны и той пользой, которую решение приносит в вашем конкретном случае, — с другой.

    Кстати, недавно в документацию Rook был добавлен раздел «Adopt an existing Rook Ceph cluster into a new Kubernetes cluster». В нём более подробно расписано, что нужно делать, чтобы переехать имеющимися данными в новый кластер Kubernetes или же восстановить работу кластера, развалившегося по той или иной причине.

    P.S.


    Читайте также в нашем блоге:

    Флант
    DevOps-as-a-Service, Kubernetes, обслуживание 24×7

    Comments 23

      0

      А почему оператор один? Как я понимаю, rook-operator это мастер для ceph, и по идее их тоже надо три для кворума.

        +1
        Нет, что за мастер для ceph? Суть оператора это управлять сущностями в виде mon,osd,csi плагинами и discovery
          –2
          rook-operator — это сущность для кубера, которая провижинит вам ceph кластер в нем, а у цефв, то что вы назвали мастерами, является mon, да их должно быть нечетное количество для кворума
            +1
            да их должно быть нечетное количество для кворума

            позвольте поинтересоваться — Вы это откуда взяли?
            В доке про обязательное нечетное количество ничего не написано. Можно и 2, и 4, и 6 мониторов...


            Ceph monitors are light-weight processes that maintain a master copy of the cluster map. You can run a cluster with 1 monitor. We recommend at least 3 monitors for a production cluster. Ceph monitors use a variation of the Paxos protocol to establish consensus about maps and other critical information across the cluster. Due to the nature of Paxos, Ceph requires a majority of monitors running to establish a quorum (thus establishing consensus).
            It is advisable to run an odd-number of monitors but not mandatory. An odd-number of monitors has a higher resiliency to failures than an even-number of monitors. For instance, on a 2 monitor deployment, no failures can be tolerated in order to maintain a quorum; with 3 monitors, one failure can be tolerated; in a 4 monitor deployment, one failure can be tolerated; with 5 monitors, two failures can be tolerated. This is why an odd-number is advisable. Summarizing, Ceph needs a majority of monitors to be running (and able to communicate with each other), but that majority can be achieved using a single monitor, or 2 out of 2 monitors, 2 out of 3, 3 out of 4, etc.

            Т.е. попросту в четном количестве смысла нет, т.к. можно добавить +1 мон и получить устойчивость к отказу еще одного.

              0
              В документации для более старых версий (0.8 0.9 версий) они писали про нечетное колличество mon как рекомендация.
          +3

          Похоже на героические попытки нажить себе проблем, а потом так же георически их решать. Ну, молодцы, что починили и поделились опытом. Пускай все знают насколько это тонкая материя.
          С другой стороны — это прекрасная иллюстрация того, что Rook ПРЕКРАСНО ЗАХОДИТ в тестовые среды. Вообще отлично. При этом умолчим о критерии идентичности прода и стейджа. А вот в продакшен среды… Как-то опасливо такое ставить. Тем более, что все эти новомодные операторы явно, что пишут не сеньоры и не покрывают все ситуации тестами.

            +2
            Во, как раз скоро будет у нас другая статья про один такой оператор (печальные последствия его использования) ;-)
              +2

              Ждем статей:


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

              Я верю в вас — вы можете )))

                0

                +1 вопрос:
                как считаете — чем хуже отдельный кластер цеф с выделенными нодами? Т.к. типичная ошибка проектантов — в случае с руком — нет выделенной сетки под сторедж, в результате весь трафик летит на общих основаниях. А если цеф-рук на мастерах, то при большой нагрузке смешно (на самом деле — нет) начинают моргать etcd.

                  0
                  Что есть моргать? из-за загруженности сети? или из-за исчерпания ресурсов нод?
                    0

                    Из-за загруженности сети и сервера. Мастера и етсд переставали видеть друг друга, нарушалась синхронизация.

                      0
                      Если не сложно можно чуть больше информации о вашем кейсе? etcd в докере или systemd? есть ли резервация ресурсов для etcd и kubelet ресурсов, какая скорость сети? сколько нод в кластере? и в какой момент началось такое поведение, был какой то сбой или вывалились osd?
                        0

                        Вам для чего? Деталей не помню. Помню, что был кластер ранчера (задеплоили как было), в него закинули рук, несколько сетевух в бонде. Решили не рисковать в будущем.
                        Коллеги выше очень верно говорят, что рук добавляет сложности к обслуживанию, т.к. засунуть в него кастомные параметры надо еще умудрится. А цеф такая штука… которая на автопилоте не работает.

                          0
                          предстоит эксплуатация, вот собираю чужие грабли
                            0

                            ну, тогда лучше в профильном телеграм чатике спрашивать ) не думаю, что там аудитория меньше, чем тут. Речь про https://t.me/kubernetes_ru так-то

                    +2
                    Как показывает практика, *далеко не всегда необходимо* разделять cluster_network и public_network, да и даже не всегда для этого есть возможности.

                    Да, трафик синка osd и доступа к rbd-образам от клиентов летит по одной сети, но, как правило, это не приводит к каким-либо глобальным проблемам.

                    Стоит отметить, что в данном случае речь не идет об инсталляциях ceph на сотни и тысячи машин, как оно бывает в действительно крупных кластерах чистого ceph. Именно поэтому разделение сетей тут не принесет особого эффекта, но, при этом, значительно усложнит настройку, обслуживание и диагностику.
                      0
                      Именно поэтому разделение сетей тут не принесет особого эффекта, но, при этом, значительно усложнит настройку, обслуживание и диагностику.

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


                      Да, трафик синка osd и доступа к rbd-образам от клиентов летит по одной сети, но, как правило, это не приводит к каким-либо глобальным проблемам.

                      Ага. В частности, в кейсе, когда у Вас одновременно отказала одна нода ceph'а и параллельно активно деплоят в кластер большие образы (у нас разработчики-затейники и иногда попадаются образа по 100ГиБ — это все-таки bad practice, но кластер кубернетес точно не является дуракоустойчивой штукой и не вижу причин добавлять точек отказа).

                0
                Это реальный кейс? или конь в вакууме?
                  +1
                  Реальный случай, причем старались его воспроизвести, но не получилось, а это совсем грустно.
                  P.S. Версия была v1.0.4.
                    0
                    т.е получается rook-operator без перезапуска и прочего, решил задеплоить новый кластер?
                  +5
                  Все конечно хорошо, но описание причины того, что rook-operator решил задеплоить новый кластер, ибо это выходит как, лечение симптоматики до следующего такого редеплоя
                    0
                    Шикарное название. )
                      +1

                      Реально sysrq или пешком в ЦОД?
                      А reboot -f? Чем он отличается от sysrq в данном случае?

                      Only users with full accounts can post comments. Log in, please.