Надежное хранилище с DRBD9 и Proxmox (Часть 1: NFS)

    image


    Наверное каждый, кто хоть раз озадачивался поиском высокопроизводительного software-defiined хранилища рано или поздно слышал про DRBD, а может даже и имел дело с ним.


    Правда на пике популярности Ceph и GlusterFS, которые работают в принципе неплохо, а главное сразу и из коробки, все просто немного подзабыли про него. Тем более что предыдущая версия не поддерживала репликацию более чем на два узла, и из-за чего часто встречались проблемы со split-brain, что явно не добавило ему популярности.


    Решение и правда не новое, но вполне конкурентоспособное. При относительно небольших затратах на CPU и RAM, DRBD предоставляет реально быструю и безопасную синхронизацию на уровне блочного устройства. За все это время LINBIT — разработчики DRBD не стоят на месте и постоянно дорабатывают его. Начиная с версии DRBD9 перестает быть просто сетевым зеркалом и становится чем-то бОльшим.


    Во первых, идея создания одного распределенного блочного устройства для нескольких серверов отошла на задний план, и теперь LINBIT старается предоставить инструменты оркестрации и управления множеством drbd-устройств в кластере, которые создаются поверх LVM и ZFS-разделов.


    Например DRBD9 поддерживает до 32 реплик, RDMA, diskless-ноды, а новые инструменты оркестрации позволяют использовать снапшоты, online-миграцию и много чего другого.


    Несмотря на то что DRBD9 имеет инструменты интеграции с Proxmox, Kubernetes, OpenStack и OpenNebula, на данный момент они находится в некотором переходном режиме, когда новые инструменты еще не везде поддерживаются, а старые уже очень скоро будут объявлены как deprecated. Речь идет о DRBDmanage и Linstor.


    Я воспользуюсь этим моментом что бы не сильно вдаваться в подробности каждого из них, но более подробно рассмотреть настройку и принципы работы с самим DRBD9. Вам все равно придется c этим разрбраться, хотя бы потому что отказоустойчивая настройка контроллера Linstor, подразумевает его установку на одно их таких устройств.


    В данной статье я бы хотел рассказать вам о DRBD9 и возможности его использования в Proxmox без сторонних плагинов.


    DRBDmanage и Linstor


    Во первых стоит еще раз упомянуть про DRBDmanage, который очень неплохо интегрируется в Proxmox. LINBIT предоставляет готовый плагин DRBDmanage для Proxmox который позволяет использовать все его функции прямо из интерфейса Proxmox.


    Выглядит это и правда потрясающе, но к сожалению имеет некоторые минусы.


    • Во первых захаркоженные названия томов, LVM-группа или ZFS-пул обязательно должен иметь название drbdpool.
    • Невозможность использования более одного пула на ноду
    • В силу специфики решения сontroller volume может находиться только на обычном LVM и никак иначе
    • Переодические глюки dbus, который тесно используется DRBDmanage для взаимодействия с нодами.

    В результате чего, LINBIT было принято решение заменить всю сложную логику DRBDmanage на простое приложение, которое связывается с нодами используя обычное tcp-соединение и работает безо всякой там магии. Так появился Linstor.


    Linstor и правда работает очень хорошо. К сожалению разработчики выбрали java как основной язык для написания Linstor-server, но пусть это не пугает вас, так как Linstor сам по себе занимается только распределением конфигов DRBD и нарезкой LVM/ZFS разделов на нодах.


    Оба решения бесплатны и распространяются под свободной лицензией GPL3

    Прочитать про каждое из них и о настройке вышеупомянутого плагина для Proxmox можно на официальной wiki Proxmox


    Отказоустойчивый NFS-сервер


    К сожалению на момент написания статьи Linstor имеет готовую интеграцию только с Kubernetes. Но в конце года ожидаются драйверы и для остальных систем Proxmox, OpenNebula, OpenStack.


    Но пока готового решения нет, а старое нам так или иначе не нравится. Попробуем использовать DRBD9 по старинке для организации NFS-доступа на общий раздел.


    Тем не менее данное решение так-же окажется не без плюсов, ведь NFS-сервер позволит вам организовать конкурентный доступ к файловой системе хранилища с нескольких серверов без необходимости использования сложных кластерных файловых систем с DLM, таких как OCFS и GFS2.


    При этом вы получите возможность переключать роли Primary/Secondary нод просто мигрируя контейнер с NFS-сервером в интерфейсе Proxmox.


    Вы так же сможете хранить любые файлы внутри этой файловой системы, так же как виртуальные диски и бэкапы.


    В случае если вы используете Kubernetes вы сможете организовать ReadWriteMany доступ для ваших PersistentVolumes.


    Proxmox и LXC-контейнеры


    Теперь вопрос: почему Proxmox?


    В принципе для построения подобной схемы мы могли бы использовать и Kubernetes так и обычную схему с кластер-менеджером. Но Proxmox предоставляет готовый, очень многофункциональный и в тоже время простой и интуитивно понятный интерфес практически для всего что нужно. Он из коробки умеет кластеризацию и поддерживает механизм fencing основанный на softdog. А при использовании LXC-контейнеров позволяет добиться минимальных таймаутов при переключении.
    Полученное решение не будет иметь единой точки отказа.


    По сути мы будем использовать Proxmox преимущественно как cluster-manager, где мы сможем рассматривать отдельный LXC-контейнер как сервис запущенный в классическом HA-кластере, лишь с тем отличием, что с контейнером в комплекте идет так же и его корневая система. То есть у вас нет необходимости устанавливать несколько экземаляров сервиса на каждом сервере отдельно, вы можете сделать это только один раз внутри контейнера.
    Если вы когда-нибудь работали с cluster-manager software и обеспечением HA для приложений вы поймете что я имею ввиду.


    Общая схема


    Наше решение будет напоминать стандартную схему репликации какой-нибудь базы данных.


    • У нас есть три ноды
    • На каждой ноде распределенное drbd-устройство.
    • На устройстве обычная файловая система (ext4)
    • Только один сервер может быть мастером
    • На мастере запущен NFS-сервер в LXC-контейнере.
    • Все ноды обращаются к устройству строго через NFS
    • При необходимости мастер может переехать на другую ноду, вместе с NFS-сервером

    DRBD9 имеет одну очень крутую функцию которая сильно все упрощает:
    drbd-устройство автоматически становиться Primary в тот момент когда оно монтируется на какой-нибудь ноде. В случае если устройство помечено как Primary, любая попытка смонтировать его на другой ноде приведет к ошибке доступа. Таким образом обеспечивается блокировка и гарантированная защита от одновременного доступа к устройству.


    Почему это все сильно упрощает? Потому что при запуске контейрнера Proxmox автоматически монтирует это устройство и оно становится Primary на этой ноде, а при остановке контейнера наоборот размонтирует и устройство становится опять Secondary.
    Таким образом нам больше не нужно беспокоиться о переключении Primary/Secondary устройств, Proxmox будет делать это автоматически, УРА!


    Настройка DRBD


    Ну хорошо, с идеей разобрались теперь перейдем к реализации.


    По умолчанию в комплекте с ядром Linux поставляется модуль восьмой версии drbd, к сожалению он нам не подходит и нам необходимо установить модуль девятой версии.


    Подключим репозиторий LINBIT и установим все необходимое:


    wget -O- https://packages.linbit.com/package-signing-pubkey.asc | apt-key add - 
    echo "deb http://packages.linbit.com/proxmox/ proxmox-5 drbd-9.0" \
      > /etc/apt/sources.list.d/linbit.list
    
    apt-get update && apt-get -y install pve-headers drbd-dkms drbd-utils drbdtop

    • pve-headers — заголовки ядра необходимые для сборки модуля
    • drbd-dkms — модуль ядра в формате DKMS
    • drbd-utils — основные утилиты для управления DRBD
    • drbdtop — интерактивный инструмент, как top только для DRBD

    После установки модуля проверим, все ли в порядке с ним:


    # modprobe drbd
    # cat /proc/drbd 
    version: 9.0.14-1 (api:2/proto:86-113)

    Если вы увидите в выводе команды восьмую версию значит что-то пошло не так и загружен in-tree модуль ядра. Проверьте dkms status что-бы разобраться в чем причина.


    Каждая нода у нас будет иметь одно и тоже drbd-устройство запущенное поверх обычных разделов. Для начала нам нужно подготовить этот раздел под drbd на каждой ноде.


    В качестве такого раздела может выступать любое блочное устройство, это может быть lvm, zvol, раздел диска или весь диск целиком. В этой статье я буду использовать отдельный nvme диск с разделом под drbd: /dev/nvme1n1p1


    Стоит заметить, что имена устройств имеют свойство иногда меняться, так что лучше сразу взять за привычку использовать постоянный симлинк на устройство.


    Найти такой симлинк для /dev/nvme1n1p1 можно таким образом:


    # find /dev/disk/ -lname '*/nvme1n1p1'
    /dev/disk/by-partuuid/847b9713-8c00-48a1-8dff-f84c328b9da2
    /dev/disk/by-path/pci-0000:0e:00.0-nvme-1-part1
    /dev/disk/by-id/nvme-eui.0000000001000000e4d25c33da9f4d01-part1
    /dev/disk/by-id/nvme-INTEL_SSDPEKKA010T7_BTPY703505FB1P0H-part1

    Опишем наш ресурс на всех трех нодах:


    # cat /etc/drbd.d/nfs1.res
    resource nfs1 {
      meta-disk internal;
      device    /dev/drbd100;
      protocol  C;
      net { 
        after-sb-0pri discard-zero-changes;
        after-sb-1pri discard-secondary;
        after-sb-2pri disconnect;
      }
      on pve1 {
        address   192.168.2.11:7000;
        disk      /dev/disk/by-partuuid/95e7eabb-436e-4585-94ea-961ceac936f7;
        node-id   0;
      }
      on pve2 {
        address   192.168.2.12:7000;
        disk      /dev/disk/by-partuuid/aa7490c0-fe1a-4b1f-ba3f-0ddee07dfee3;
        node-id   1;
      }
      on pve3 {
        address   192.168.2.13:7000;
        disk      /dev/disk/by-partuuid/847b9713-8c00-48a1-8dff-f84c328b9da2;
        node-id   2;
      }
      connection-mesh {
        hosts pve1 pve2 pve3;
      }
    }

    Желательно для синхронизации drbd использовать отдельную сеть.


    Теперь создадим метаданные для drbd и запустим его:


    # drbdadm create-md nfs1
    initializing activity log
    initializing bitmap (320 KB) to all zero
    Writing meta data...
    New drbd meta data block successfully created.
    success
    # drbdadm up nfs1

    Повторим эти действия на всех трех нодах и проверим состояние:


    # drbdadm status
    nfs1 role:Secondary
      disk:Inconsistent
      pve2 role:Secondary
        peer-disk:Inconsistent
      pve3 role:Secondary
        peer-disk:Inconsistent

    Сейчас наш диск Inconsistent на всех трех нодах, это потому, что drbd не знает какой диск должен быть взят в качестве оригинала. Мы должны пометить один из них как Primary, что бы его состояние синхронизировалось на остальные ноды:


    drbdadm primary --force nfs1
    drbdadm secondary nfs1

    Сразу после этого начнется синхронизация:


    # drbdadm status
    nfs1 role:Secondary
      disk:UpToDate
      pve2 role:Secondary
        replication:SyncSource peer-disk:Inconsistent done:26.66
      pve3 role:Secondary
        replication:SyncSource peer-disk:Inconsistent done:14.20
    

    Нам не обязательно дожидаться ее окончания и мы можем параллельно выполнять дальнейшие шаги. Их можно выполнять на любой ноде, вне зависимости от ее текущего состояния локального диска в DRBD. Все запросы будут автоматически перенаправлены на устройство с UpToDate состоянием.


    Стоит не забыть активировать автозапуск drbd-сервиса на нодах:


    systemctl enable drbd.service

    Настройка LXC-контейнера


    Опустим часть настройки кластера Proxmox из трех нод, эта часть хорошо описана в официальной wiki


    Как я говорил раньше наш NFS-сервер будет работать в LXC-контейнере. Сам контейнер мы будем держать на устройстве /dev/drbd100, которое мы только что создали.


    Сначала нам нужно создать файловую систему на нем:


    mkfs -t ext4 -O mmp -E mmp_update_interval=5 /dev/drbd100

    Proxmox по умолчанию включает multimount protection на уровне файловой системы, в принципе мы можем обойтись и без нее, т.к. DRBD по умолчанию имеет собственную защиту, он просто запретит второй Primary для устройства, но осторожность нам не повредит.


    Теперь скачаем шаблон Ubuntu:


    # wget http://download.proxmox.com/images/system/ubuntu-16.04-standard_16.04-1_amd64.tar.gz -P /var/lib/vz/template/cache/

    И создадим из него наш контейнер:


    pct create 101 local:vztmpl/ubuntu-16.04-standard_16.04-1_amd64.tar.gz \
      --hostname=nfs1 \
      --net0=name=eth0,bridge=vmbr0,gw=192.168.1.1,ip=192.168.1.11/24 \
      --rootfs=volume=/dev/drbd100,shared=1

    В данной команде мы указываем что корневая система нашего контейнера будет находиться на устройстве /dev/drbd100 и добавим параметр shared=1 что бы разрешить миграцию контейнера между нодами.


    Если что-то пошло не так, вы всегда можете поправить это через интерфейс Proxmox или в конфиге контейнера /etc/pve/lxc/101.conf


    Proxmox распакует шаблон и подготовит корневую систему контейнера для нас. После этого мы можем запустить наш контейнер:


    pct start 101

    Настройка NFS-сервера.


    По умолчанию Proxmox не разрешает запуск NFS-сервера в контейнере, но есть несколько способов разрешить это.


    Один из них просто добавить lxc.apparmor.profile: unconfined в конфиг нашего контейнера /etc/pve/lxc/100.conf.


    Или мы можем разрешить NFS для всех контейнеров на постоянной основе, для этого нужно обновить стандартный шаблон для LXC на всех нодах, добавьте в /etc/apparmor.d/lxc/lxc-default-cgns следующие строки:


      mount fstype=nfs,
      mount fstype=nfs4,
      mount fstype=nfsd,
      mount fstype=rpc_pipefs,

    После изменений перезапустите контейнер:


    pct shutdown 101
    pct start 101

    Теперь давайте залогинимся в него:


    pct exec 101 bash

    Установим обновления и NFS-сервер:


    apt-get update 
    apt-get -y upgrade
    apt-get -y install nfs-kernel-server

    Создадим экспорт:


    echo '/data *(rw,no_root_squash,no_subtree_check)' >> /etc/exports
    mkdir /data
    exportfs -a

    Настройка HA


    На момент написания статьи proxmox HA-manager имеет баг, который не позволяет HA-контейнеру успешно завершить свою работу, в результате чего, не до конца убитые kernel-space процессы nfs-сервера не дают drbd-устройству уйти в Secondary. В случае если вы уже столкнулись с такой ситуацией не стоит паниковать и просто выполните killall -9 nfsd на ноде, где был запущен контейнер и тогда drbd-устройство должно "отпустить" и оно перейдет в Secondary.


    Что бы этот баг поправить, выполните следующие команды на всех нодах:


    sed -i 's/forceStop => 1,/forceStop => 0,/' /usr/share/perl5/PVE/HA/Resources/PVECT.pm
    systemctl restart pve-ha-lrm.service

    Теперь мы можем перейти к кофигурации HA-manager. Создадим отдельную HA-группу для нашего устройства:


    ha-manager groupadd nfs1 --nodes pve1,pve2,pve3 --nofailback=1 --restricted=1

    Наш ресурс будет работать только на нодах указанных для этой группы. Добавим наш контейнер в эту группу:


    ha-manager add ct:101 --group=nfs1 --max_relocate=3 --max_restart=3

    На этом все. Просто, не правда ли?


    Полученную nfs-шару можно сразу-же подключить в Proxmox, для хранения и запуска других виртуальных машин и контейнеров.


    Рекомендации и тюнинг


    DRBD

    Как я отметил выше, всегда желательно использовать отдельную сеть под репликацию. Крайне желательно использовать 10-гигабитные сетевые адаптеры, в противном случае у вас все упрется в скорость портов.
    Если репликация вам кажется достаточно медленной попробуйте потюнить некоторые параметры для DRBD. Вот конфиг, который на мой взгляж является оптимальными для моей 10G-сети:


    # cat /etc/drbd.d/global_common.conf
    global {
     usage-count yes;
     udev-always-use-vnr; 
    }
    common {
     handlers {
     }
     startup {
     }
     options {
     }
     disk {
      c-fill-target 10M;
      c-max-rate   720M;
      c-plan-ahead   10;
      c-min-rate    20M;
     }
     net {
      max-buffers     36k;
      sndbuf-size   1024k;
      rcvbuf-size   2048k;
     }
    }

    Подробнее про каждый параметр вы можете получить информацию из официальной документации DRBD


    NFS-сервер

    Для ускорения работы NFS-сервера возможно поможет увеличение общего числа запускаемых экземпляров NFS-сервера. По умолчанию — 8, лично мне помогло увеличение этого числа до 64.


    Что бы этого добиться обновите параметр RPCNFSDCOUNT=64 в /etc/default/nfs-kernel-server.
    И перезапустите демоны:


    systemctl restart nfs-utils
    systemctl restart nfs-server

    NFSv3 vs NFSv4

    Знаете в чем отличие между NFSv3 и NFSv4?


    • NFSv3 — это stateless протокол как правило он лучше переносит сбои и быстрее восстанавливается.
    • NFSv4 — это stateful протокол, он работает быстрее и может быть привязан к определенным tcp-портам, но из-за наличия состояния он более чувствителен к сбоям. В нем так же есть возможность использование аутентификации с помощью Kerberos и куча других интересных функций.

    Тем не менее когда вы выполняете showmount -e nfs_server используется протокол NFSv3. Proxmox тоже использует NFSv3. NFSv3 так же обычно используется для организации загрузки машин по сети.


    В общем, если у вас нет особых причин использовать NFSv4, старайтесь использовать NFSv3 так как он менее болезненно переживает любые сбои из-за отсутствия состояния как такового.


    Примонтировать шару используя NFSv3 можно указав параметр -o vers=3 для команды mount:


    mount -o vers=3 nfs_server:/share /mnt

    При желании можно отключить NFSv4 для сервера вообще, для этого добавьте опцию --no-nfs-version 4 в переменную RPCNFSDCOUNT и перезапустите сервер, пример:


    RPCNFSDCOUNT="64 --no-nfs-version 4"

    iSCSI и LVM


    Подобным образом внутри контейнера может быть настроен и обычный tgt-демон, iSCSI будет выдавать значительно бОльшую производительность для операций ввода-вывода, а контейнер будет работать более гладко ввиду того tgt-сервер работает полностью в пространстве пользователя.


    Как правило экспортируемый LUN нарезается на много кусочков с помощью LVM. Однако есть несколько ньюансов которые стоит учесть, например: каким образом обеспечены блокировоки LVM для совместного использования экспортированной группы на нескольких хостах.


    Пожалуй эти и другие ньюансы я опишу в следующей статье.

    Поделиться публикацией
    Комментарии 9
      0
      Модель DRBD с _двумя_ узлами в кластере с самого начала полна шизофрении и split-brain'а. Как бы с ним не боролись, без кворума никак. А какой кворум у DRBD? Ну… Вот такой вот кворум, из двух, всегда друг с другом согласных узлов.
        0
        Под небольшой нагрузкой и с определенной осторожностью — вполне себе работал DRBR 8 с Dual Primary.
        Но да — конструкция ненадежная была.
          +1
          Разумеется, она работает, когда всё хорошо.

          Все кластерные системы надо смотреть не в том, как они работают (happy path), а как они обрабатывают ошибки (sad path). У drbd такой sad path, что он, скорее, bad path по всем признакам.

          UPD: И дело не только в primary/primary. Даже модель primary/secondary с автопромоутингом secondary на primary — всё равно шизофренична.

          Pacemaker в такой конфигурации не работает даже со STONITH, потому что из-за сетевого сбоя «плохая» нода может прибить хорошую, и нет никакого арбитра понять кто прав, а кто баг.
            0
            Если мне не изменяет память, для STONITH было «замечательное» решение с рандомным таймаутами на убийство второй ноды для решения этой проблемы :)
              +1
              Рандомный таймаут не решает проблемы, от слова «совсем».

              Если у нас происходит partitioning, то для двух нод не существует метода понять, какая половинка «в сети». node1 думает, что она в сети, node2 думает, что она в сети. Не важно кто кого первым прибъёт, т.к. каждая из них может ошибаться, есть 50% шанс, что умрёт не та нода.

              Чтобы такого не было, нужен кворум. А кворум требует большинства. Большинство для двух нод — это две ноды, т.е. неудобно. Чтобы было удобно, нужна третья нода — арбитр.
                0
                Кворум можно сделать например, на дешёвой VPS'ке. Это будет дешевле, чем решение с тремя стораджами в ряде случаев, нужных для ceph
                  0
                  ceph не требует три стораджа, он требует три монитора. Избыточность данных контролируется уже настройками в процессе. Хочешь — 3, хочешь — 5, хочешь — 2. Или даже 1, как я часто делаю в лабораторных условиях.

                  А drbd научилась делать кворум с третьим участником?
                    0

                    Конечно, о том то и речь, drbd9 уже давно умеет кворум.
                    По умолчанию он всегда будет принимать решения исходя из большинства нод в кластере.
                    Но так же есть есть широкие возможности для конфигурации поведения при потере кворума.

                      0
                      Спасибо.

                      Я не знал, что drbd встала на путь разума (quorum).

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое