LINSTOR Controllerを冗長化する

LINBITが開発しているLINSTORは、複数のLinuxサーバ(ノード)が持つストレージを管理するツールです。
ノードが持つストレージをストレージプールというかたまりにして、そこからユーザーの必要に応じてボリュームを確保していろいろな方法で提供します。
LINSTORの内部での処理はボリュームマネージャや暗号化ライブラリ、データ冗長化にDRBDなどを使っていますが、ユーザはそれらのシステムを意識する必要がなく、LINSTORのコマンドを覚えればいろいろな機能を簡単に使うことができます。

LINSTORはControllerと呼ばれる管理プログラムとControllerの命令を受けて働くSatelliteという実行プログラムの2構成で動いています。Controllerはノードやストレージの構成を管理するデータベース(管理DB)を持っています。linstorコマンドを実行すると、Controllerで入力されたコマンドを解釈して、各ノードのSatteliteを操作します。Satelliteは、LVMのボリュームを切り出したり、ボリュームをDRBDで冗長化したり、iSCSIで外部へ公開したりします。

LINSTORの管理DBは/var/lib/linstorに作成されます。この管理DBのバックアップを取っておけば、Controllerノードが壊れてもLINSTORの設定を再現できるので、通常の運用ではこの管理DBのバックアップを強く推奨します。ControllerはLINSTORで管理しているノードの中で1つだけ動作しなければなりません。もしControllerを複数起動のノードで起動してしまうと、管理DBはControllerを起動したノードに作成され、更新されます。

実際の例でControllerとSatelliteの動きを説明します。node1、node2、node3の3つのノードから構成されるLINSTORクラスタの場合で、Controllerはnode1で動作して、Satelliteは全てのノードで動いています。node1の/var/lib/linstorには前出のように管理DBが存在します。このファイルを定期的にnode2にコピーしておけば、node1が故障したとき、node2でControllerを起動すればLINSTORのシステムを復旧できます。

node1とnode2で同時にControllerを起動すると、それぞれのノードで管理DBが更新されてしまい、LINSTORのストレージの設定が矛盾する可能性があります。そのため、Controllerの起動は注意深く行う必要があります。

ノード間のデータベースの更新と、LINTSTORクラスタ内でControllerが1つだけ起動できると、LINSTORが冗長化され、Controllerノード故障時にLINSTORの停止を最低限の時間に抑えることができます。過去LINBITのBlogではPacemakerとCorosyncを使って、ControllerをHAクラスター化する記事が公開されましたが、LINBITでは新たにDRBD Reactorという管理ツールを開発して、より簡単にLINSTORを冗長化ができるようになりました。

本Blogではその手順を紹介します。

1.環境

CentOS7のサーバを3台準備します。
各サーバーのIPアドレスは下のように設定しました。

ホスト名 IPアドレス

node1 192.168.3.81
node2 192.168.3.82
node3 192.168.3.83

LINBITのデモライセンスの申請フォームからライセンスを申し込んで、各ノードにLINBITバイナリのリポジトリを登録します。
登録の方法は「作っておぼえるHAシステム1」(https://blog.drbd.jp/2020/12/create-learn-ha-1/)のDRBDインストールを参照ください。
登録が終わったら、次のコマンドを実行して、DRBDとLINSTORをインストールします。

[root@node1 ~]# yum install drbdd kmod-drbd drbd-udev linstor-satellite linstor-controller linstor-client

インストール後にLINSTORの初期化をおこないます。

node1ではLINSTOR Controllerを起動します。

[root@node1 ~]# systemctl start linstor-controller

全てのノードでLINSTOR Satelliteを起動します。node1でControllerを起動したので、DBのディレクトリにはデータベースのファイルが作成されます。

[root@node1 ~]# ls -l /var/lib/linstor/
total 452
-rw-r--r--. 1 root root 442368 May 6 09:44 linstordb.mv.db
-rw-r--r--. 1 root root 4263 Apr 21 14:07 linstordb.trace.db
-rw-r--r--. 1 root root 0 May 6 09:42 loop_device_mapping
drwx------. 2 root root 12288 Apr 21 14:06 lost+found

2.LINSTORのセットアップ

インストールが終わったら、LINSTORの初期化とストレージプールの設定を行います。
この手順は既に「UbuntuでLINSTORを試してみた」(https://blog.drbd.jp/2020/09/try_linstor_with_ubuntu/)で
紹介しています。今回の環境に合わせて3ノードをLINSTORに登録します。次のコマンドをnode1で実行します

[root@node1 ~]# linstor node create node1 192.168.3.81
[root@node1 ~]# linstor node create node2 192.168.3.82
[root@node1 ~]# linstor node create node3 192.168.3.83
[root@node1 ~]# linstor node list
+--------------------------------------------------------+
| Node | NodeType   | Addresses                  | State |
|========================================================|
| node1 | SATELLITE | 192.168.3.81:3366 (PLAIN) | Online |
| node2 | SATELLITE | 192.168.3.82:3366 (PLAIN) | Online |
| node3 | SATELLITE | 192.168.3.83:3366 (PLAIN) | Online |
+--------------------------------------------------------+

LINSTORのDBをDRBDを使って冗長化するために、200MBのボリュームを作成します。DBは各ノードから参照できるように”–auto-place 3″を指定します。

[root@node1 ~]# linstor resource-definition create linstor_db
[root@node1 ~]# linstor volume-definition create linstor_db 200M
[root@node1 ~]# linstor resource create linstor_db -s linstor-pool --auto-place 3

ボリュームが作成されたので、LINSTOR Controllerを停止します。

[root@node1 ~]# systemctl stop linstor-controller

このボリュームを自動的にマウントできるようにsystemdのマウント設定ファイルを作成します。
ファイル名はvat-lib-linstor.mountとしました

[root@node1 ~]# cat /etc/systemd/system/var-lib-linstor.mount
 [Unit]
 Description=Filesystem for the LINSTOR controller
 [Mount]
 #you can use the minor like /dev/drbdX or the udev symlink
 What=/dev/drbd/by-res/linstor_db/0
 Where=/var/lib/linstor

/dev/drbd/by-res/linstor_db/0はdrbd-udevをインストールすると利用できるデバイスの記述方法です。
このシステムではDBの入ったデバイスは/dev/drbd1000なので、このデバイス名を使っても良いです。

このマウント設定ファイルは全てのノードにコピーしておきます。

DBファイルのディレクトリを別の名前に変更し、ファイルシステムを作成します。
この操作はnode1だけで実行します。

[root@node1 ~]# mv /var/lib/linstor /var/lib/linstor.orig
[root@node1 ~]# mkdir /var/lib/linstor
[root@node1 ~]# mkfs.ext4 /dev/drbd/by-res/linstor_db/0

先程作成したsystemdの設定ファイルでマウントできるかどうか確認します。

[root@node1 ~]# systemctl start var-lib-linstor.mount

マウントに成功したら別のディレクトリに保存しておいたDBファイルを戻して、LINSTOR Controllerを起動します。

[root@node1 ~]# cp -r /var/lib/linstor.orig/* /var/lib/linstor
[root@node1 ~]# systemctl start linstor-control

LINSTORの動作を確認してnode listでnode1〜3のノードが認識できれば問題ありません。

[root@node1 ~]# linstor node list

3.LINSTOR Controllerの自動起動

DRBD ReactorというLINBITのツールをインストールします。LINBITのリポジトリから簡単にインストールできます。

[root@node1 ~]# yum install drbd-reactor

DRBD Reactorの設定ファイルのディレクトリを/etc/drbd-reactor.dに作成します。次に設定ファイルを作成します

[root@node1 ~]# mkdir /etc/drbd-reactor.d/
[root@node1 ~]# cat /etc/drbd-reactor.d/linstor.toml
[[promoter]]
[promoter.resources.linstor_db]
start = ["var-lib-linstor.mount", "linstor-controller.service"]

設定の中ではDBのマウントを行ってから、LINSTOR Controllerを起動するという順番を定義しています。

DRBD Reactorの設定ファイルができたら、linstor-controllerの自動起動をやめて、dbrd-reactorは自動起動を設定します。

[root@node1 ~]# systemctl disable linstor-controller
[root@node1 ~]# systemctl enable drbd-reactor

最後にLINSTOR Satelliteの起動順番を定義します。
LINSTOR Satelliteはdrbd-reactorが起動した後に起動する必要があります。設定順を定義するにはサービスファイルを直接編集せず、systemctl editを使用して起動順番を設定します。

[root@node1 ~]# systemctl edit linstor-satellite
--設定内容--
[Service]
Environment=LS_KEEP_RES=linstor_db
[Unit]
After=drbd-reactor.service

以上の作業は全てのノードで行います。

全てのノードの設定が終わったら、node1〜3を全て再起動します。

4.動作確認

各ノードの再起動後にDRBD Reactorが起動すると、3ノードのうちどれかでLINSTOR Controllerが起動されます。
node1でControllerが起動した場合には、linstorコマンドはnode1で起動しますが、もしnode2でControllerが起動した場合にはlinstorコマンドは起動できません。そのような場合には、次のようにコマンドの引数か、環境変数でControllerのノードを指定して実行します。

[root@node1 ~]# linstor --controllers=node2 node list
[root@node1 ~]# LS_CONTROLLERS=node2 linstor node list

あるいは、 /etc/linstor/linstor-client.conf ファイルを作成して、以下のように定義することもできます。

[global]
controllers=node1,node2,node3

複数のlinstorコントローラが設定されている場合は、それらをカンマ区切りで指定します。linstorコマンドは順番で接続を試すので、どのノードでControllerが起動していてもlinstorコマンドを利用できます。

Controllerがnode2で起動している時に、そのnode2を再起動すると、DBファイルのマウントとControllerの起動がDRBD Reactorによって行われ、node1もしくはnode3でControllerが動き始めます。

前出の/etc/linstor/linstor-client.confファイルの設定があれば、node1で実行されたLINSTORへの命令は、新しいControllerに伝わり設定を継続して行えます。