GCP(Google Cloud Platform)でNEMの次期バージョンSymbolのテストネットのノードを構築する手順(Ubuntu 18.04)

本記事は、作成後、度重なる破壊的変更が加えられたため、申し訳ありませんが参考になりません。
他の資料を参考にしてくださいますようよろしくお願いします。

# Let's 築城 on GCP !

## きっかけ

### NEM SEMINAR 2020

先日、NEM SEMINAR 2020にて、NEM関連の様々なお話を伺ってきたのですが、その中にノード運営に関する内容がありました。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ノードの構築は複雑化したが、Dockerで管理するためのbootstrap等のツールが整備された側面もある<br><br>「築城しましょう。」にはクスッときたwww<a href="https://twitter.com/hashtag/nem_seminar?src=hash&amp;ref_src=twsrc%5Etfw">#nem_seminar</a> <a href="https://t.co/vlnI6dLW00">pic.twitter.com/vlnI6dLW00</a></p>&mdash; 松岡靖典 (@salaryman_tousi) <a href="https://twitter.com/salaryman_tousi/status/1218795608003117056?ref_src=twsrc%5Etfw">January 19, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

「築城」というパワーワードがすごく印象に残り、私もやってみようと思いました。

### コア開発者のJaguarさんのSlackコメント

コア開発者の方が以下のようなコメントをSlackにされていたとのお話を聞きました。

![1579698504スクリーンショット 2020-01-22 22.07.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324152/832d5ba4-69f7-dea2-cf94-6e8f26e4b280.png)

テストネットのノードが1000ノード以上稼働するには、手順が詳細に説明された記事があるといいな...と思い、この記事を書きました。

結論としては、そこそこ簡単にテストネットのノードをたてることができたので、非エンジニアの方も果敢にチャレンジしてみて頂けると嬉しいです。

さて、前置きはこれくらいにして、さっそく築城を開始していきましょう！

# 築城手順

## 大まかな流れ

1. GCP (Google Cloud Platform)上に新規プロジェクトを作成
2. GCE (Google Compute Engine)VMインスタンスを作成(≒仮想マシン(≒サーバー)をクラウド上に用意する)
3. 作成したVMインスタンスへの接続
4. VMインスタンス上に環境構築(Docker, Docker Composeのインストール)
5. ファイアーウォールルールの作成とVMインスタンスへの設定
6. Symbolのテストネットのノード構築ツールをGitで導入し、ノードを起動
7. ノードの稼働状態をVMインスタンスのローカル上で確認(/chain/heightを叩いて確認)
8. 外部IPアドレスをエフェメラルから静的に変更
9. /node/infoで表示される"host", "friendlyName"を適切に設定

## 詳細な手順

### 1. GCP(Google Cloud Platform)上に新規プロジェクトを作成

1. まずは新規プロジェクトを作成しましょう。プロジェクト名を入力し、場所も必要に応じて選択して、`作成`ボタンをクリックしてください。もし、設定値に迷う場合は、以下の設定例をそのまま使って手順を進めてみてください。作成後、少し待つとプロジェクトの作成が完了するので、その後、次の手順に進んでください。
    - 設定例
        - プロジェクト名
            - `symbol-testnet-node`
        - 場所
            - 特にこだわりが無ければデフォルトの「組織なし」でOK

### 2. GCE(Google Compute Engine)VMインスタンスを作成

1. 少し待つとプロジェクトの作成が完了します。そうすると、プロジェクトを選択するプルダウンリストから先ほど作成したプロジェクト(設定例の通りなら`symbol-testnet-node`)が選択できるようになっているので、選択しましょう。
- その状態で、画面左上のナビゲーションメニューを表示させる三本線のボタンをクリックし、その中の`コンピューティング`の項目内の`Compute Engine`にカーソルをあわせ、出てくるメニューの中の`VMインスタンス`をクリックしましょう。
- Compute Engineが使えるようになるまで少し待ちましょう。1分くらいのイメージです。Compute Engineが使えるようになると、VMインスタンスと表示されている箇所の近くの`作成`ボタンがクリックできるようになっていると思うので、クリックしてVMインスタンスを作成していきましょう。
- 設定例を以下にまとめますので、迷う場合はそのまま使って手順を進めてみてください。設定例で触れていない項目は、特に何もする必要は無いと思います。
    - 名前
        - symbol-testnet-api-1
    - リージョン
        - asia-northeast1 (東京)
    - ゾーン
        - asia-northeast1-b
    - マシンの構成
        - マシンファミリー
            - 汎用
        - シリーズ
            - N1
        - マシンタイプ
            - n1-standard-2 (2 vCPU, 7.5 GBメモリ)
            - 2020/03/07に再確認したところ、ノードのマシンスペックの要求が緩和され、2CPU以上、4GB以上となっていたため、カスタムからメモリを4GBに設定する等の設定でコストが節約できるかもしれません。
    - ブートディスク
        - `変更`ボタンをクリックし、Ubuntu 18.04 LTSのラジオボタンにチェックを入れ、サイズ(GB)欄に40と入力し、`選択`ボタンをクリック
    - ファイアウォール
        - `Httpトラフィックを許可する`にチェックを入れる
        - `Httpsトラフィックを許可する`にチェックを入れる
- 上記を参考に設定ができたら、`作成`ボタンをクリックしてVMインスタンスを作成しましょう。
- 画面が切り替わって、作成中のインスタンスがリスト表示された画面が表示されると思います。インスタンス作成が完了すると名前の左横に緑色のチェックマークが表示されるので、それが確認できたら、次の手順に進みましょう。

### 3. 作成したインスタンスへの接続

- リスト表示されたVMインスタンスの`接続`列のプルダウンから`ブラウザウィンドウで開く`をクリックすると、VMインスタンスに接続する黒い画面がブラウザで開きます。以降の操作はこちらの黒い画面を中心に行います。

### 4. 環境構築

#### Dockerのインストール

オフィシャルな手順はこちら( https://docs.docker.com/install/linux/docker-ce/ubuntu/ )ですが、英語なので、以下に必要な情報をまとめておきます。

記載してある通りの順序でコマンドを実行していけば、問題ありません。黒い画面にコピペして、`Enter`で順番に実行してみてください。

注意点として、途中、以下のような質問が表示され、処理が一時停止する箇所があるかもしれません。その場合は、Yと入力して`Enter`で処理を継続してください。

<pre>Do you want to continue? [Y/n]</pre>

1. OS内の全ソフトウェアの更新チェック<pre>sudo apt-get update</pre>
2. Dockerインストールの前提となる各種ツールのインストール
<pre>
sudo apt-get install \
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common
</pre>
3. Dockerのダウンロード元のURL、公開鍵の登録<pre>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</pre>
    - `OK`と表示されればOK
4. Dockerのダウンロード元の正当性の検証
    - 以下コマンドを実行して
<pre>sudo apt-key fingerprint 0EBFCD88</pre>
    - 表示される内容が以下と一致しているか確認
<pre>
pub   rsa4096 2017-02-22 [SCEA]
      9DC8 5822 9FC7 DD38 854A  E2D8 8D81 803C 0EBF CD88
uid           [ unknown] Docker Release (CE deb) <docker@docker.com>
sub   rsa4096 2017-02-22 [S]
</pre>
5. OSにDockerの最新のステーブルバージョンのURLを追加
<pre>
sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"
</pre>
6. OSのソフトウェア情報参照先を再度更新
<pre>
sudo apt-get update
</pre>
7. Dockerをインストール
<pre>
sudo apt-get install docker-ce docker-ce-cli containerd.io
</pre>
8. Dockerのバージョン確認のコマンドを実行し、バージョンが表示されれば成功
    - バージョン確認のコマンド
<pre>
docker --version
</pre>
    - 確認結果の例
<pre>
Docker version 19.03.5, build 633a0ea838
</pre>

#### Docker Composeのインストール

オフィシャルな手順はこちらのページの中のLinuxタブ( https://docs.docker.com/compose/install/ )の通りですが、英語なので、以下に必要な情報をまとめておきます。

記載してある通りの順序でコマンドを実行していけば、問題ありません。黒い画面にコピペして、`Enter`で順番に実行してみてください。

注意点として、途中、以下のような質問が表示され、処理が一時停止する箇所があるかもしれません。その場合は、Yと入力して`Enter`で処理を継続してください。

<pre>Do you want to continue? [Y/n]</pre>

1. Docker Composeのインストール
<pre>
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.3/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
</pre>
2. 実行権限の設定
<pre>
sudo chmod +x /usr/local/bin/docker-compose
</pre>
3. Docker Composeのバージョン確認のコマンドを実行し、バージョンが表示されれば成功
    - バージョン確認のコマンド
<pre>
docker-compose --version
</pre>
    - 確認結果の例
<pre>
docker-compose version 1.25.3, build d4d1b42b
</pre>

### 5. ファイアーウォールルールの作成とVMインスタンスへの適用

Symbolテストネットノードはhttpノードでは、API接続用に3000番、ノード同士の通信用に7900番、APIブローカー用に7902番のポートを使用するため、これらのポートについては明示的にポートを開けて通信可能となるよう、ファイアーウォールルールの作成と、それをVMインスタンスへ適用する手順を先に実行しておくとよいでしょう。

#### ファイアーウォールルールの作成

1. `ファイアウォールルール`をクリックし、+マークのある`ファイアウォールルールの作成`をクリックしてください。
2. 出てきた画面でポートNo. 3000, 7900, 7902の開放の設定を行います。設定値に自信が無い方は以下の設定例をそのままご利用ください。設定例に記載していない内容は、おそらくデフォルトでよいと思います。設定内容が入力できたら、`作成`ボタンをクリックしてください。なお、`作成`ボタンをクリックする前に、ターゲットタグの値をコピーしておくと後の手順が楽です。
    - 設定例
        - 名前
            - `symbol-testnet-http-allow`
        - トラフィックの方向
            - `上り`
        - 一致したときのアクション
            - `許可`
        - ターゲット
            - `指定されたターゲットタグ`をプルダウンで選択
        - ターゲットタグ
            - `symbol-testnet-http-allow`　... この値は後で使うのでコピーしておきましょう。
            - ここに設定した値は、このファイアウォールルール自体を表すタグの名称となり、このタグの名前をVMインスタンス側に設定するという流れになります。(その手順は後述してあります。)
        - ソースフィルタ
            - IP範囲
        - ソースIPの範囲
            - `0.0.0.0/0`
        - プロトコルとポート
            - `指定したプロトコルとポート`のラジオボタンにチェック
                - `tcp`にチェック
                - `tcp`の右横の入力欄に`3000,7900,7902`と入力

#### ファイアウォールルールをGCE (Google Compute Engine)のVMインスタンスに適用

1. 画面左上のナビゲーションメニューを表示させる三本線のボタンをクリックし、その中の`コンピューティング`の項目内の`Compute Engine`にカーソルをあわせ、出てくるメニューの中の`VMインスタンス`をクリックしてください。
2. 対象のVMインスタンスの名前(設定例通りなら`symbol-testnet-api-1`)をクリックし、出てきた画面で、上の方にある`編集`をクリックしてください。
3. `ネットワークタグ`という項目(下の方にスクロールしなければ見つけられないかもしれません)に、先ほどコピーした`ターゲットタグ`の値(設定例の通りなら`symbol-testnet-http-allow`)を入力し、一番下の`保存`ボタンをクリックします。

### 6. Symbolのテストネットのノード構築ツールを導入し、ノードを起動

オフィシャルな手順はこちら( https://nemtech.github.io/ja/guides/network/running-a-test-net-node.html )ですが、APIノード+Peerノードの構成でノードを起動するか、Peerノードのみの構成でノードを起動するかの場合分け等が、事情を知らない方からは少しわかりにくいかもしれません。

Peerノードのみの構成では、適切にノードが稼働しているかどうか確認がしにくいため、通常であればAPIノード+Peerノードの構成でノードを起動したほうがよいでしょう。

以下にAPIノード+Peerノードの構成でノードを構築する手順を整理しておきますので、オフィシャルな手順で確信を持てなかった方は、こちらをご参照ください。

1. GitHubから必要なツールをクローン
<pre>git clone https://github.com/nemfoundation/symbol-testnet-bootstrap.git</pre>
2. APIノード+Peerノードの構築のためのフォルダに移動
<pre>
cd symbol-testnet-bootstrap
</pre>
<pre>
cd api-harvest-assembly
</pre>
3. Docker Composeを実行
<pre>
sudo docker-compose up --build --detach
</pre>
色々動いて、それらが終わったら、ノードの起動は完了です。一番最後はこんな感じの表示があると思います。
<pre>
Creating api-harvest-assembly_db_1                     ... done
Creating api-harvest-assembly_store-addresses_1        ... done
Creating api-harvest-assembly_generate-raw-addresses_1 ... done
Creating api-harvest-assembly_api-node_1               ... done
Creating api-harvest-assembly_api-broker_1             ... done
Creating api-harvest-assembly_update_vars_1            ... done
Creating api-harvest-assembly_init-db_1                ... done
Creating api-harvest-assembly_rest-gateway_1           ... done
</pre>

### 7. ノードの稼働状態をVMインスタンスのローカル上で確認

ノードの状態を確認するには、以下のコマンドをそのまま実行してみるとよいでしょう。

<pre>
curl http://localhost:3000/chain/height
</pre>

上手くノードが起動できていれば、以下のような結果が表示されると思います。

<pre>
{"height":"16001"}
</pre>

ノードのブロック高さを確認する`curl http://localhost:3000/chain/height`を何回か連続で実行してみると、すごい勢いで結果の数字が増えていっているのがわかると思います。他のノードの最も進んだブロックの高さに少しずつこの数字が近づいていきます。

参考までに、私が立ててみたテストネットのノードのブロック高さを確認できるURLを以下に置いておくので、そろそろ追いついたかな～といった確認の際には、ご活用ください。
https://symbol-testnet-api-2.next-web-technology.com:3001/chain/height

### 8. 外部IPアドレスをエフェメラルから静的に変更

さて、ここまでで、テストネットのノードは起動し、ノードが動いているVMインスタンスのローカル環境からでも、外部からでもテストネットのAPIにアクセスできる体制になりました。

ただ、外部IPアドレスはデフォルトの設定では、エフェメラルという設定になっており、仮想マシンの再起動等が発生した場合IPアドレスは変更になってしまう可能性があります。後述する手順で、ノードが公開する情報として外部IPアドレスを登録するので、再起動の度にIPアドレスが変わってしまうのは都合が悪いと思います。そこで、再起動後も同じIPアドレスが変わらず使用できるよう、あらかじめそのVMインスタンスにそのIPアドレスを割り当てるという予約をしておきましょう。

1. 画面左上のナビゲーションメニューを表示させる三本線のボタンをクリックし、その中の`ネットワーキング`の項目(かなり下の方にあるのでスクロールするしてあげる必要があると思います)内の`VPCネットワーク`にカーソルをあわせ、出てくるメニューの中の`外部IPアドレス`をクリックしてください。
- そこにある外部IPアドレスの`タイプ`をプルダウンで`エフェメラル`から`静的`に変更してください。
- その際出てくるダイアログでは、そのIPアドレスの予約設定に名前が要求されます。迷った方は次のような名前を入力して`保存`ボタンをクリックしてください。説明は省略可能ですので空欄でもよいでしょう。
    - 設定例
        - `symbol-testnet-api-1`

ファイアーウォールルールの設定が完了していれば、以下のようなURLで自分のノードのブロック高さが確認できると思います。IPアドレスの箇所は自分の環境の値に読み替えて試してみてください。

http://34.97.95.214:3000/chain/height

### 9. /node/infoで表示される"host", "friendlyName"を適切に設定

この記事最後の項目です。ノードの設定項目として、`host`と`friendlyName`という項目があり、デフォルトの設定のままノードを起動すると、これらの値が`host`は空白に、`friendlyName`は何か謎の値が入っているという状態になります。

ここを適切に再設定するため、一旦ノードを停止させ、設定ファイルを編集して、再度ノードのサービスを開始するという手順を実行する必要があるようです。

~~ここの手順は「本当に必要？」かつ「イマイチ...」という印象を持ちました。(host = ホスト名？が必要なら、ノードの起動プロセスで自動で取ればいいのでは？と思ったのと、friendlyNameはニックネームとしてユーザーがつけるとすると、ノードの起動前に設定ファイルに記載してノードを起動すれば一発でノードの起動が完了するのでは？と思いました。設定ファイルはノードの初回起動前には存在しておらず、何か制約があるのかな？と疑問を感じました。~~ (2020/02/15追記：hostには外部から接続可能な情報としてIPアドレスかフルコンピューター名(yahoo.co.jp的なもの)を登録する必要があり、friendlyNameは単純に識別のためで、半角文字であれば特に値に制約は無いという状況のようです。)

1. ノードを停止
<pre>
sudo docker-compose down
</pre>
2. 設定ファイル(`config-input.yaml`)の編集
    - 設定ファイルの場所へ移動
        - この記事の流れに沿って作業を進めていたなら、現在`api-harvest-assembly`フォルダの中にいると思います。その場合、以下コマンドで、設定ファイル`config-input.yaml`が配置してあるフォルダ()に移動できると思います。移動したら設定ファイルがそのフォルダにあることを確認しておきましょう。
            - フォルダ移動コマンド
<pre>
cd ..
</pre>
<pre>
cd identity
</pre>

            - そのフォルダのファイルやフォルダを表示するコマンド
<pre>
ls
</pre>
`config-input.yaml`の表示があればOK
    - 設定ファイルの編集
        - 黒い画面上での編集方法
            - nanoを使用する場合のコマンド
<pre>
sudo nano config-input.yaml
</pre>
            - 編集箇所
                - friendlyName
                    - 変更前
<pre>
friendly_name: 
</pre>
                    - 変更後(設定例)
<pre>
friendly_name: symbol-testnet-api-1 
</pre>
                    - 上書き保存して閉じる
                        - `Ctrl` + `X`
                        - `Y`と入力して`Enter`
                        - ファイル名はそのままで`Enter`で上書き保存&閉じる

3. 設定ファイル(`config-node.properties.template`)の編集
    - 設定ファイルの場所へ移動
        - この記事の流れに沿って作業を進めていたなら、現在`identity`フォルダの中にいると思います。その場合、以下コマンドで、設定ファイル`config-node.properties.template`が配置してあるフォルダに移動できると思います。移動したら設定ファイルがそのフォルダにあることを確認しておきましょう。
            - フォルダ移動コマンド
<pre>
cd ..
</pre>
<pre>
cd api-harvest-assembly
</pre>
<pre>
cd api-node
</pre>
<pre>
cd userconfig
</pre>
<pre>
cd resources
</pre>

            - そのフォルダのファイルやフォルダを表示するコマンド
<pre>
ls
</pre>
`config-node.properties.template`の表示があればOK
    - 設定ファイルの編集
        - 黒い画面上での編集方法
            - nanoを使用する場合のコマンド
<pre>
sudo nano config-node.properties.template
</pre>
            - 編集箇所
                - host
                    - 変更前
<pre>
host = 
</pre>
                    - 変更後(設定例)...外部IPアドレスは皆さんの環境にあわせて設定してください
<pre>
host = 34.97.95.214
</pre>
                    - 上書き保存して閉じる
                        - `Ctrl` + `X`
                        - `Y`と入力して`Enter`
                        - ファイル名はそのままで`Enter`で上書き保存&閉じる

4. `docker-compose.yaml`があるフォルダまで戻って、再度ノードのサービスを開始

ひとつ上のフォルダに戻るコマンド(3回繰り返すと、そのフォルダに戻れる)
<pre>
cd ..
</pre>

ノードを再始動するコマンド
<pre>
sudo docker-compose up --build --detach
</pre>

これで、host, friendlyNameともに、適切に設定された状態で、ノードが構築でき、外部からIPアドレスでのAPIアクセスができるようになりました。

http://34.97.95.214:3000/node/info

# 所感

手順書にするとかなりのボリュームになってしまったのですが、実際の作業としては、かなり簡単にブロックチェーンのノードを建てられる印象を感じました。

AWSのノード構築自動化スクリプトを公開してくださった方もいらっしゃるので、AWSでの築城も良いかもしれません。

疑問点や間違っている点等ありましたら、お気軽にコメント頂けますと幸いです。

皆さんの築城活動によって、メインネットローンチ前に、しっかりとテストネットをしばき倒すことができ、問題を見つけることができ、問題が事前に修正された、より良いメインネットローンチにつなげられることを祈っています。

さあ、皆さんも「Let's 築城！」

# 参考にさせて頂いた情報

- Symbolテストネットに関する情報のまとめ
    - https://jp-nem-dev.growi.cloud/testnet
- Catapultテストネットノードの構築スクリプトを作りました。(AWS EC2 Amazon Linux2 向け)
    - https://nemlog.nem.social/blog/36829
- GCP(GCE)+ubuntu18.04LTSでSymbolノード立ててみた
    - https://nemlog.nem.social/blog/38049
- Symbol testnet 構築後 https 対応
    - https://www.u2yasan.com/ja/content/20200213/79

# 追記記録、予定

- 実際の運用では、IPアドレスを直接指定する方法ではなく、ドメインを割り当てて、文字列のURLで運用したいでしょう。ドメインの設定についても、どこかで追記したいと思います。
- 本番環境ではhttpsノードが必要とされると思います。SSLの設定を行い、httpsノードにする手順についても、どこかで追記したいと思います。
- 2020/01/30追記 「GitHubから必要なツールをクローン」の箇所で参照しているツールの新しいものが出たようです。手順としての変更点はgit cloneの際のURLが変更となった点、git cloneで作成されるフォルダ名がcatapult-testnet-bootstrapからsymbol-testnet-bootstrapに変更となった点が挙げられます。オフィシャルな手順の説明ページの情報も新しいツールを使用する方法に変更済のようです。本記事内も新しいツールsymbol-testnet-bootstrapを使用する手順に修正してありますのでご承知おきください。
- 2020/02/08追記修正　ファイアーウォールの設定でAPI用に3000番だけ明示的にノード起動後に開けるような手順となっていましたが、ノード同士の通信で7900番が使用されるはずで、ここを事前に明示的に開けていなかったのが、ノード再起動時にブロック更新が止まってしまう原因の一つではないかと考え、ブートストラップツールを初回実行する前に7900番、3000番ともに開けておくような手順に修正しました。
- 2020/02/15追記修正　ファイアーウォールの設定でAPIブローカー用に7902番も開放するような手順に修正し、一つのファイアーウォールルールでまとめて3000, 7900, 7902番を開放するような手順に修正しました。
- 2020/05/27追記修正　どのバージョンアップの時かは把握できていないのですが、設定ファイルのパスが変わっていたので修正しました。