NEM NISサーバの軽量なDockerイメージを構築してみた

タイトルの通りです。

Symbolがリリースされ、旧NEMのNIS(NEM Infrastructure Server)がオープンソース化されgithubへ公開されました。

正直なところ、よほどのスキモノかNEM1のチェーンを独自に立てて何かを成し遂げようとするツワモノくらいしかもはや利用価値なんてないだろうと思っていました。

しかし、サブチェーン利用という構想の元、ハードフォークまで行われ、意外なことにNISサーバを建てるということが再燃し始めました。

# NISサーバの入手先

NISサーバはJavaのパッケージとして提供されており、ダウンロードしてJREで実行します。

[Index of /](https://bob.nem.ninja/)

ここから、`nis-0.6.100.tgz` をダウンロードできます。

[NemProject/nis\-client: project for building nis client](https://github.com/NemProject/nis-client)

または、オープンソース化されているのでこのリポジトリから取得したソースをビルドすることでもサーバが手に入ります。

実行の仕方はここでは説明せず、紹介だけにします。
立ち上げ方の詳細は他の方の記事を参照してください。

# 公式のDockerイメージ

NEM Project公式からもDockerイメージ化するリポジトリは存在します。

[NemProject/nem\-docker: Docker configuration and scripts to run NEM software](https://github.com/NemProject/nem-docker)

しかし、このイメージには、すでに開発が停止している`NCC`という旧ウォレットソフトやスーパーノード用のモニタソフトなどが同梱されていたり、ビルドイメージが大きいです。

# 軽量なイメージ、シンプルな構成

公式のイメージはその発祥がそもそも古いものがベースとなっており、Docker自体が当時よりも高機能になっています。

現在では、マルチステージビルドを使うことで、初期セットアップに必要なツールを実行時には含めないようにしたり、実行イメージには軽量イメージを使用するなど、いろいろな工夫ができるようになりました。

リポジトリはこちらです。

[44uk/nem\-docker](https://github.com/44uk/nem-docker)


## 実行・設定ファイル

リポジトリをクローンしたら、必要に応じた設定ファイルを書きます。

設定は`./config/nis-client/config-user.properties`に置くと、記述された内容の設定行でデフォルトの値を上書きします。

```properties
nis.bootName = your_node_name
#nis.bootKey = __YOUR_BOOTKEY__
nem.host = your-node.example.com
```

よく変更するのはこのあたりの値だと思われますので、変更が必要な行だけ書いてください。

設定値の詳しい内容は他の記事を参考にしてください。

起動は`docker-compose up -d`すれば動きます。(Docker Composeも要インストール)

`restart: always`にしてあるので、(Dockerデーモンがちゃんと動けば)サーバが再起動しても勝手に立ち上がります。


# 解説

工夫したことを書き出してみます。ツッコミなどがあればコメントしていただけると幸いです。


## マルチステージビルド

今回はソースからのビルドではなく、公開されているパッケージアーカイブを使用しますが、その取得やハッシュチェックで必要なソフトはビルド用イメージだけに導入するようにしています。

[nem\-docker/Dockerfile at main · 44uk/nem\-docker](https://github.com/44uk/nem-docker/blob/main/docker/nis-client/Dockerfile#L1)

https://bob.nem.ninja/ にて公開されているアーカイブには、`nis-0.6.100.tgz.sig`というファイルも公開されています。

これには、以下のような情報が書かれています。

```
txId: 19bf0f33b7992419b54759f5bf38599adf36ee4ac0da9cafb086d9ab051df75f
block: 3471906
```

これは、ブロック 3471906 のトランザクション 19bf0f33... にアーカイブのハッシュ値が刻まれていることを指しています。

このトランザクションのメッセージには、アーカイブのハッシュ値が記録されていされていて、ファイルの検証をすることができるようになっています。

[superalice\.nemmain\.net:7890/transaction/get?hash=19bf0f33b7992419b54759f5bf38599adf36ee4ac0da9cafb086d9ab051df75f](http://superalice.nemmain.net:7890/transaction/get?hash=19bf0f33b7992419b54759f5bf38599adf36ee4ac0da9cafb086d9ab051df75f)


その検証やアーカイブの展開を行ったりしています。

[nem\-docker/Dockerfile at main · 44uk/nem\-docker](https://github.com/44uk/nem-docker/blob/main/docker/nis-client/Dockerfile#L10)

### ハッシュを取得するノードについて

アーカイブを検証するためにトランザクションのメッセージを取得する際に、アクセスするノードがつながらないと、ビルドに失敗してしまいます。

- http://superalice.nemmain.net:7890

これを回避するために、ビルド時には引数で接続先ノードを変えられるようになっています。

```shell
$ docker build -t nis-client ./ --build-arg NODE_URL=http://superalice.nemmain.net:7890
```

- [nem\-docker/docker\-compose\.yml at main · 44uk/nem\-docker](https://github.com/44uk/nem-docker/blob/main/docker-compose.yml#L9)

`NODE_URL`引数で別のノードを指定してみてください。

```yml
   - NODE_URL=http://つながるノード
```

- [nem\-docker/docker\-compose\.yml at main · 44uk/nem\-docker](https://github.com/44uk/nem-docker/blob/main/docker-compose.yml#L8)

`docker-compose.yml`なら`args`に追記してください。

ノードは次のノードリストより探してください。

- [NIS1 node list](https://nemnodes.org/nodes/)
- [NEM \- BlockChain Explorer](https://explorer.nemtool.com/#/nodelist)


## 軽量イメージ

実行用のイメージには`gcr.io/distroless/java:11`を採用してみました。

そのまま使えるJava環境としては最軽量ではないでしょうか？

ビルドイメージからダウンロードして検証が済み、展開したNISサーバをコピーしてきます。

[nem\-docker/Dockerfile at main · 44uk/nem\-docker](https://github.com/44uk/nem-docker/blob/main/docker/nis-client/Dockerfile#L24)

これにより、NISサーバのファイルも合わせておおよそ250MB前後に納めることができました。


## カスタムJREの利用(未完)

さらに軽量なイメージを構築するために、カスタムJREの利用に挑戦してみました。

しかし、結果としてはあまりうまく行かず、達成できなかったため、前述の軽量イメージを採用しています。

NISサーバは`Java 8`に向けて書かれているようです。

なぜそんな古いバージョンで…と思うかもしれませんが、Symbolの開発が開始して、NISの開発が停止した時期がおおよそ2017年中で、`Java 9`は2017年9月21日にリリースされています。

その当時からすれば、新しいメジャーバージョンが出たばかりで、かつSymbolの開発に入り始めたため、バージョンに追従するモチベーションがなかったのでしょう。

[Javaバージョン履歴 \- Wikipedia](https://ja.wikipedia.org/wiki/Java%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E5%B1%A5%E6%AD%B4)

それが原因なのか、単に自分が普段Javaをいじらないので、なにかをミスっていただけなのかわかりませんが、うまくいきませんでした。

これが出来ると、100MB程度のイメージに納めることが出来る可能性があるので、知見がある方は是非教えていただきたいです。

コード側が対応していないということであれば、サブチェーン化に伴って、開発が再開したら、バージョンアップに期待したいところです。


# おわりに

スーパーノードのエージェントやHTTPSへの対応など、盛り込みたいことがあり、作業中の部分や検証が足りていないことが多いのですが、このソースやイメージの構築方法は最終的に公式の方で採用してもらう方向で動いてみようと思います。


サブチェーンとしての利用価値とOSS化によって、今後はバージョンアップが進むかもしれません。

だからこそ、Docker(またはPodman)さえ使えれば動くというコンテナ時代にきちっと対応して、スマートなNISサーバに生まれ変わっていって欲しいものです。

Symbolだけでなく、こちらにもフォーカスが当たるように情報を追いかけて見たいと思います。