こちらの続きです:
HATOYA の Docker イメージを公開
また、そもそもこのようなデータベースプラットフォームを開発しようと考えた背景的なものはこちらのブログエントリで綴っています。こちらも合わせて参照ください:
開発者視点で「理想的なブロックチェーン」とは?
↑上述のブログエントリでブロックチェーン対応 RESTful データベースプラットフォームである HATOYA とその REST API 、また公開している docker イメージをシングルノードで使う方法を紹介しました:

アプリケーション開発者が対応アプリケーションを開発するだけの目的であればシングルノードでも充分だと考えていますが、実際に運用(特にブロックチェーンネットワークを運用)する際においてはマルチノードで運用するケースが多いと考えています。ということで、本ブログエントリでは同じ docker イメージを使ってマルチノードで HATOYA ネットワークを構築する方法を紹介します:

まず、以下で紹介する HATOYA ネットワークのトポロジーは以下のように定義するものと仮定します:

このようなブロックチェーンネットワークを定義するための各ノードの設定内容を紹介していきます。
まず、今回3つのサーバーノードを docker コンテナとして起動しますが、docker 上のコンテナが同期を取る際にコンテナ間でネットワーク通信する必要があります。したがって docker 上に構成する複数のサーバーノードは同一の docker ネットワーク上で作成する必要があります。というわけで、まずは hatoya-network という docker ネットワークを作成しておきます:
次に3つのサーバーノードコンテナを同一の hatoya-network ネットワーク上で、それぞれポート番号 14126, 24126, 34126 で起動します。また docker 上での名前をそれぞれ hatoya1, hatoya2, hatoya3 とします。この時点では3つの HATOYA サーバーがそれぞれ単独で起動される状態となります:
これで docker 上にコンテナ通信可能な3つの HATOYA ノードが作成・起動できました。
次にブロックチェーン同期のための設定を各ノードに加えます。まずノード1は自身のブロックチェーンに変更があった場合、即時にノード3のブロックチェーンに同期リクエストを発行する必要があります。そのための設定項目を追加します。
ノード1のダッシュボードを開き(http://xx.xx.xx.xx:14126/)、左ペインから (Config) と書かれた項目を選択します。右ペインにはノード1のネットワーク設定一覧が表示されますが、この時点では何も設定されていないはずです(新規追加用のフィールドがあるだけです):

ここにノード3のブロックチェーンへ同期リクエストを行うための設定を追加します。右ペイン内の新規追加フィールド内に以下の JSON テキストを記述して "Save" ボタンをクリックします(赤字は説明用のコメントなので不要です)。リクエスト送信元では URL キーで同期リクエスト先(今回はノード3)の URL を指定ような設定を行います:

正しく設定が保存されると、設定一覧が更新され、以下のように1件追加されます(表示されている文字列は自動追加された ID です):

ID 部分をクリックすると設定内容を表示することができます(もう一度クリックすると省略表示に戻ります):

これでノード1のブロックチェーン更新時にノード3のブロックチェーンに同期リクエストが発行されるようになりました。ただこれだけでは同期されません。正しく同期するにはノード3側にもこの同期リクエストを受け付けるための設定が必要です。
その設定をする際にリクエスト元であるノード1の serverid 情報が必要になります。このタイミングで確認しておきましょう。サーバーノードの serverid はダッシュボード画面左上の鳩マーク部分をマウスホバーすると表示されます。この値をこの後使うのでメモしておきます:

改めて、今度はノード3のダッシュボード(http://xx.xx.xx.xx:34126)を開き、(Config) を選択して設定一覧の画面を開きます。ノード3も起動直後であれば、この時点では設定項目は何もないはずです:

ここに新しい設定を以下の JSON テキストの内容で追加(Save)します。なお serverid 値は先程確認した同期リクエスト元の serverid を指定する必要があります。同期リクエスト先ではリクエスト元の serverid を明示的に指定することであらかじめ想定したノードからのリクエストのみを受け付けることができるよう調整できます:

正しく保存できるとノード3の設定一覧が更新され、指定した serverid からの同期リクエストを処理するための設定が追加されます:

このペアとなる設定でノード1のブロックチェーンが更新された時にノード3のブロックチェーンと同期を取るための設定ができあがりました。このように同期リクエストを発行する側ではリクエスト先の URL を、受ける側ではリクエスト元の serverid を指定して、両方設定済みの場合のみ同期が行われる点に注意してください。
(今回は設定しませんが)同様にしてノード3のブロックチェーンが更新された時にノード1と同期する場合は今の逆の設定を行います。ノード3の Config にノード1の URL を指定した設定を追加し、ノード1の Config にノード3の serverid を指定した設定を追加することで双方向の同期が実現できます。
続いてノード2とノード3の同期設定を行います。ここでの設定内容は「1分おきにノード2からノード3へ同期リクエストを送る」です。同期リクエストを受けるノード3側はノード1の時とほぼ同様の設定をするだけですが、同期リクエストを送信するノード2側の設定を「ブロックチェーンが更新されたら」ではなく「1分おき」に変更する必要があります。
ではその具体的な方法を紹介します。ノード2のダッシュボードを開き(http://xx.xx.xx.xx:24126)、(Config) を選択して設定一覧の画面を開きます。ノード2も起動直後であれば、この時点では設定項目は何もないはずです:

ここに新しい設定を以下の JSON テキストの内容で追加(Save)します。先程と異なり同期リクエスト先 URL に加えて、"cron" というキーで同期タイミングを cron フォーマットで指定します。"* * * * *" は「1分おき」を意味しています:

正しく保存できると一覧が更新されます。"url" と "cron" 指定がある設定は「指定先 URL に cron 指定のタイミングで定期的に同期リクエストを送信する」というものです。またこの cron 指定はいわゆるスケジュール実行の crontab と同じフォーマットを利用します。「1分」おき以外にも「毎時○分」とか「毎週○○曜日の××時」のような指定も可能です:

後はこのノード2からの同期リクエストを受けるための設定をノード3側に追加します。こちらはノード1からの同期リクエストを受ける設定と同様です。ノード2の serverid を調べ、その値を serverid キーに指定して保存します(つまりノード3の設定項目は2つになります):

これで目的のブロックチェーンネットワークを構築するための設定が完了しました。なお最後の設定を保存することでノード2のブロックチェーンとノード3のブロックチェーンは1分おきに同期が取られるようになるため、これまでの (Config) 項目を変更した際のブロックチェーンも同期されることになります。1分程度待ってからノード2とノード3のブロックチェーン一覧を確認すると、ノード2とノード3の Config を追加した内容が記録され、同期されている(同じ3つのブロックになっている)はずです:

一方ノード1のブロックチェーンのみ、まだ(同期が行われていないため)単独の内容になっているはずです。ではノード1にブロックを追加して、ノード3と同期してみます。ノード1のダッシュボードを開いて左ペインのデータベース作成フィールド(new db と表示されているフィールド)に "db1" を指定して "New" をクリックします("db1" というデータベースを作ります)。この処理がノード1のブロックチェーンに記録されると共にノード3へブロックチェーンの同期リクエストが送信されて同期されます。そのためノード1のブロックチェーンはノード1、ノード2、ノード3の変更記録が全て記録された、5つのブロックで構成されます(ノード3のブロックチェーンも同じ内容になります):

また、この直後(ノード1に db1 データベースを追加した直後)ではノード2のブロックチェーンに変化はありませんが、1分程度経過するとノード1との同期が行われたノード3のブロックチェーンと再度同期されるため、ノード2のブロックチェーンも他の2つと同じ5つのブロックからなるブロックチェーンに変わるはずです。これで全てのノードの内容が同期されることになります。
以上が HATOYA をマルチノード運用する場合の設定例となります。もちろん4ノード以上で運用することもあるでしょうし、全て同一ホストの docker ネットワーク上で構成する必要もありません。あくまで同期設定の URL で正しい(ポート番号までを含めた)オリジンが指定されていれば同期できます。HATOYA ネットワークにノードを参加させたい場合は同期リクエストを送る側と受ける側両方に設定が必要(一方的な設定でネットワークに参加することはできない)な点に注意してください。
最後に、この設定方法の特徴として、「プライベートネットワークから HATOYA ネットワークに参加する」ことも可能になっている点を紹介します。上の例では3ノードを全て同一の docker ネットワーク上に作成して説明しましたが、必ずしも同一ネットワーク上に作る必要はなく、また全ノードがパブリックネットワークに存在している必要はありません。同期リクエストを送信する際の設定項目の中で同期リクエスト先の正しい URL を指定できていること(と、同期リクエスト元の正しい serverid を指定すること)だけが条件になっているので、同期リクエスト送信ノードはプライベートネットワーク上に存在していてもよい(同期リクエスト受信ノードから送信ノードにアクセスできなくてもよい)という副産物的な特徴があります。事実、上の例でいえばノード3はノード1やノード2から URL でアクセスできる場所に存在している必要がありますが、ノード1やノード2は他のノードから直接参照できる場所に存在している必要はなく、それぞれ別のネットワーク上に存在していても構いませんし、それがプライベートネットワークであっても構いません。この特徴によって HATOYA ではプライベートネットワークからブロックチェーンに参加することも可能になり、既存のネットワーク構成(の変更)を意識することなくブロックチェーンネットワークが実現しやすいという特徴があります:

以上が HATOYA のブロックチェーンネットワーク構築の例となります。ノードの数が増えたり、その同期トポロジーや同期タイミングを複雑にしたり、一度作成したネットワークに新たにノードを追加するようなこともあると思っていますが、基本的には上述の応用でカバーできると思っています。
また HATOYA の場合、マルチノードネットワークにしておくと、サーバーノードの故障時や増強時などにブロックチェーンからデータベースをリストアするという特徴的な機能も実装済みだったりします。そのあたりはいずれ別の機会に紹介したいと思っています。
HATOYA の Docker イメージを公開
また、そもそもこのようなデータベースプラットフォームを開発しようと考えた背景的なものはこちらのブログエントリで綴っています。こちらも合わせて参照ください:
開発者視点で「理想的なブロックチェーン」とは?
↑上述のブログエントリでブロックチェーン対応 RESTful データベースプラットフォームである HATOYA とその REST API 、また公開している docker イメージをシングルノードで使う方法を紹介しました:

アプリケーション開発者が対応アプリケーションを開発するだけの目的であればシングルノードでも充分だと考えていますが、実際に運用(特にブロックチェーンネットワークを運用)する際においてはマルチノードで運用するケースが多いと考えています。ということで、本ブログエントリでは同じ docker イメージを使ってマルチノードで HATOYA ネットワークを構築する方法を紹介します:

まず、以下で紹介する HATOYA ネットワークのトポロジーは以下のように定義するものと仮定します:
- サーバーノードは3つ(それぞれノード1、ノード2、ノード3と呼ぶ)。それぞれが個別のデータベース・サーバーとなっており、ブロックチェーンのみネットワークで同期する
- (docker でネットワークを構築することを想定し)3つのサーバーノードの IP アドレスは全て同一とする。またポート番号はそれぞれ 14126、24126、34126 とする
- ノード1上でブロックチェーンに更新があると、その情報はノード3のブロックチェーンと同期する
- ノード2上でブロックチェーンに更新があってもなくても、1分おきにノード3のブロックチェーンと同期する
- ノード3上でブロックチェーンに更新があっても、同期しない(他ノードからの同期リクエストを待つだけ)
- ノード1とノード2間は直接の同期パスは存在しないが、ノード3を介して情報が同期される

このようなブロックチェーンネットワークを定義するための各ノードの設定内容を紹介していきます。
まず、今回3つのサーバーノードを docker コンテナとして起動しますが、docker 上のコンテナが同期を取る際にコンテナ間でネットワーク通信する必要があります。したがって docker 上に構成する複数のサーバーノードは同一の docker ネットワーク上で作成する必要があります。というわけで、まずは hatoya-network という docker ネットワークを作成しておきます:
$ docker network create hatoya-network
次に3つのサーバーノードコンテナを同一の hatoya-network ネットワーク上で、それぞれポート番号 14126, 24126, 34126 で起動します。また docker 上での名前をそれぞれ hatoya1, hatoya2, hatoya3 とします。この時点では3つの HATOYA サーバーがそれぞれ単独で起動される状態となります:
$ docker run -e PORT=14126 --name hatoya1 --network hatoya-network -d -p 14126:14126 dotnsf/hatoya $ docker run -e PORT=24126 --name hatoya2 --network hatoya-network -d -p 24126:24126 dotnsf/hatoya $ docker run -e PORT=34126 --name hatoya3 --network hatoya-network -d -p 34126:34126 dotnsf/hatoya
これで docker 上にコンテナ通信可能な3つの HATOYA ノードが作成・起動できました。
次にブロックチェーン同期のための設定を各ノードに加えます。まずノード1は自身のブロックチェーンに変更があった場合、即時にノード3のブロックチェーンに同期リクエストを発行する必要があります。そのための設定項目を追加します。
ノード1のダッシュボードを開き(http://xx.xx.xx.xx:14126/)、左ペインから (Config) と書かれた項目を選択します。右ペインにはノード1のネットワーク設定一覧が表示されますが、この時点では何も設定されていないはずです(新規追加用のフィールドがあるだけです):

ここにノード3のブロックチェーンへ同期リクエストを行うための設定を追加します。右ペイン内の新規追加フィールド内に以下の JSON テキストを記述して "Save" ボタンをクリックします(赤字は説明用のコメントなので不要です)。リクエスト送信元では URL キーで同期リクエスト先(今回はノード3)の URL を指定ような設定を行います:
{ "name": "config1-1", 設定の名前(任意文字列) "url": "http://xx.xx.xx.xx:34126" 同期リクエスト先URL、今回はノード3のURL }

正しく設定が保存されると、設定一覧が更新され、以下のように1件追加されます(表示されている文字列は自動追加された ID です):

ID 部分をクリックすると設定内容を表示することができます(もう一度クリックすると省略表示に戻ります):

これでノード1のブロックチェーン更新時にノード3のブロックチェーンに同期リクエストが発行されるようになりました。ただこれだけでは同期されません。正しく同期するにはノード3側にもこの同期リクエストを受け付けるための設定が必要です。
その設定をする際にリクエスト元であるノード1の serverid 情報が必要になります。このタイミングで確認しておきましょう。サーバーノードの serverid はダッシュボード画面左上の鳩マーク部分をマウスホバーすると表示されます。この値をこの後使うのでメモしておきます:

改めて、今度はノード3のダッシュボード(http://xx.xx.xx.xx:34126)を開き、(Config) を選択して設定一覧の画面を開きます。ノード3も起動直後であれば、この時点では設定項目は何もないはずです:

ここに新しい設定を以下の JSON テキストの内容で追加(Save)します。なお serverid 値は先程確認した同期リクエスト元の serverid を指定する必要があります。同期リクエスト先ではリクエスト元の serverid を明示的に指定することであらかじめ想定したノードからのリクエストのみを受け付けることができるよう調整できます:
{ "name": "config3-1", 設定の名前(任意文字列) "serverid": "1597540321639" 同期リクエスト元serverid、今回はノード1の serverid }

正しく保存できるとノード3の設定一覧が更新され、指定した serverid からの同期リクエストを処理するための設定が追加されます:

このペアとなる設定でノード1のブロックチェーンが更新された時にノード3のブロックチェーンと同期を取るための設定ができあがりました。このように同期リクエストを発行する側ではリクエスト先の URL を、受ける側ではリクエスト元の serverid を指定して、両方設定済みの場合のみ同期が行われる点に注意してください。
(今回は設定しませんが)同様にしてノード3のブロックチェーンが更新された時にノード1と同期する場合は今の逆の設定を行います。ノード3の Config にノード1の URL を指定した設定を追加し、ノード1の Config にノード3の serverid を指定した設定を追加することで双方向の同期が実現できます。
続いてノード2とノード3の同期設定を行います。ここでの設定内容は「1分おきにノード2からノード3へ同期リクエストを送る」です。同期リクエストを受けるノード3側はノード1の時とほぼ同様の設定をするだけですが、同期リクエストを送信するノード2側の設定を「ブロックチェーンが更新されたら」ではなく「1分おき」に変更する必要があります。
ではその具体的な方法を紹介します。ノード2のダッシュボードを開き(http://xx.xx.xx.xx:24126)、(Config) を選択して設定一覧の画面を開きます。ノード2も起動直後であれば、この時点では設定項目は何もないはずです:

ここに新しい設定を以下の JSON テキストの内容で追加(Save)します。先程と異なり同期リクエスト先 URL に加えて、"cron" というキーで同期タイミングを cron フォーマットで指定します。"* * * * *" は「1分おき」を意味しています:
{ "name": "config2-1", 設定の名前(任意文字列) "url": "http://xx.xx.xx.xx:34126", 同期リクエスト先URL "cron": "* * * * *" 同期タイミングの cron 指定 }

正しく保存できると一覧が更新されます。"url" と "cron" 指定がある設定は「指定先 URL に cron 指定のタイミングで定期的に同期リクエストを送信する」というものです。またこの cron 指定はいわゆるスケジュール実行の crontab と同じフォーマットを利用します。「1分」おき以外にも「毎時○分」とか「毎週○○曜日の××時」のような指定も可能です:

後はこのノード2からの同期リクエストを受けるための設定をノード3側に追加します。こちらはノード1からの同期リクエストを受ける設定と同様です。ノード2の serverid を調べ、その値を serverid キーに指定して保存します(つまりノード3の設定項目は2つになります):

これで目的のブロックチェーンネットワークを構築するための設定が完了しました。なお最後の設定を保存することでノード2のブロックチェーンとノード3のブロックチェーンは1分おきに同期が取られるようになるため、これまでの (Config) 項目を変更した際のブロックチェーンも同期されることになります。1分程度待ってからノード2とノード3のブロックチェーン一覧を確認すると、ノード2とノード3の Config を追加した内容が記録され、同期されている(同じ3つのブロックになっている)はずです:

一方ノード1のブロックチェーンのみ、まだ(同期が行われていないため)単独の内容になっているはずです。ではノード1にブロックを追加して、ノード3と同期してみます。ノード1のダッシュボードを開いて左ペインのデータベース作成フィールド(new db と表示されているフィールド)に "db1" を指定して "New" をクリックします("db1" というデータベースを作ります)。この処理がノード1のブロックチェーンに記録されると共にノード3へブロックチェーンの同期リクエストが送信されて同期されます。そのためノード1のブロックチェーンはノード1、ノード2、ノード3の変更記録が全て記録された、5つのブロックで構成されます(ノード3のブロックチェーンも同じ内容になります):

また、この直後(ノード1に db1 データベースを追加した直後)ではノード2のブロックチェーンに変化はありませんが、1分程度経過するとノード1との同期が行われたノード3のブロックチェーンと再度同期されるため、ノード2のブロックチェーンも他の2つと同じ5つのブロックからなるブロックチェーンに変わるはずです。これで全てのノードの内容が同期されることになります。
以上が HATOYA をマルチノード運用する場合の設定例となります。もちろん4ノード以上で運用することもあるでしょうし、全て同一ホストの docker ネットワーク上で構成する必要もありません。あくまで同期設定の URL で正しい(ポート番号までを含めた)オリジンが指定されていれば同期できます。HATOYA ネットワークにノードを参加させたい場合は同期リクエストを送る側と受ける側両方に設定が必要(一方的な設定でネットワークに参加することはできない)な点に注意してください。
最後に、この設定方法の特徴として、「プライベートネットワークから HATOYA ネットワークに参加する」ことも可能になっている点を紹介します。上の例では3ノードを全て同一の docker ネットワーク上に作成して説明しましたが、必ずしも同一ネットワーク上に作る必要はなく、また全ノードがパブリックネットワークに存在している必要はありません。同期リクエストを送信する際の設定項目の中で同期リクエスト先の正しい URL を指定できていること(と、同期リクエスト元の正しい serverid を指定すること)だけが条件になっているので、同期リクエスト送信ノードはプライベートネットワーク上に存在していてもよい(同期リクエスト受信ノードから送信ノードにアクセスできなくてもよい)という副産物的な特徴があります。事実、上の例でいえばノード3はノード1やノード2から URL でアクセスできる場所に存在している必要がありますが、ノード1やノード2は他のノードから直接参照できる場所に存在している必要はなく、それぞれ別のネットワーク上に存在していても構いませんし、それがプライベートネットワークであっても構いません。この特徴によって HATOYA ではプライベートネットワークからブロックチェーンに参加することも可能になり、既存のネットワーク構成(の変更)を意識することなくブロックチェーンネットワークが実現しやすいという特徴があります:

以上が HATOYA のブロックチェーンネットワーク構築の例となります。ノードの数が増えたり、その同期トポロジーや同期タイミングを複雑にしたり、一度作成したネットワークに新たにノードを追加するようなこともあると思っていますが、基本的には上述の応用でカバーできると思っています。
また HATOYA の場合、マルチノードネットワークにしておくと、サーバーノードの故障時や増強時などにブロックチェーンからデータベースをリストアするという特徴的な機能も実装済みだったりします。そのあたりはいずれ別の機会に紹介したいと思っています。
コメント