DRBD9で分散ストレージを作る

Ubuntu 18.04LTSでDRBD9の分散ストレージを作るメモです。

DRBD(Distributed Replicated Block Device)とは、Linux上でネットワークを介したストレージをリアルタイムにミラーリングするためのソフトウェアです。
何が出来るかと言えば、2台〜4台のコンピュータ間のストレージで完全に同期を取ることが出来ます。
Active/Standbyで動作しているActive側でストレージに書き込みが行われると、ネットワークを介してSlave側のストレージにも書き込みが行われることで、データが同期されるという仕組みです。
また、同期はブロック単位でおこなわれるので、スライス(パーティション)がそっくり同期されます。その為、ファイルシステムに依存しない事も特徴です。(ファイル単位での同期ならrsync使うとか、他にも方法は色々あるけれど)

通常クラスタ構成のシステムでは共有ストレージなど「高価なハードウェア」を使うか、レプリケーションソフトで定期的に同期を行う方式が一般的だと思います。レプリケーションソフトの同期では同期のタイミングによって時間差が生まれてしまうため、同期が取れていないタイミングが発生しますが、DRBDではブロック単位の書き込みをそのままネットワークを介して行いますのでほぼリアルタイムの同期が行えます。
(市販のクラスタソフトウェアでも似たような仕組みを備えている製品があるようだ・・・)

Linuxではクラスタ自体はPacemaker(旧 Heartbeat)で行えますので、複数のコントローラ、複数のパスを備えた高価なストレージを使わずにクラスタのシステムが作れる事になります。とはいえネットワークを介して同期するってことは、ネットワークに相当負荷が掛かるということですので、高パフォーマンスを要求されると厳しい気がします。
仕組み自体は昔からあった(カーネル2.6の頃・・・2009年位?・・・に生まれたらしい)のですが、これまで触ってこなかったので、今更ながらちょっと触ってみましょうという感じです。

仮想環境上にUbuntu 18.04LTSのサーバを3台作りました。といっても全部一から作ると面倒なんで1台作ってテンプレート化して3台デプロイしました。

  1. まず一台作成します。これをテンプレート化して3台作ります。
  2. OSインストール
    • 普通にUbuntu Server 18.04LTSをインストールしました。IPv6を止めたり、NTP設定したりはいつもどおり。
    • NICは2個準備しておきます。1つは普通に使うヤツで、もう1つがDRBDの同期用です。

  3. 共有させるストレージの作成
  4. 仮想基板で仮想ハードディスクを作る
  5. 仮想ハードディスクにスライス(パーティション)を作る
  6. SATAの2台目のHDDとして作成したので、
    $ sudo fdisk /dev/sdb
    コマンド (m でヘルプ): n
    パーティションタイプ
    p 基本パーティション (0 プライマリ, 0 拡張, 4 空き)
    e 拡張領域 (論理パーティションが入ります)
    選択 (既定値 p): p
    パーティション番号 (1-4, 既定値 1): 1
    最初のセクタ (2048-33554431, 既定値 2048):
    最終セクタ, +セクタ番号 または +サイズ{K,M,G,T,P} (2048-33554431, 既定値 33554431):
    新しいパーティション 1 をタイプ Linux、サイズ 40 GiB で作成しました。

  7. パッチの適用いつもどおりです
    $ sudo apt-get update
    $ sudo apt-get upgrade
    $ sudo apt-get dist-upgrade
    $ sudo apt autoremove

  8. hostsファイルの作成
    3台分名前解決できるようにhostsファイルに書きます。ここで同期用に使うIPアドレスを書いておきます。
    127.0.0.1 localhost.localdomain localhost
    ::1 localhost6.localdomain6 localhost6
    10.255.255.101 drbd1
    10.255.255.102 drbd2
    10.255.255.103 drbd3

    # The following lines are desirable for IPv6 capable hosts
    ::1 localhost ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters
    ff02::3 ip6-allhosts

  9. DRBD9 パッケージのインストール
    $ sudo add-apt-repository ppa:linbit/linbit-drbd9-stack

    This ppa contains DRBD9, drbd-utils, DRBD Manage, and drbdmanage-docker-volume.

    This differs from official, production grade LINBIT repositories in several ways, including:
    - We push RCs immediately to the PPA
    - We don't push hotfixes, these usually have to wait until the next RC/release
    - We only keep 2 LTS versions up to date (xenial and bionic, but not trusty)

    For support and access to official repositories see:
    https://www.linbit.com or write an email to: sales AT linbit.com
    詳しい情報: https://launchpad.net/~linbit/+archive/ubuntu/linbit-drbd9-stack
    [ENTER] を押すと続行します。Ctrl-c で追加をキャンセルできます。

    取得:1 http://ppa.launchpad.net/linbit/linbit-drbd9-stack/ubuntu bionic InRelease [21.3 kB]
    ヒット:2 http://archive.ubuntu.com/ubuntu bionic InRelease
    取得:3 http://security.ubuntu.com/ubuntu bionic-security InRelease [83.2 kB]
    取得:4 http://archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
    取得:5 http://ppa.launchpad.net/linbit/linbit-drbd9-stack/ubuntu bionic/main amd64 Packages [2,184 B]
    取得:6 http://archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
    取得:7 http://ppa.launchpad.net/linbit/linbit-drbd9-stack/ubuntu bionic/main Translation-en [1,228 B]
    271 kB を 2秒 で取得しました (145 kB/s)
    パッケージリストを読み込んでいます... 完了
    $ sudo apt-get install drbd-utils python-drbdmanage drbd-dkms
    パッケージリストを読み込んでいます... 完了
    依存関係ツリーを作成しています
    状態情報を読み取っています... 完了
    以下の追加パッケージがインストールされます:
    autoconf automake autopoint autotools-dev binutils binutils-common binutils-x86-64-linux-gnu build-essential cpp cpp-7 debhelper
    dh-autoreconf dh-strip-nondeterminism dkms dpkg-dev fakeroot g++ g++-7 gcc gcc-7 gcc-7-base gettext guile-2.0-libs intltool-debian
    libaio1 libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libarchive-cpio-perl libarchive-zip-perl libasan4
    libatomic1 libbinutils libc-dev-bin libc6-dev libcc1-0 libcilkrts5 libcroco3 libdpkg-perl libfakeroot libfile-fcntllock-perl
    libfile-stripnondeterminism-perl libgc1c2 libgcc-7-dev libgomp1 libgsasl7 libisl19 libitm1 libkyotocabinet16v5 liblsan0 libltdl-dev
    libltdl7 libmail-sendmail-perl libmailutils5 libmpc3 libmpx2 libmysqlclient20 libntlm0 libpython-stdlib libpython2.7
    libpython2.7-minimal libpython2.7-stdlib libquadmath0 libstdc++-7-dev libsys-hostname-long-perl libtimedate-perl libtool libtsan0
    libubsan0 linux-libc-dev m4 mailutils mailutils-common make manpages-dev mysql-common po-debconf postfix python python-dbus python-gi
    python-gobject python-gobject-2 python-minimal python2.7 python2.7-minimal ssl-cert thin-provisioning-tools
    提案パッケージ:
    autoconf-archive gnu-standards autoconf-doc binutils-doc cpp-doc gcc-7-locales dh-make dwz menu debian-keyring heartbeat g++-multilib
    g++-7-multilib gcc-7-doc libstdc++6-7-dbg gcc-multilib flex bison gdb gcc-doc gcc-7-multilib libgcc1-dbg libgomp1-dbg libitm1-dbg
    libatomic1-dbg libasan4-dbg liblsan0-dbg libtsan0-dbg libubsan0-dbg libcilkrts5-dbg libmpx2-dbg libquadmath0-dbg gettext-doc
    libasprintf-dev libgettextpo-dev glibc-doc bzr libtool-doc libstdc++-7-doc gfortran | fortran95-compiler gcj-jdk m4-doc mailutils-mh
    mailutils-doc make-doc libmail-box-perl procmail postfix-mysql postfix-pgsql postfix-ldap postfix-pcre postfix-lmdb postfix-sqlite
    sasl2-bin dovecot-common resolvconf postfix-cdb postfix-doc python-doc python-tk python-dbus-dbg python-dbus-doc python-gi-cairo
    python-gobject-2-dbg python2.7-doc binfmt-support openssl-blacklist
    以下のパッケージが新たにインストールされます:
    autoconf automake autopoint autotools-dev binutils binutils-common binutils-x86-64-linux-gnu build-essential cpp cpp-7 debhelper
    dh-autoreconf dh-strip-nondeterminism dkms dpkg-dev drbd-dkms drbd-utils fakeroot g++ g++-7 gcc gcc-7 gcc-7-base gettext guile-2.0-libs
    intltool-debian libaio1 libalgorithm-diff-perl libalgorithm-diff-xs-perl libalgorithm-merge-perl libarchive-cpio-perl
    libarchive-zip-perl libasan4 libatomic1 libbinutils libc-dev-bin libc6-dev libcc1-0 libcilkrts5 libcroco3 libdpkg-perl libfakeroot
    libfile-fcntllock-perl libfile-stripnondeterminism-perl libgc1c2 libgcc-7-dev libgomp1 libgsasl7 libisl19 libitm1 libkyotocabinet16v5
    liblsan0 libltdl-dev libltdl7 libmail-sendmail-perl libmailutils5 libmpc3 libmpx2 libmysqlclient20 libntlm0 libpython-stdlib
    libpython2.7 libpython2.7-minimal libpython2.7-stdlib libquadmath0 libstdc++-7-dev libsys-hostname-long-perl libtimedate-perl libtool
    libtsan0 libubsan0 linux-libc-dev m4 mailutils mailutils-common make manpages-dev mysql-common po-debconf postfix python python-dbus
    python-drbdmanage python-gi python-gobject python-gobject-2 python-minimal python2.7 python2.7-minimal ssl-cert thin-provisioning-tools
    アップグレード: 0 個、新規インストール: 91 個、削除: 0 個、保留: 0 個。
    53.9 MB のアーカイブを取得する必要があります。
    この操作後に追加で 231 MB のディスク容量が消費されます。
    続行しますか? [Y/n] y
    ・・・省略・・・
    DKMS: install completed.


  10. DRBDで管理するスライス(パーティション)はLVMを作る必要があるので
    物理ボリュームを作って
    $ sudo pvcreate /dev/sdb1

    ボリュームグループ「drbdpool」を作ります
    $ sudo vgcreate drbdpool(このプール名称 drbdpoolは変更しちゃダメです)

    ここまででやっと準備ができました。
  11. 仮想基盤上でテンプレート化
  12. テンプレートから3台デプロイ
  13. 1台目のサーバのホスト名とIPアドレスを設定して再起動しておきます。
    $ sudo hostnamectl set-hostname drbd1
    $ sudo vi /etc/netplan/50-cloud-init.yaml
    $ sudo reboot

  14. 2台目の、3台目サーバも同じようにホスト名とIPアドレスを設定して再起動しておきます。
    ちなみにホスト名を変更するのはdrbdmanageコマンドを実行するまでです。それ以降でホスト名を変更してしまうと上手く動作しなくなります。
    $ sudo hostnamectl set-hostname drbd2(3台目はdrbd3ですね。)
    $ sudo vi /etc/netplan/50-cloud-init.yaml
    $ sudo reboot

  15. 1台目のサーバでDRBDを初期化します
    $ sudo drbdmanage init 10.255.255.101

    You are going to initialize a new drbdmanage cluster.
    CAUTION! Note that:
    * Any previous drbdmanage cluster information may be removed
    * Any remaining resources managed by a previous drbdmanage installation
    that still exist on this system will no longer be managed by drbdmanage

    Confirm:

    yes/no: yes
    Empty drbdmanage control volume initialized on '/dev/drbd0'.
    Empty drbdmanage control volume initialized on '/dev/drbd1'.
    Waiting for server: .
    Operation completed successfully


    そうすると1台目のサーバがDRBDに認識されます
    $ sudo drbdmanage list-nodes
    +------------------------------------------------------------------------------------------------------------+
    | Name | Pool Size | Pool Free | | State |
    |------------------------------------------------------------------------------------------------------------|
    | drbd1 | 40956 | 40948 | | ok |
    +------------------------------------------------------------------------------------------------------------+
  16. 1台目のサーバで、2台目のサーバを追加する操作をします
    $ sudo drbdmanage add-node drbd2 10.255.255.102
    Operation completed successfully
    Operation completed successfully
    Host key verification failed.
    Give leader time to contact the new node
    Operation completed successfully
    Operation completed successfully

    Join command for node drbd2:
    drbdmanage join -p 6999 10.255.255.102 1 drbd1 10.255.255.101 0 パスフレーズ


    最後に指示のあったdrbdmanage join のコマンドは2台目のサーバで実行します。
  17. 2台目のサーバでdrbdmanage joinのコマンドを実行します。
    $ drbdmanage join -p 6999 10.255.255.102 1 drbd1 10.255.255.101 0 パスフレーズ
    You are going to join an existing drbdmanage cluster.
    CAUTION! Note that:
    * Any previous drbdmanage cluster information may be removed
    * Any remaining resources managed by a previous drbdmanage installation
    that still exist on this system will no longer be managed by drbdmanage

    Confirm:

    yes/no: yes
    Waiting for server to start up (can take up to 1 min)
    Operation completed successfully


  18. どうなったか1号機で確認します。
    $ sudo drbdmanage list-nodes
    +------------------------------------------------------------------------------------------------------------+
    | Name | Pool Size | Pool Free | | State |
    |------------------------------------------------------------------------------------------------------------|
    | drbd1 | 40956 | 40948 | | online/quorum vote ignored |
    | drbd2 | unknown | unknown | | pending actions: adjust connections |
    +------------------------------------------------------------------------------------------------------------+

    Stateがpendingになってますので同期されるまでしばらく待ちます。
  19. しばらく待ってから再度確認を行います。
    $ sudo drbdmanage list-nodes
    +------------------------------------------------------------------------------------------------------------+
    | Name | Pool Size | Pool Free | | State |
    |------------------------------------------------------------------------------------------------------------|
    | mail1 | 40956 | 40948 | | ok |
    | mail2 | unknown | unknown | | ok |
    +------------------------------------------------------------------------------------------------------------+

    Stateがokになったので2台目が無事に組み込まれました。
  20. 1台目のサーバで、3台目のサーバを追加する操作をします
    $ sudo drbdmanage add-node drbd3 10.255.255.103
    Operation completed successfully
    Operation completed successfully
    Host key verification failed.
    Give leader time to contact the new node
    Operation completed successfully
    Operation completed successfully

    Join command for node drbd3:
    drbdmanage join -p 6999 10.255.255.103 1 drbd1 10.255.255.101 0 パスフレーズ


    最後に指示のあったdrbdmanage join のコマンドは3台目のサーバで実行します。
  21. 3台目のサーバでdrbdmanage joinのコマンドを実行します。
    $ drbdmanage join -p 6999 10.255.255.103 1 drbd1 10.255.255.101 0 パスフレーズ
    You are going to join an existing drbdmanage cluster.
    CAUTION! Note that:
    * Any previous drbdmanage cluster information may be removed
    * Any remaining resources managed by a previous drbdmanage installation
    that still exist on this system will no longer be managed by drbdmanage

    Confirm:

    yes/no: yes
    Waiting for server to start up (can take up to 1 min)
    Operation completed successfully


  22. どうなったか1号機で確認します。
    $ sudo drbdmanage list-nodes
    +------------------------------------------------------------------------------------------------------------+
    | Name | Pool Size | Pool Free | | State |
    |------------------------------------------------------------------------------------------------------------|
    | drbd1 | 40956 | 40948 | | ok |
    | drbd2 | 40956 | 40948 | | ok |
    | drbd3 | unknown | unknown | | offline/quorum vote ignored, pending actions: adjust connections |
    +------------------------------------------------------------------------------------------------------------+

    3台目のStateがpendingになってますので同期されるまでしばらく待ちます。
    2台目のPool SizeとPool Freeが取得出来てますね。
  23. しばらく待ってから再度確認を行います。
    $ sudo drbdmanage list-nodes
    +------------------------------------------------------------------------------------------------------------+
    | Name | Pool Size | Pool Free | | State |
    |------------------------------------------------------------------------------------------------------------|
    | drbd1 | 40956 | 40948 | | ok |
    | drbd2 | 40956 | 40948 | | ok |
    | drbd3 | 40956 | 40948 | | ok |
    +------------------------------------------------------------------------------------------------------------+

    3台ともStateがokになったので3台目も無事に組み込まれました。
  24. 同期しているか確認
    $ sudo drbdsetup status
    .drbdctrl role:Primary
    volume:0 disk:UpToDate
    volume:1 disk:UpToDate
    drbd2 role:Secondary
    volume:0 peer-disk:UpToDate
    volume:1 peer-disk:UpToDate
    drbd3 role:Secondary
    volume:0 peer-disk:UpToDate
    volume:1 peer-disk:UpToDate

    1号機がPrimaryになってて、2号機と3号機がSecondaryになっていることが確認できました。
  25. 1台目でプールを作ります。(名前はr0・・・安直ですが)
    $ sudo drbdmanage add-resource r0

    プールが出来たか確認します。
    $ sudo drbdmanage list-volumes --show Port
    +------------------------------------------------------------------------------------------------------------+
    | Name | Vol ID | Size | Minor | Port | | State |
    |------------------------------------------------------------------------------------------------------------|
    | r0 | * | * | * | 7000 | | * |
    +------------------------------------------------------------------------------------------------------------+

    r0 出来てますね。
  26. そこに40GBのボリュームを作ります。
    $ sudo drbdmanage add-volume r0 40GB
    Operation completed successfully

    ボリュームが出来たか確認します。
    $ sudo drbdmanage list-volumes --show Port
    +------------------------------------------------------------------------------------------------------------+
    | Name | Vol ID | Size | Minor | Port | | State |
    |------------------------------------------------------------------------------------------------------------|
    | r0 | 0 | 37.25 GiB | 100 | 7000 | | ok |
    +------------------------------------------------------------------------------------------------------------+

    出来ましたね。
  27. リソースを2台目、3台目に適用します。
    $ sudo drbdmanage deploy-resource r0 3

    確認します。
    $ sudo drbdmanage list-assignments
    +------------------------------------------------------------------------------------------------------------+
    | Node | Resource | Vol ID | | State |
    |------------------------------------------------------------------------------------------------------------|
    | drbd1 | r0 | * | | ok |
    | drbd2 | r0 | * | | ok |
    | drbd3 | r0 | * | | ok |
    +------------------------------------------------------------------------------------------------------------+

    出来ましたね。
  28. ファイルシステムを作る
    あとは普通にPrimaryになっているサーバ(1号機)から/dev/debd100としてボリュームが使えるようになっていますので、ファイルシステムを作ります。
    $ sudo mkfs -t ext4 /dev/drbd100
    mke2fs 1.44.1 (24-Mar-2018)
    Creating filesystem with 9765625 4k blocks and 2444624 inodes
    Filesystem UUID: 6db9e21d-c29d-489f-bea8-c2503add8351
    Superblock backups stored on blocks:
    32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
    4096000, 7962624

    Allocating group tables: done
    Writing inode tables: done
    Creating journal (65536 blocks): done
    Writing superblocks and filesystem accounting information: done


  29. ここで状態を確認してみると、同期が開始されていますので、リソースを配信すると同期が行われるようです。
    $ sudo drbdsetup status
    .drbdctrl role:Primary
    volume:0 disk:UpToDate
    volume:1 disk:UpToDate
    drbd2 role:Secondary
    volume:0 peer-disk:UpToDate
    volume:1 peer-disk:UpToDate
    drbd3 role:Secondary
    volume:0 peer-disk:UpToDate
    volume:1 peer-disk:UpToDate

    r0 role:Secondary
    disk:UpToDate
    drbd2 role:Secondary
    replication:SyncSource peer-disk:Inconsistent done:3.60
    drbd3 role:Secondary
    replication:SyncSource peer-disk:Inconsistent done:3.56


  30. あとはPrimaryになっているサーバ(ここでは1号機)で/dev/debd100をマウントすれば、使えるようになっています。

手順はかなり面倒ですが、これでもDRBD8までと違いdrbdmanageコマンドのおかげでかなり簡略化されているようです。
とりあえず出来たので、ここからPacemakerと組み合わせてクラスタを組んで行きたいと思います。

注意ですが各サーバを再起動するとdrbdのサービスが起動されないため、offline状態になってしまいます。
サービスを確認すると

$ sudo systemctl status drbd.service
● drbd.service - DRBD -- please disable. Unless you are NOT using a cluster manager.
Loaded: loaded (/lib/systemd/system/drbd.service; disabled; vendor preset: enabled)
Active: inactive (dead)

というように、クラスタ管理ソフトを使用する場合は自動起動に設定しないように注意書きがあります。

とりあえず、DRBDを起動させるには

$ sudo systemctl enable drbdmanaged.service
Created symlink /etc/systemd/system/multi-user.target.wants/drbdmanaged.service → /lib/systemd/system/drbdmanaged.service.

と、drbdmanaged.serviceを自動起動に設定すると、サーバを再起動してもちゃんと組み込まれるようになりました。