Time4VPSのStorageVPSを活用してSymbolノードを建てる

どうもこんちは。

Symbolブロックチェーンのノード運用コストを抑えるために、一部のディレクトリを安価なストレージVPSに保管する試みです。

今回はリトアニアのTime4VPSを利用していきます。

Time4VPSには、通常のLinuxが動作するLinuxVPSと、スペックは低いがディスク容量が大きいStorageVPSを同一セグメントのLANに配置できます。
それらのサーバーをNFSによって繋ぎ、必要なデータをStorageVPSに持つことで安価なSymbolノード運営ができないか試します。

## 前提
### 本記事で使用する単語
NFSのサーバーとクライアントを明確に分けるために本記事では以下のように定義する。

- NFSクライアント：Linux VPS。ノードを動かす。
- NFSサーバー:StorageVPS。NFSサーバーをインストールし、データを保管する。

### 環境
#### NFSクライアント
- プラン：Linux VPS 8GBプラン
- OS : Ubuntu 20.04
- オプション : 5x Faster SSD storage, 1Gbps port speed.の2つを選択 

##### 注意事項
- ノードの推奨スペックはメモリ16GB以上。今回はあくまでも実験的スペック。
- Container VPSはNFS接続が無効化されているので **必ずLinux VPSプランを選択する** 。

#### NFSサーバー
- プラン: Storage VPS 0.5TB(メモリ1GB)
- OS : CentOS7(Ubuntuは16.04と古いのでこちらを選択)
- オプション: 1Gbps port speed

## NFSサーバーの初期設定

### 1. OSインストール
1. サーバ契約後、メニューからCent OS 7をインストールする
2. Login Detailsからrootユーザのパスワードを控える


### 2.SSH接続の有効化
ブラウザSSHでの操作はやりづらいので、ローカルからSSH接続できるようにする。
標準ではSSH接続が無効になっているので、以下の手順でファイアウォールのルールを設定して起動する。

1. メニューのConnect via SSHを選択
1. rootユーザでログインする(パスワードは右クリックして「Paste from browser」から入力すると便利)
1. 以下のコマンドを順に打ち込んでSSH接続を有効化する
```bash
systemctl start firewalld
systemctl enable firewalld
firewall-cmd --set-default-zone=drop
firewall-cmd --add-service=ssh --permanent
firewall-cmd --reload

# ついでにNFS関連のFirewall設定（これらは後で追加しても良い）
firewall-cmd --permanent --add-service=nfs
firewall-cmd --permanent --add-service=mountd
firewall-cmd --permanent --add-service=rpc-bind
firewall-cmd --reload
```

4.ついでに`passwd`コマンドでrootユーザのパスワードを変更しておくと便利

### 3. NFSサーバーのインストール
前の手順でSSH接続ができるようになっていると思うので、接続します。
接続後、以下のコマンドを実行します。

```bash
# NFSサーバインストール
yum install nfs-utils
# NFSサーバ起動＆自動起動設定
systemctl enable nfs
systemctl start nfs
# NFSサーバ起動確認
systemctl status nfs
#  Active: active (exited) となっていればOK!
```

### 4. 共有するディレクトリの作成
色々実験(※後述)した結果、今回おは下記の2ディレクトリをマウントする。

※NFSサーバー側の保存パスはお好きなディレクトリで大丈夫です。

| NFSクライアントのディレクトリ | NFSサーバー側の保存パス |
| --- | --- |
| target/databases | /var/nfs/symbol/databases |
| target/nodes/node/data/statedb | /var/nfs/symbol/data/statedb |

### 5. マウント情報を書き込む

```bash
# vimは入ってないのでviで。他のエディタが良い方はインストールしてください。
vi /etc/exports
```

以下の内容を記載します。

※注意: xxx.xxx.xxx.xxx は**NFSクライアント**のプライベート(ローカル)IPです。NFSサーバ自身のではないので注意。
```text
/var/nfs/symbol/databases xxx.xxx.xxx.xxx(rw,sync,no_root_squash,no_subtree_check)
/var/nfs/symbol/data/statedb xxx.xxx.xxx.xxx(rw,sync,no_root_squash,no_subtree_check)
```

保存したら、以下のコマンドで反映します。
```
exportfs -r
```
以上でサーバー側の設定は完了です。

## NFSクライアントの設定

### 前提
- ユーザー名は「ubuntu」で、sudoが実行できること
- Symbolのノードを建てる設定は終わっていること

### 1. NFS クライアントインストール

LinuxVPSのサーバにSSH接続します。
こちらは上記のようにファイアウォールの設定をしなくてもSSH接続できます。
以下のコマンドでNFSクライアントをインストールします。

```bash
sudo apt -y install nfs-common
```

### 2. Symbolノードを建てる
一旦ノードを起動し、すぐ止めます。
すぐ止めないと同期がどんどん進むのでマウント後のデータ転送が時間かかります。

```bash
# 各々普段からやってるやり方でどうぞ
symbol-bootstrap config -a dual -p mainnet -c my-preset.yml
symbol-bootstrap compose
symbol-bootstrap start -d

# healthCheckを実施し、起動したらすぐ止める
symbol-bootstrap healthCheck
symbol-bootstrap stop

```

### 3. 各ディレクトリをマウントする

一度ノードを起動することで必要なディレクトリとファイルが作成されたので、それらをマウントしていきます。
※すでにファイルやフォルダが存在するディレクトリをマウントすると、その内容が消えてしまうので一旦別名で退避させてからマウントします。

#### target/databasesディレクトリのマウント

```bash
# ディレクトリを退避
mv target/databases/ target/bk
# マウントするディレクトリを作成
mkdir target/databases
# マウントの実行
# 注)yyy.yyy.yyy.yyyはNFSサーバーのプライベート(ローカル)です
# 注2)Main(グローバル)IPでマウントするとBandWidthを消費するので、ローカルIPを使う
sudo mount -t nfs yyy.yyy.yyy.yyy:/var/nfs/symbol/databases target/databases
# ディレクトリ所有者の変更(ユーザ名がubuntuの場合)
sudo chown -R ubuntu:ubuntu target/databases
# 退避した内容をマウントしたディレクトリに移動
mv target/bk/db target/databases/
# 退避フォルダの削除
rm -rf bk
```

#### target/nodes/node/data/statedbディレクトリのマウント
```bash
# ディレクトリを退避
mv target/nodes/node/data/statedb target/bk
# マウントするディレクトリを作成
mkdir target/nodes/node/data/statedb
# マウントの実行
sudo mount -t nfs yyy.yyy.yyy.yyy:/var/nfs/symbol/data/statedb target/nodes/node/data/statedb
# ディレクトリ所有者の変更(ユーザ名がubuntuの場合)
sudo chown -R ubuntu:ubuntu target/nodes/node/data/statedb
# 退避した内容をマウントしたディレクトリに移動
cd target/bk/statedb
mv * target/nodes/node/data/statedb
# 退避フォルダの削除
rm -rf bk
```


### 4. ノードの起動
```bash
symbol-bootstrap start -d
```

以上でノードが起動すれば完了です。
あとは同期されるまで待ちます。

## 補足：マウントできない場合のトラブルシューティング

##### 1. IPアドレスが正しいか確認する。
IPアドレスが正しく設定されているか再度確認します。

- NFSサーバの"/etc/exports"には「**NFSクライアントのローカルIPアドレス**」を記載します。
- NFSサーバの"/etc/exports"を修正後は`exportfs -r`コマンドで変更内容を適用する。
- NFSクライアントの`mount`コマンドでは、「**NFSサーバのローカルIPアドレス**」を記載します。

##### 2. ファイアウォールのルールを確認する

マウントに成功した際のファイアウォールの設定は以下の通りです。
```bash
# 現在の設定確認
firewall-cmd --list-all
```

```text:結果
public
  target: default
  icmp-block-inversion: no
  interfaces:
  sources:
  services: dhcpv6-client mountd nfs rpc-bind ssh
  ports:
  protocols:
  masquerade: no
  forward-ports:
  source-ports:
  icmp-blocks:
  rich rules:
```

##### 3. Filewallを一時的に無効にする
下記コマンドでファイアウォールを停止してつながるか試してみて下さい。
※当然リスクを伴うので、接続できたらFirewallは起動させて別の原因を探して下さい。
```bash
systemctl stop firewalld
# 以下を実行すると再起動後も起動しなくなる
systemctl disable firewalld
```

## 補足：マウントするディレクトリを決めた経緯
今回、databasesとstatedbの2ディレクトリをマウントしましたが、それに至った経緯をつらつら書いていきます。

### targetディレクトリまるごとマウントしてみた
あえなく惨敗。ノードが起動しません。

### databasesとdataにシンボリックリンクを張って単一ディレクトリのみマウントした
これもノードが起動しません。dockerのログを見ると、シンボリックリンク先のディレクトリにアクセスできないようです。
これが解決できたら行けるかも？

### 容量を確認する
マウント対象を絞り込むため、執筆時点の各ディレクトリの容量を調べました
結果、以下のようになりました。
```
target全体:83GB

target配下：
./databases 9.2GB
./nemesis 6.2MB
./docker 72KB
./nodes 74GB!!
./gateways 24MB

target/nodes/node/data配下:
./statedb:62G

```
これにより、対象をdatabases/とtarget/nodes/node/dataにしぼりました。


### target/nodes/node/dataディレクトリまるごとマウントしてみた
こちらも最初はうまくいきましたが、しばらく同期を進めるとノードがダウンし、以後上がらなくなりました。
dataディレクトリにはharvesters.datなどのバイナリファイルも多数あるため、アクセス頻度が高いためと思われます。

また、00001など1万ブロックごとに自動生成されるディレクトリは今回は断念しました。
上記の通り、マウントするフォルダが増えるごとに色んな設定をしないと行けないので。。。

こちらもブロックのディレクトリまでNFSにマウントできたら更に容量を節約できますので、挑戦される方をお待ちしていますｗ

### 結論
- 容量が大きい
- アクセス数が少ない
- フォルダが自動生成されない

上記を満たした2ディレクトリのみマウントすることにしました。