Gfarm分散ファイルシステムを導入してみよう

#  はじめに

分散ファイルシステムとは、ネットワーク上に設置したファイルサーバにデータを格納しておき、クライアントがローカルのファイルにアクセスするのと同様にしてアクセスすることを可能にしたファイルシステムです。
「複数のクライアントが容易にファイルを共有することができる」「データストレージを拡充しやすい」「データに冗長性・耐障害性を持たせることができる」などのメリットが挙げられます。
有名どころとしてはGluster FSやCeph, Amazon S3などが挙げられるでしょうか。

[Gfarm](http://oss-tsukuba.org/software/gfarm)は、そんな分散ファイルシステムの1種です。NPO法人つくばOSS技術支援センターが中心となって開発を進めている、国産の（？）分散ファイルシステムとなっています。
日本国内の共用高性能計算基盤である[HPCI](http://www.hpci-office.jp/pages/what_is_hpci)などで利用されていますが、オープンソースソフトウェアであり、私たちも手軽に導入することができます。
今回は、このGfarmとそのマウントシステムであるGfarm2fsの環境構築をしてみたので、その流れをまとめたいと思います。

Gfarmに着目した理由は以下の通りです。

- 作業の関係で分散ファイルシステムが必要になった
- Qiitaに記事がなかったのでネタになるかと思った
- ~~国産ゆえに公式のリファレンスが基本的に日本語なので作りやすそうだと思った~~これが間違いだったということにも気づかせてくれました（「Gfarmがダメ」という話ではなく、「自分の認識・姿勢が甘かった」という話です）

およそ公式のリファレンスに沿った流れではありますが、自分がハマったポイントやその解決策を添えながら書いていきますので、お役に立てれば幸いです。

# 環境と注意事項
Gfarmに所属するホストは、大きく3種類の役割を持ちます。

- メタデータサーバ：ファイルのメタ情報を保持しておく中心となるサーバです。鍵の生成や各ホストの状態監視などもここから行います。1台のみでも構成できますが複数台で冗長構成にすることもできます。
- ファイルシステムノード：実際にデータを保存することのできるノードです。
- クライアントノード：Gfarm上のデータへのアクセス権を持ったノードです。ファイルシステムノードとしての役割をもつノードは同時にクライアントノードとしての役割も持ちます。


今回は、メタデータサーバ兼ファイルシステムノード兼クライアントノードとなるホスト1台（metahost:192.168.XX.1）、ファイルシステムノード兼クライアントノードとなるホスト1台（filehost:192.168.XX.2）の計2台からなる環境で検証を進めました。

バージョンなどの情報は以下の通りです。

- ホストに載っているOS : CentOS 7.3 
- Gfarm 2.7.13
- Gfarm2fs 1.2.12

そのほかの注意事項は以下の通りです。

- 特に断りがない限り、一連の作業はroot権限で行います。
- 今回の環境構築はrpmからのビルドと公開鍵認証による認証を想定しています。
- ソースコードからのインストールやGSIによる認証を想定した環境構築は行なっていないので悪しからずご了承ください。
- コマンド実行中のログなどは適宜`... Complete!`で省略します。

# Gfarm環境構築
## rpmファイルのインストール
まずは[公式のインストールページ](https://sourceforge.net/projects/gfarm/files/gfarm_v2/)から任意のバージョンのファイルをダウンロードします。
この中にあるrpmファイルをビルドして、インストールしていきます。

``` shell-session:metahost/filehost
# yum install openssl-devel openldap-devel postgresql-devel
...
Complete!

# rpmbuild --rebuild gfarm-2.7.13-1.src.rpm
...
Complete!

# cd rpmbuild/RPMS/x86_64

# ls
gfarm-doc-2.7.13-1.el7.centos.x86_64.rpm           gfarm-fsnode-2.7.13-1.el7.centos.x86_64.rpm
gfarm-client-2.7.13-1.el7.centos.x86_64.rpm        gfarm-ganglia-2.7.13-1.el7.centos.x86_64.rpm
gfarm-debuginfo-2.7.13-1.el7.centos.x86_64.rpm     gfarm-libs-2.7.13-1.el7.centos.x86_64.rpm
gfarm-devel-2.7.13-1.el7.centos.x86_64.rpm         gfarm-server-2.7.13-1.el7.centos.x86_64.rpm
```
特に恐れることはないです。rpmファイルをrebuildすることで8つほどrpmファイルが用意されます。
できたてほやほやのOS上だとrpmbuildがインストールされていない場合もあるのでその場合は`yum install rpm-build`で持ってきておきましょう。
これをインストールしていきます。

``` shell-session:metahost
# rpm -Uvh gfarm-server-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-libs-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-fsnode-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-client-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-doc-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-devel-2.7.13-1.el7.centos.x86_64.rpm
```
``` shell-session:filehost
# rpm -Uvh gfarm-fsnode-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-libs-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-client-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-doc-2.7.13-1.el7.centos.x86_64.rpm \
gfarm-devel-2.7.13-1.el7.centos.x86_64.rpm
```

ここではホストの役割によってインストールするものが変わってきます。メタデータサーバにはserverとlibsを、ファイルシステムノードにはfsnode,libs,client,docを、兼用の場合はその全てをインストールしましょう。
また、公式リファレンスでは言及されていませんが、**develを同時にインストールしておくとあとで少し幸せになれるのでこの時にやっておきましょう。**

## ファルシステム構築
ここからはメタデータサーバとクライアントノードで作業が大きく変わってきます。流れとしてはまずメタデータサーバを用意して、そのあとにクライアントノードを増やしていきます。
順番に見ていきましょう。

### メタデータサーバの準備
```shell-session:metahost
# config-gfarm -t -A gfarm_user

prefix                 [--prefix]:
metadata backend             [-b]: postgresql
(available backend: postgresql ldap none)
metadata     directory       [-l]: /var/gfarm-pgsql
metadata log directory       [-L]: /var/gfarm-pgsql/pg_xlog
postgresql admin user        [-U]: postgres
postgresql admin password    [-W]: (auto generated)
postgresql user              [-u]: gfarm
postgresql password          [-w]: (auto generated)
postgresql prefix            [-P]: /usr
postgresql version           [-V]: 9.2
postgresql XML supported     [-X]: no
postgresql data checksum support
                             [-E]: no
metadata replication         [-r]: no
digest                       [-d]:
metaserver hostname          [-h]: metahost
matadata admin user          [-A]: gfarm_user
matadata admin dn            [-D]:
portmaster port              [-p]: 10602
gfmd port                    [-m]: 601
auth type                    [-a]: sharedsecret
rc script for gfmd               : /etc/systemd/system/gfmd.service
gfmd conf file                   : /etc/gfmd.conf
gfarm client conf file           : /etc/gfarm2.conf
gfmd pid file                    : /var/run/gfmd.pid
rc script for backend            : /etc/systemd/system/gfarm-pgsql.service
backend pid file                 : /var/run/postmaster.pid

# config-gfarm -A gfarm_user
...
Complete!
```

まずはconfig-gfarmから設定を行います。`-t`オプションを使用すると基本的な設定値が確認されますのでここから確認しておきましょう。
`-A`は管理者のグローバルユーザ名を指定するオプションです。root権限でコマンドを実行しているとデフォルトではrootがグローバルユーザになるため、これを回避するためには`-A`で適切なグローバルユーザを設定しておく必要があります（ここではgfarm_user）。
そのほかのオプションも`--prefix`で対応づけていけば任意に設定できるので独自に設定したい場合は設定しましょう。
確認が済んだら`-t`オプションを外して設定を行います。

ちなみにここで私はちょっとハマりましたので余談です。

```shell-session:metahost
# config-gfarm -t -A gfarm_user
...
WARNING: command not found: pg_ctl
```
`config-gfarm`を実行すると、このようにpg_ctlコマンドが見つからない、とエラーが吐かれました。
pg_ctl はPostgreSQL関係のコマンドなのですが、PostgreSQLは既にインストール済み。
何回やっても実行できない…と訝しんで色々検証したところ...

```shell-session:metahost
# pg_config --version
PostgreSQL 9.2.24
# /usr/pgsql-10/bin/pg_config --version
PostgreSQL 10.9
```
バージョンが違う2つのSQLが共存してしまっていたみたいで、`config-gfarm`は9.2の方を参照しているけど、pg_ctlは10.9のものを参照している、という状況だったみたいです…情けない。
バージョンはきちんと統一しましょう。

なお、バージョンの統一が面倒な場合は、以下のように`-P`オプションを使って強引に処理することもできます。
 
```shell-session:metahost
# config-gfarm -P /usr/pgsql-10 -A gfarm_user
...
Complete!
```

ここまででデフォルトの設定が終わりました。
次に公開鍵認証の準備に移ります。

```shell-session:metahost
# su _gfarmfs
$ cd ~
$ gfkey -f -p 31536000
$ chmod 600 .gfarm_shared_key
$ chown _gfarmfs:_gfarmfs .gfarm_shared_key
$ ls -la | grep .gfarm_shared_key
-rw-------. 1 _gfarmfs _gfarmfs  74 Jun 25 16:12 .gfarm_shared_key
```
鍵の生成は`_gfarmfs`ユーザで行います。私の環境ではこれまでの設定の過程で自動でユーザが追加されていましたが、もし`_gfarmfs`ユーザが追加されていなければ`useradd`から追加しておいきましょう。
`gfkey`コマンドを実行することで`.gfarm_shared_key`という名前の鍵が生成されます。権限と所有者を変更して`_gfarmfs`のホームディレクトリに追加しておきましょう。なお、`-p`オプションは鍵の有効時間（秒）です。

最後に起動確認です。

```shell-session:metahost
# systemctl start  gfmd
# systemctl status gmfd
● gfmd.service - Gfarm filesystem metaserver
   Loaded: loaded (/etc/systemd/system/gfmd.service; enabled; vendor preset: disabled)
   Active: active (running) since Tue 2019-06-25 16:44:50 JST; 2 days ago
...
```
無事activeになっていることが確認できました！
ここでメタデータサーバの準備は１段落です。

### ファイルシステムノード（兼クライアントノード）の準備
次にファイルシステムノードの準備を行います。簡単のためfilehost上の設定のみ記述しますが、今回の環境ではmetahostはファイルシステムノードの役割も兼ねるため適宜同じ設定を施す必要があることをご注意ください。

まずは先ほど用意しておいた鍵と`gfarm2.conf`を配置します。

```shell-session:metahost
# scp .gfarm_shared_key _gfarmfs@filehost:~/
...
Complete!
# scp /etc/gfarm2.conf _gfarfs@filehost:/etc
...
Complete!
```

```shell-session:filehost
# chmod 600 .gfarm_shared_key
# chown _gfarmfs:_gfarmfs .gfarm_shared_key
# ls -la | grep .gfarm_shared_key
-rw-------. 1 _gfarmfs _gfarmfs  74 Jun 25 16:53 .gfarm_shared_key
```

メタデータサーバからscpなどでそれぞれ送ります。
公開鍵はメタデータサーバと同じように権限と所有者を変更しておきます。
`gfarm2.conf`はGfarmのコンパイル時に生成される設定ファイルです。基本的に`/etc`に配置されているはずですが、正確な場所は`config-gfmd`コマンドの実行結果からも確認できます。ファイルシステムノードでも同じ階層に配置しましょう。

次にgfsdの設定です。

```shell-session:filehost
# config-gfsd -t /var/gfarm
prefix                 [--prefix]:
hostname                     [-h]: filehost
listen address               [-l]: (all local IP addresses)
architecture                 [-a]: x86_64-centos7.3.1611-linux
port                         [-p]: 600
ncpu                         [-n]: 24
spool directory                  : /var/gfarm
rc script                        : /etc/systemd/system/gfsd.service
gfarm client conf file           : /etc/gfarm2.conf
gfsd pid file                    : /var/run/gfsd.pid


# config-gfsd /var/gfarm
...
/usr/bin/gfhost -c -a x86_64-centos7.3.1611-linux -p 600 -n 24 filehost
...
Complete!
```

```shell-session:metahost
# su gfarm_user
$ /usr/bin/gfhost -c -a x86_64-centos7.3.1611-linux -p 600 -n 24 filehost
```
メタデータサーバでも似たようなコマンドを実行しました。`-t`オプションで設定値を確認したあと、設定を行いましょう。
重要なのが`/usr/bin/gfhost ~`のコマンドです。このコマンドを実行することでこのホストがgfarmに参加します。メタデータサーバのグローバルユーザから実行しておきましょう。


なおここで，以下のようにエラーが出る場合が確認できました。

```shell-session:filehost
# config-gfsd /var/gfarm
created /var/gfarm
created /etc/systemd/system/gfsd.service
sed: cannot read /usr/share/gfarm/config/unconfig-gfsd.sh.in: No such file or directory
config-gfsd: cannot create /etc/unconfig-gfsd.sh
config-gfsd failure
```
エラーの通り`unconfig-gfsd.sh.in`が見つからないようです。
私はメタデータサーバから持ってくることで解消できました。`scp`コマンドでメタデータサーバのものを持ってきたあと、再度`config-gfsd`を実行しましょう。

最後に状態確認です。

```shell-session:filehost
# systemctl start  gfsd
# systemctl status gfsd
● gfsd.service - Gfarm filesystem node daemon
   Loaded: loaded (/etc/systemd/system/gfsd.service; disabled; vendor preset: disabled)
   Active: active (running) since Tue 2019-06-25 17:01:50 JST; 2 days ago
```
こちらも無事起動しました！

最後に、メタデータサーバからこれらのマシンが認識できているか確認しましょう。
（filehostだけでなくmetahostにもファイルシステムノード用のインストールをしていることを思い出してください）

```shell-session:metahost
# gfhost -lv
0.00/0.01/0.05 s x86_64-centos7.3.1611-linux 24 metahost 600 0(192.168.X.1)
0.00/0.01/0.05 s x86_64-centos7.3.1611-linux 24 filehost 600 0(192.168.X.2)
```
このように表示されていれば成功です。

なお私はここで2パターンほどハマりました。せっかくなので共有しておきます。

- パターン1：ポートが開いていない

```shell-session:metahost
# gfhost -lv
0.00/0.01/0.05 s x86_64-centos7.3.1611-linux 24 metahost 600 0(192.168.X.1)
x.xx/x.xx/x.xx - x86_64-centos7.3.1611-linux 24 filehost 600 0(192.168.X.2)
```
前の数値が`x.xx/x.xx/x.xx`となっている場合は必要なポートが開いていない可能性が高いです。
Gfarmが使用するポートは，メタデータサーバは601/tcp、ファイルシステムノードは600/tcpと600/udpです（いずれも初期設定値）。
このうち、600/tcpでの疎通ができていない場合、このような表示になってしまうようです。必要なポートを開けることで、きちんと認識されるようになりました。
なお、使用するポートは`config-farm -m`と`config-gfsd -p`で任意に設定することもできます。


- パターン2：鍵認証がうまくいっていない

```shell-session:metahost
# gfhost -lv
0.00/0.01/0.05 s x86_64-centos7.3.1611-linux 24 metahost 600 0(192.168.X.1)
0.00/0.01/0.05 - x86_64-centos7.3.1611-linux 24 filehost 600 0(192.168.X.2)
filehost: authentication error
```
数字が表示されていてもホストが使用不可能（2項目目が`s`でなく`-`）になってしまう場合があります。
原因はズバリauthentication error、つまり認証の問題です。
このエラーが発生してしまった時は，鍵の配置・権限・所有者などを今一度確認しましょう。

# Gfarm2fs環境構築
次にGfarm2fsの環境構築に移りたいと思います。Gfarm2fsはファイルシステムノードおよびクライアントノードへ導入できます。
例によってfilehostを例に説明しますが、今回の例ならmetahostに、実環境ならGfarm上のファイルをマウントしたい全てのホストに導入する必要があります。

```shell-session:filehost
# yum install fuse fuse-devel
...
Complete!
# rpmbuild --rebuild gfarm2fs-1.2.12-1.src.rpm
...
Complete!
# cd rebuild/RPMS/x86_64
# rpm -Uvh gfarm2fs-1.2.12-1.el7.centos.x86_64.rpm
...
Complete!
```
といっても、必要なパッケージをインストールしてあとはrpmにお任せです。
大元のrpmファイルはGfarmと同じ[公式のインストールページ](https://sourceforge.net/projects/gfarm/files/gfarm2fs/)から落としてきておきましょう。

注意点としては，gfarm2fsのbuildには`fuse-devel`と`gfarm-devel`が必要です。`fuse-devel`はyumで持ってこれますが`gfarm-devel`はrpmからあらかじめインストールしておく必要があります。
この記事の手順に則っている場合Gfarmのインストールの時点で準備されていますが、もし準備が抜けていた場合はインストールしておきましょう。

# 動作確認
では実際にGfarm、Gfarm2fsを使ってファイルシステムを実際に触ってみましょう。

## マウントを用いない利用

metahostからGfarmファイルシステムにローカルの`foo.txt`をコピーする流れを示しています。


```shell-session:metahost
$ ls
foo.txt
$ gfls
$ cat foo.txt
I'm foo.txt From metahost.
$ gfreg foo.txt foo.txt
$ gfls
foo.txt
$ gfexport foo.txt
I'm foo.txt From metahost.
```
```shell-session:filehost
$ gfls
foo.txt
$ gfexport foo.txt
I'm foo.txt From metahost.
```

`gfls`はファイルシステム上のファイルを表示するコマンドです（`ls`のgfarm版）。
最初はGfarm上にはなにも登録されていませんが、metahostにあるローカルのファイルをコピーすることに成功しています。
この情報は別のホストであるfilehostからも確認できています。

## マウントを用いる場合

metahost,filehostそれぞれからgfarm2fsを用いてGfarmファイルシステムをマウントし、アクセスを流れを示しています。

```shell-session:metahost
$ ls
$ gfls
bar.txt
$ gfexport bar.txt
I'm bar.txt From Gfarm.
$ mkdir mountdir
$ ls
mountdir
$ ls mountdir
$ gfarm2fs mountdir
$ ls mountdir
bar.txt
$ cat mountdir/bar.txt
I'm bar.txt From Gfarm.
$ touch mountdir/hoge.txt
$ gfls
bar.txt hoge.txt
```
まずmetahost上ではmountdirというマウントポイントとなるディレクトリを作り、そこにGfarmを`gfarm2fs`コマンドでマウントしています。
これにより、あたかもローカルファイルを操作するようにして、Gfarm上のファイルを操作することが可能になります。

```shell-session:filehost
$ ls
$ gfls
bar.txt hoge.txt
$ mkdir mountdir
$ gfarm2fs mountdir
$ ls mountdir
bar.txt hoge.txt
$ ls mountdir/bar.txt
I'm bar.txt From Gfarm.
$ echo "I'm hoge.txt From filehost." >> hoge.txt
$ gfexport hoge.txt
I'm hoge.txt From filehost.
```
つづけてfilehost上にもマウントポイントを用意してみます。先ほどmetahostで追加した`hoge.txt`が見えることから、Gfarmを共有できていることが確認できます。
このように、複数のホストからもGfarm上のファイルにアクセスすることができ、共有ストレージとしての振る舞いもきちんと行えます。

ちなみに、マウント中のディレクトリは使用中の扱いになるため、名前の変更等は行えません。こうした場合は`fusermount`でアンマウントしてあげましょう。

```shell-session:metahost
$ mv mountdir/ mountdir_2/
mv: cannot move ‘mountdir/’ to ‘mountdir_2/’: Device or resource busy
$ fusermount -u mountdir
$ mv mountdir/ mountdir_2/
$ ls
mountdir2
```


# 最後に
GfarmとGfarm2fsの環境構築、それに簡単な動作確認について説明しました。
実際に触ってみた印象ですが、インストールから実際の動作まで、多少詰まったポイントもありましたが、基本的に非常にスムーズに進めることができました。
最後の動作確認は本当に触りの部分だけで、[他にももっといろんなことができますので、](http://oss-tsukuba.org/gfarm/share/doc/gfarm/html/ja/ref/index.html)是非試してみてください。