この記事は、OSSの分散型台帳技術であるHyperledger/fabricを用いて簡易な入出金処理を作り、docker swarm modeで分散処理させてみる、という連載の3回目です。
最終回の今回は、docker swarmクラスタ上でHyperledger/fabricを分散動作させてみます。
- OSSの分散型台帳 Hyperledger/fabric をdocker swarmで分散させてみよう(1/3)〜 動作確認編
- OSSの分散型台帳 Hyperledger/fabric をdocker swarmで分散させてみよう(2/3)〜 chaincode解説編
- OSSの分散型台帳 Hyperledger/fabric をdocker swarmで分散させてみよう(3/3)〜 分散環境解説編
docker swarm modeとdocker-compose.yaml
2016/07にリリースされた1.12からdocker本体に組み込まれたswarm modeを用いることで、dockerだけで複数ノードからなるdockerクラスタを構築できるようになりました。また2017/01リリースの1.13からは、docker-composeのyaml定義ファイルからswarm上にサービス群をまとめてstackとして構築できるようになりました。
GKEやAKSのみならずEKSも出てきた昨今、コンテナオーケストレーションプラットフォームとしてはkubernetes一択のような気がしないでもないのですが、とりあえずdocker-composeのyaml定義を流用でき、他のソフトウェアをインストールして環境構築しなくても複数ノードにコンテナを分散配置して協調動作した際の挙動を確認することができる、という意味では、docker swarm modeは便利です。ということで今回は、docker swarm modeを用いてHyperledger/fabricを分散動作させることにしました(言い訳おわり)。
docker-complseのyaml定義をdocker swarm modeで実行する際の注意点
○ コンテナ名
docker-composeを用いて単体docker上でサービスを起動する場合、yaml定義ファイルのservice
の名前としてアルファベット大文字小文字、数字、ピリオド、ハイフン、アンダースコア([a-zA-Z0-9\._\-]
)を使うことができます。
yaml定義ファイルにcontainer_name
を定義していた場合はその名前でコンテナが立ち上がりますし、指定していなかった場合は<<プロジェクト名>>_<<サービス名>>_<<連番>>
という形でコンテナ名が付与されます。
実際、Hyperledger/fabricの公式サンプルのdocker-compose.yamlでは、
ca.example.com
といった名前で認証局サービスが定義されています。
一方、docker-composeでは有効だったyaml定義をdocker swarm modeにdeployすると、コンテナ起動に失敗する場合があります。例えば上記のca.example.com
というサービス名で認証局コンテナを起動しようとすると、次のようなエラーが発生します。
failed to create service fabric-payment_ca.example.com: Error response from daemon: rpc error: code = InvalidArgument desc = name must be valid as a DNS name component
docker swarm modeでは、yaml定義ファイルにcontainer_name
を定義していても無視され、<<スタック名>>_<<サービス名>>.<<連番>>.<<タスクID>>
という形式でコンテナ名を生成します。どうもこのコンテナ名が、正しいDNS名として認識できる形になっていないとダメなようです。
正しいDNS名となるためには、アンダースコアやピリオドは使わず、小文字(あるいは大文字)と数字とハイフンのみで、なるべく短めのサービス名にしたほうが良いでしょう。
ピリオド(.)で区切られた部分は「ラベル」と呼ばれます。 一つのラベルの長さは63文字以下、ドメイン名全体の長さは、 ピリオドを含めて253文字以下でなければなりません。 ラベルには、英字(A~Z)、数字(0~9)、 ハイフン( - )が使用できます(ラベルの先頭と末尾の文字をハイフンとするのは不可)。 ラベル中では大文字・小文字の区別はなく、 同じ文字とみなされます。
出典:https://www.nic.ad.jp/ja/dom/system.html
○ ホスト名
docker-composeを用い単体docker上でHyperledger/fabricネットワークを起動する場合、bridge networkが自動作成(手動で作成しても良いですが)され内部DNSによりサービス名で名前解決されます。そのため特に何も設定をしなくても、コンテナ間はサービス名で通信できます。
swarm modeで分散環境下でHyperledger/fabricネットワークを起動する場合は、bridge networkではなくnodeをまたがって仮想ネットワークを敷設できるoverlay networkを利用することになります。
docker-composeのyaml定義に従ってコンテナを起動する上ではこれで何も問題は起きないのですが、第一回で説明したように、Hyperledger/fabricはpeerコンテナ内から直接chaicodeコンテナを起動し、docker networkに接続しようとします。この処理の最中、peerがdockerの内部dnsをlookupしているようなのですが、docker swarm modeの場合はなぜか自動生成するホスト名だとlookupがtimeoutしてしまうようです(詳細は追ってません。。。)。
docker-composeのyaml定義に、サービス名と同じホスト名を明示的に指定してあげることで、この問題を回避することができます。
○ overlay network名
docker-composeのyaml定義にoverlay driverを指定したnetworks
エントリを記述すると、docker swarm modeにdeployした際にそのstack用のoverlay networkが自動作成されます。docker-composeのyaml定義に定義されているコンテナを起動してoverlay networkで接続する上では何も問題は起きませんし、stack削除時にはそのoverlay networkも自動的に削除されるため便利なのですが、Hyperledger/fabricで用いるためには二点注意が必要です。
- overlay networkはattachableでなければならない
- peerコンテナが起動したchaicodeコンテナをoverlay networkに接続するため、overlay networkには後からコンテナを接続できなければなりません。driverを指定しただけでは自動作成されたoverlay networkはattachableになりませんので、
networks
エントリで明示的にattachable: true
を指定する必要があります(attachable指定は、yaml定義ファイルのversionは3.3から導入)
- peerコンテナが起動したchaicodeコンテナをoverlay networkに接続するため、overlay networkには後からコンテナを接続できなければなりません。driverを指定しただけでは自動作成されたoverlay networkはattachableになりませんので、
- peerコンテナに設定する
CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE
環境変数の値- この環境変数には、chaincodeを接続するdocker networkの名前を設定します。docker swarm modeへのdeploy時に自動起動したoverlay networkは、
<<スタック名>>_<<yaml定義中で設定したnetwork名>>
という名前になりますので、network名をそのまま指定するとchaincodeコンテナが立ち上がりません。
- この環境変数には、chaincodeを接続するdocker networkの名前を設定します。docker swarm modeへのdeploy時に自動起動したoverlay networkは、
今回のサンプルでは、zookeeperやkafkaのstackを分割したこともあり、事前に作成したattacableなoverlay networkを参照する形に落ち着きました(stackを削除しても残るため、最後にoverlay networkを自分で削除しなければなりませんが)。
○ コンテナを起動するnodeの指定
Hyperledger/fabricはordererやpeer、couchdb等が緊密に連携して動作しますので、連携したコンテナは適切なnodeで動作させる必要があります(ordererが全て同一nodeで動作していたら耐障害性がありませんし、peerが使用するcouchdbが別々のnodeで動作していたらレイテンシ的にもネットワーク負荷的にも不利です)。
そこでversion3以降のyaml定義に導入されたdeploy
指定を用い、連携したコンテナ群を適切なnodeに配置できるようにします。
version: '3'
networks:
fabric-sample-nw:
external: true
services:
...
peer0:
hostname: peer0
image: localhost:5000/fabric-payment-swarm/fabric-peer
environment:
- CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
- CORE_PEER_ID=peer0.org1.example.com
- CORE_LOGGING_PEER=debug
- CORE_CHAINCODE_LOGGING_LEVEL=DEBUG
- CORE_PEER_LOCALMSPID=Org1MSP
- CORE_PEER_MSPCONFIGPATH=/etc/hyperledger/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp/
- CORE_PEER_ADDRESS=peer0:7051
- CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=fabric-sample-nw
- CORE_LEDGER_STATE_STATEDATABASE=CouchDB
- CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984
- CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=
- CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=
working_dir: /etc/hyperledger
command: peer node start
ports:
- 7051
- 7053
volumes:
- /var/run/docker.sock:/host/var/run/docker.sock
networks:
- fabric-sample-nw
deploy:
replicas: 1
placement:
constraints:
- node.labels.type == node0
...
docker swarmクラスタを用い分散環境下で動かしてみよう
上記の注意点を踏まえ、node0〜node3の4台のVM上で動作するdocker swarmクラスタ上で、Hyperledger/fabricを分散動作させてみましょう。以下のようなコンテナ群でHyperledger/fabricネットワークを構成します。
zookeeperとkafka
分散環境下でordererを協調動作させるためには、最低限4つのkafkaノードと、3つ以上かつ奇数のzookeeperノードが必要です。(Bringing up a Kafka-based Ordering Service)
同一ノードでkafkaを二つ動かしても耐障害性的に意味がないので、Hyperledger/fabricを分散環境下で動作させるには最低限4つ以上のノードが必要ということになります。
認証局(ca)の可用性
今回のHyperledger/fabricネットワークは、認証局(ca)がSPOFとなっています。kafkaとzookeeperで分散協調動作してくれるordererとは違い、認証局は耐障害性の高いRDBMS(PostgreSQLかMySQL)あるいはLDAPをバックエンドに、自力で負荷分散とフェイルオーバーを組む必要があります。
出典:http://hyperledger-fabric-ca.readthedocs.io/en/latest/users-guide.html#prerequisites
今回は力尽きましたので、認証局の可用性は別の機会としたいと思います。。。
docker swarm modeクラスタを起動する
-
node0でswarmモード用のディレクトリに移動する
ubuntu@node0:~/fabric-payment-sample-docker/dev-solo$ cd ../swarm-kafka/ ```
-
node0でswarmクラスタを立ち上げる
- 今回検証したVirtualboxVMには仮想NICが2枚刺さっているため、--advertise-addrでdocker swarmが使用する仮想NICのIPアドレスを指定します。
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker swarm init --advertise-addr 192.168.100.10
-
docker swarm init
を実行すると、他のnodeをworkerとして追加するためのTOKENが表示されますが、今回は使いません。
-
masterとしてswarmクラスタにjoinするためのTOKENを表示する
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker swarm join-token manager
- 次のようなコマンド文字列が表示されます
docker swarm join --token SWMTKN-1-..... 192.168.100.10:2377
- 次のようなコマンド文字列が表示されます
-
3.で表示されたコマンドをnode1、node2、及びnode3で実行し、managerとして各々をswarmクラスタに参加させる
ubuntu@node1:~$ docker swarm join --token SWMTKN-1-...... 192.168.100.10:2377
ubuntu@node2:~$ docker swarm join --token SWMTKN-1-...... 192.168.100.10:2377
ubuntu@node3:~$ docker swarm join --token SWMTKN-1-...... 192.168.100.10:2377
-
各nodeにラベルを付与する
- yaml定義にてコンテナを立ち上げるnodeを指定できるようにするために、各nodeにラベルを付与します。
- ホスト名で制約を指定することもできるので、今回の検証程度ならばラベルを付与しなくても動作させることは可能です。
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n8aex03epr54vk0js3i968j7e * node0 Ready Active Leader klg2t4ho5v47osx7mckb2ngyt node1 Ready Active Reachable krwzoozg3l86l6ahvbhye5s8h node2 Ready Active Reachable q31j94lguqvox13o5u84tsvvk node3 Ready Active Reachable
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker node update --label-add type=node0 n8aex03epr54vk0js3i968j7e ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker node update --label-add type=node1 klg2t4ho5v47osx7mckb2ngyt ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker node update --label-add type=node2 krwzoozg3l86l6ahvbhye5s8h ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker node update --label-add type=node3 q31j94lguqvox13o5u84tsvvk
- yaml定義にてコンテナを立ち上げるnodeを指定できるようにするために、各nodeにラベルを付与します。
swarmクラスタ内にローカルレジストリを起動する
-
ローカルレジストリをswarmのサービスとして立ち上げる
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker service create --name registry --publish 5000:5000 registry:2
- ビルドしたdocker imageを分散環境下の各ノードで共有できるように、swarmクラスタ内にローカルレジストリを立ち上げます。
- peerがトランザクションに署名する暗号鍵など、Hyperledger/fabricネットワークの管理者以外には秘匿すべき情報を焼き込んだdocker imageを生成するため、DockerHub等のパブリックレジストリは使用せず、ローカルレジストリに登録します。
- プライベートなDockerRegistryサービスが既にあるならば、そちらを使っても良いでしょう。
- ビルドしたdocker imageを分散環境下の各ノードで共有できるように、swarmクラスタ内にローカルレジストリを立ち上げます。
NFSを設定する
-
node0にNFSサーバを立ち上げる
- 分散環境下ではREST APIコンテナが複数ノードで立ち上がることになるため、Hyperledger/fabricネットワークの認証局に接続するための暗号鍵ファイルを各REST APIコンテナで共有しなければなりません。
- またpeerをchannelにjoinさせる際にchannelをcreateした際に生成されるgenesisファイルが必要となるため、ノード障害等でgenesisファイルを失うと新たなpeerのjoinが困難になります。
- 上記のファイルは常時読み書きするものではないため、NFSで共有することにします。
例)node0(192.168.100.10)の/opt/nfs/fabric-paymentをNFSで共有する場合ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ sudo apt-get install nfs-kernel-server -y ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ sudo mkdir -p /opt/nfs/fabric-payment/key_store ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ sudo mkdir -p /opt/nfs/fabric-payment/genesis_store ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ sudo su -c "echo '/opt/nfs/fabric-payment 192.168.100.0/24(rw,sync,no_subtree_check,no_root_squash)' >> /etc/exports" ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ sudo exportfs -ra ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ sudo systemctl restart nfs-kernel-server.service
- 今回は手っ取り早くnode0にNFSサーバを立ち上げましたが、既に運用されているNFSサービスがあるならば、それを利用したほうが楽かもしれません。
-
node1〜node3にNFSクライアントライブラリを導入する
ubuntu@node1:~$ sudo apt-get install nfs-common -y
ubuntu@node2:~$ sudo apt-get install nfs-common -y
ubuntu@node3:~$ sudo apt-get install nfs-common -y
swarmクラスタ上にHyperledger/fabricのネットワークを起動する
-
第一回を参考に、以下の手順を実行する
- dockerのインストール
- githubから
fabric-payment-sample-docker
とfabric-payment-sample-api
をclone - chaincodeをgo get
- REST APIアプリのBearer tokenを生成し、Docker imageを生成
-
fabric-payment-sample-docker/swarm-kafka
でHyperledger/fabric 1.1.0-rc1のバイナリとdocker imageを取得するubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ curl -sSL https://goo.gl/6wtTN5 | bash -s 1.1.0-rc1
-
環境変数を設定した後、Hyperledger/fabricが必要とする暗号鍵と、fabricネットワークの設定等が記載されているアーティファクトを生成する
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ source .env ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ export CA_ADMIN_PASSWORD=<<任意の文字列>> ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ ./generate_artifact.sh ${CA_ADMIN_PASSWORD} <<NFSサーバのIP>> <<共有ディレクトリ>>
- docker単体の場合と異なり、NFSの設定を引数で与えます。
- この
generate_artifact.sh
は環境毎に異なる変数を埋め込んだdocker-compose.yamlを生成しますが、その際にNFSを用いた共有volumeも定義するためです。
- この
- 自動生成した各コンテナが署名に使う暗号鍵やchaincode、REST APIのソースコードなどを焼き込んだdocker imageも生成し、ローカルリポジトリに登録します。詳細はDockerfileを確認してください。
- docker単体の場合と異なり、NFSの設定を引数で与えます。
-
Hyperledger/fabricネットワークを分散環境下で立ち上げる
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ ./start_fabric.sh
- docker単体の場合と異なり、swarm環境下で複数のnodeに分散させてコンテナを立ち上げるには、時間がかかる場合があります。
- そのため、
start_fabric.sh
ではコンテナ起動まで行います。全てのコンテナが立ち上がっている(CURRENT STATEがRunningになっている)ことを確認してください。- 特に初回は各nodeがローカルリポジトリからdocker imageをpullする手間がかかるため、zookeeperやkafkaが居ない状態でorderderの起動を試みて、起動に失敗する可能性があります。
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker stack ps zookeeper ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS jjn0hqts9w3t zookeeper_zookeeper2.1 localhost:5000/hyperledger/fabric-zookeeper:latest node2 Running Running about a minute ago wwtfc54krest zookeeper_zookeeper1.1 localhost:5000/hyperledger/fabric-zookeeper:latest node1 Running Running about a minute ago 6pl9wohamgfl zookeeper_zookeeper0.1 localhost:5000/hyperledger/fabric-zookeeper:latest node0 Running Running about a minute ago
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker stack ps kafka ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS ab0y5b66esy4 kafka_kafka1.1 localhost:5000/hyperledger/fabric-kafka:latest node1 Running Running about a minute ago f65rcxrzou10 kafka_kafka0.1 localhost:5000/hyperledger/fabric-kafka:latest node0 Running Running about a minute ago 355ff4e4j0rf kafka_kafka3.1 localhost:5000/hyperledger/fabric-kafka:latest node3 Running Running about a minute ago 123u0483b4lh kafka_kafka2.1 localhost:5000/hyperledger/fabric-kafka:latest node2 Running Running about a minute ago
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ docker stack ps ${STACK_NAME}
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
krfhlqfh3vvz fabric-payment_cli.krwzoozg3l86l6ahvbhye5s8h localhost:5000/fabric-payment-swarm/fabric-tools:latest node2 Running Running 38 seconds ago
1ctlrvha8ecv fabric-payment_cli.q31j94lguqvox13o5u84tsvvk localhost:5000/fabric-payment-swarm/fabric-tools:latest node3 Running Running 36 seconds ago
wcww4fuohsdi fabric-payment_cli.klg2t4ho5v47osx7mckb2ngyt localhost:5000/fabric-payment-swarm/fabric-tools:latest node1 Running Running 3 minutes ago
l9wp44p2mfub fabric-payment_cli.n8aex03epr54vk0js3i968j7e localhost:5000/fabric-payment-swarm/fabric-tools:latest node0 Running Running 3 minutes ago
tu1jc0fb1ec0 fabric-payment_peer3.1 localhost:5000/fabric-payment-swarm/fabric-peer:latest node3 Running Running 2 minutes ago
s3h5oovqe4hk fabric-payment_api3.1 localhost:5000/fabric-payment-swarm/api:latest node3 Running Running about a minute ago
4ai3nchy19b3 fabric-payment_peer0.1 localhost:5000/fabric-payment-swarm/fabric-peer:latest node0 Running Running 3 minutes ago
jivvxdhxxia6 fabric-payment_api0.1 localhost:5000/fabric-payment-swarm/api:latest node0 Running Running 3 minutes ago
16zcfd3qhwkl fabric-payment_api1.1 localhost:5000/fabric-payment-swarm/api:latest node1 Running Running 3 minutes ago
ln15z8ho5t92 fabric-payment_peer2.1 localhost:5000/fabric-payment-swarm/fabric-peer:latest node2 Running Running 2 minutes ago
xqz7ppa7a4if fabric-payment_couchdb3.1 localhost:5000/hyperledger/fabric-couchdb:latest node3 Running Running 34 seconds ago
i8p08cu3hgjk fabric-payment_couchdb0.1 localhost:5000/hyperledger/fabric-couchdb:latest node0 Running Running 3 minutes ago
ujchvelk2hek fabric-payment_couchdb1.1 localhost:5000/hyperledger/fabric-couchdb:latest node1 Running Running 3 minutes ago
ye7pcr7g4o8s fabric-payment_couchdb2.1 localhost:5000/hyperledger/fabric-couchdb:latest node2 Running Running 46 seconds ago
27ugkqwdl9yk fabric-payment_orderer3.1 localhost:5000/fabric-payment-swarm/fabric-orderer:latest node3 Running Running 2 minutes ago
hhafwq7dweux fabric-payment_orderer2.1 localhost:5000/fabric-payment-swarm/fabric-orderer:latest node2 Running Running 2 minutes ago
qyysocbzi9nu fabric-payment_api2.1 localhost:5000/fabric-payment-swarm/api:latest node2 Running Running about a minute ago
qoqhmzt7oav0 fabric-payment_peer1.1 localhost:5000/fabric-payment-swarm/fabric-peer:latest node1 Running Running 3 minutes ago
yzv2v2z2j84y fabric-payment_orderer1.1 localhost:5000/fabric-payment-swarm/fabric-orderer:latest node1 Running Running 3 minutes ago
fxw6ld1dlrg6 fabric-payment_orderer0.1 localhost:5000/fabric-payment-swarm/fabric-orderer:latest node0 Running Running 3 minutes ago
0y1rsvglu7u7 fabric-payment_ca.1 localhost:5000/fabric-payment-swarm/fabric-ca:latest node0 Running Running 3 minutes ago
```
* zookeeper, kafka, 今回のアプリとstackが別れているのは、docker-compose設定ファイルからswarm stackを起動する場合、stack内でのコンテナの起動順序が制御できないからです。
* docker-composeを用いて単体dockerの中で起動する場合、depends_on
でコンテナ起動順序を制御できますが、swarm modeではサポートされていません。
> The depends_on option is ignored when deploying a stack in swarm mode with a version 3 Compose file.
> https://docs.docker.com/compose/compose-file/#depends_on
-
Hyperledger/fabricネットワークの設定を行う
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ ./setup_fabric.sh
-
setup_fabric.sh
では、Hyperledger/fabricネットワークを利用可能にするために次の処理を行っています。-
- channelの生成
docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" ${CLI} peer channel create -o ${ORDERER_ADDRESS} -c ${CHANNEL_NAME} -f /etc/hyperledger/artifacts/channel.tx
-
- 生成されたchannelのgenesisファイルをnfsへバックアップ
docker exec ${CLI} cp /etc/hyperledger/artifacts/${CHANNEL_NAME}.block /etc/hyperledger/genesis_store/
-
- peer0〜peer4の各コンテナをchannelへjoinさせ、chaincodeをインストール
setup_peer () { docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" -e "CORE_PEER_ADDRESS=${1}" ${CLI} peer channel join -b /etc/hyperledger/artifacts/${CHANNEL_NAME}.block docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" -e "CORE_PEER_ADDRESS=${1}" ${CLI} peer chaincode install -n ${CHAINCODE_NAME} -p ${CHAINCODE_SRC} -v ${CHAINCODE_VERSION}
-
-
}
setup_peer "peer0:7051"
setup_peer "peer1:7051"
setup_peer "peer2:7051"
setup_peer "peer3:7051"
```
* 4) peerのancher情報をchannelへ登録
```bash
PEER_ADDRESS="peer0:7051"
docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" -e "CORE_PEER_ADDRESS=${PEER_ADDRESS}" ${CLI} peer channel update -o ${ORDERER_ADDRESS} -c ${CHANNEL_NAME} -f /etc/hyperledger/artifacts/Org1MSPanchors.tx
```
* 5) chaincodeの初期化
```bash
PEER_ADDRESS="peer0:7051"
docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" -e "CORE_PEER_ADDRESS=${PEER_ADDRESS}" ${CLI} peer chaincode instantiate -o ${ORDERER_ADDRESS} -C ${CHANNEL_NAME} -n ${CHAINCODE_NAME} -v ${CHAINCODE_VERSION} -c '{"Args":[""]}' -P "OR ('Org1MSP.member')"
```
-
注意
- chaincodeの初期化を行ったpeer(今回のスクリプトではpeer0)以外のREST APIは、初回呼び出しに時間がかかります。これはJustInTimeで新たにコンパイル用コンテナを立ち上げてpeerにインストールされているchaincodeをコンパイルし、その後chaincode用のコンテナを立ち上げるためです。
- 初回呼び出しの前後で
docker ps
でコンテナリストを確認すると、dev-peer1.org1.example.com-fabric-payment-0.1-.....
のような名前のchaincode用コンテナが増えていることがわかります。
- 初回呼び出しの前後で
- chaincodeの初期化を行ったpeer(今回のスクリプトではpeer0)以外のREST APIは、初回呼び出しに時間がかかります。これはJustInTimeで新たにコンパイル用コンテナを立ち上げてpeerにインストールされているchaincodeをコンパイルし、その後chaincode用のコンテナを立ち上げるためです。
Hyperledger/fabricの分散処理を確認する
-
登録した口座を他のnodeで確認する
- 単体dockerの場合と同様のREST APIが利用可能です。
- node0で動作しているREST APIはポート3000です。同様に、node1はポート3001、node2は3002、node3は3003です。
- dockerのoverlay networkによって仮想ネットワークが延伸されているため、他のnodeのREST APIを利用することも可能です。
- 例えばnode0からnode1上のREST API(ポート3001)を起動するなど。
例)node0で口座を登録ubuntu@node0:~$ cat ${API_PATH}/api/.config/token.json | jq .token -r
- 単体dockerの場合と同様のREST APIが利用可能です。
4302E85F23783F132740B8A701B93534
ubuntu@node0:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3000/fabric-payment/accounts/ -X POST -d '{"name":"ほげ"}' | jq .
{
"model_type": "account",
"no": "6107511000263813",
"name": "ほげ",
"balance": 0
}
bash:例)node1で口座一覧を取得
ubuntu@node1:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3001/fabric-payment/accounts/ | jq .
[
{
"model_type": "account",
"no": "6107511000263813",
"name": "ほげ",
"balance": 0
}
]
```
* あるAPIノード経由で登録・更新した情報は、Hyperledger/fabricネットワーク内の全てのpeerに配信されます。そのためコミットに成功したら、リアルタイムに別のnodeのREST APIからも参照できます。
Hyperledger/fabricの障害復旧を確認する
-
node0で障害が発生し、Hyperledger/fabricネットワークから切り離される
- node0のdockerプロセスを停止すると、node0はswarmクラスタから除外されます。新たなLeaderノードが選出され、swarmクラスタはnode1〜node3で継続して動作します。
ubuntu@node0:~$ sudo systemctl stop docker.service
ubuntu@node1:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS n8aex03epr54vk0js3i968j7e node0 Down Active Unreachable klg2t4ho5v47osx7mckb2ngyt * node1 Ready Active Reachable krwzoozg3l86l6ahvbhye5s8h node2 Ready Active Leader q31j94lguqvox13o5u84tsvvk node3 Ready Active Reachable
-
口座を追加する
- nodeが一つダウンしていても、Hyperledger/fabricネットワークは動作しています。node3からもう一つ口座を登録してみます。
ubuntu@node3:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3003/fabric-payment/accounts/ -X POST -d '{"name":"ふが"}' | jq . { "model_type": "account", "no": "9962914372253968", "name": "ふが", "balance": 0 }
ubuntu@node3:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3003/fabric-payment/accounts/ | jq . [ { "model_type": "account", "no": "6107511000263813", "name": "ほげ", "balance": 0 }, { "model_type": "account", "no": "9962914372253968", "name": "ふが", "balance": 0 } ]
-
node0の障害を回復させる
- node0の障害が回復すると、swarmクラスタが検知してswarmクラスタに自動的にjoinします。縮退動作していたstackも復旧し、必要なコンテナがnode0で自動的に立ち上がります。
障害回復直後ubuntu@node0:~$ sudo systemctl start docker.service ubuntu@node0:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
swarmクラスタへの自動復帰後ubuntu@node0:~$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS 6k32ss9rdtfe6c0e0m6xf979y * node0 Ready Active Reachable 62retjrvcwkeky1q0mqveojvj node1 Ready Active Reachable izk1hvipbfuhoedhdx6dmh5ri node2 Ready Active Leader 09w52jcgw2u4g5mjt0t1qe39b node3 Ready Active Reachable ubuntu@node0:~$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ec086151a3f localhost:5000/fabric-payment-swarm/api:latest "npm start" 49 seconds ago Up 35 seconds fabric-payment_api0.1.swhbo2iqrwgphku8mcson7nbq
b566619f22e0 localhost:5000/fabric-payment-swarm/fabric-ca:latest "sh -c 'fabric-ca-se…" 49 seconds ago Up 33 seconds 7054/tcp fabric-payment_ca.1.p29wism0liy4b0iuud8qkamfs
313356c1b5a9 localhost:5000/hyperledger/fabric-zookeeper:latest "/docker-entrypoint.…" 49 seconds ago Up 33 seconds 2181/tcp, 2888/tcp, 3888/tcp zookeeper_zookeeper0.1.390um287fl0eywo1gdeu0v4wp
88f896299029 localhost:5000/fabric-payment-swarm/fabric-orderer:latest "orderer" 49 seconds ago Up 32 seconds 7050/tcp fabric-payment_orderer0.1.ogyc9a76hkwntx18vr6qgyhix
e916f36bc41e localhost:5000/fabric-payment-swarm/fabric-peer:latest "peer node start" 49 seconds ago Up 36 seconds fabric-payment_peer0.1.huz6q7x4763ky3jjtdlnqcohc
4e6a18cce499 localhost:5000/hyperledger/fabric-kafka:latest "/docker-entrypoint.…" 50 seconds ago Up 32 seconds 9092-9093/tcp kafka_kafka0.1.vqvd3el46ce23l87jauhu0sbf
eef8f7db4258 localhost:5000/fabric-payment-swarm/fabric-tools:latest "/bin/bash" 50 seconds ago Up 37 seconds fabric-payment_cli.yufr9amrmtml1b1owsvmnkb2z.k5p5vub6k3y8vtkh0jhp4msok
b56170b724e6 localhost:5000/hyperledger/fabric-couchdb:latest "tini -- /docker-ent…" 51 seconds ago Up 29 seconds 4369/tcp, 5984/tcp, 9100/tcp fabric-payment_couchdb0.1.tu2qy3xbiads9bez5yhqt1ecu
```
-
node0のコンテナ群をHyperledger/fabricネットワークに参加
- 残念ながら、Hyperledger/fabricネットワークへは自動復帰できません。稼働中のchannelにjoinしてchaincodeをインストールする必要があります。
-
- 変数定義
ubuntu@node0:~$ ORDERER_ADDRESS="orderer0:7050" ubuntu@node0:~$ PEER_ADDRESS="peer0:7051" ubuntu@node0:~$ LOCALMSPID="Org1MSP" ubuntu@node0:~$ PEER_MSPCONFIGPATH="/etc/hyperledger/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" ubuntu@node0:~$ CHANNEL_NAME="fabric-sample" ubuntu@node0:~$ CHAINCODE_SRC="github.com/nmatsui/fabric-payment-sample-chaincode" ubuntu@node0:~$ CHAINCODE_VERSION="0.1" ubuntu@node0:~$ CLI=$(docker ps -f name=fabric-payment_cli -q)
-
- nfsからchannelのgenesisファイルを復旧
ubuntu@node0:~$ docker exec ${CLI} cp /etc/hyperledger/genesis_store/${CHANNEL_NAME}.block /etc/hyperledger/artifacts
-
- channelへjoin
ubuntu@node0:~$ docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" -e "CORE_PEER_ADDRESS=${PEER_ADDRESS}" ${CLI} peer channel join -b /etc/hyperledger/artifacts/${CHANNEL_NAME}.block
-
- chaincodeをinstall
ubuntu@node0:~$ docker exec -e "CORE_PEER_LOCALMSPID=${LOCALMSPID}" -e "CORE_PEER_MSPCONFIGPATH=${PEER_MSPCONFIGPATH}" -e "CORE_PEER_ADDRESS=${PEER_ADDRESS}" ${CLI} peer chaincode install -n ${CHAINCODE_NAME} -p ${CHAINCODE_SRC} -v ${CHAINCODE_VERSION}
-
node0で口座一覧を取得する
- channelにjoinしたことで、state dbは障害発生後のトランザクションにも追随した状態になっています。
ubuntu@node0:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3000/fabric-payment/accounts/ | jq . [ { "model_type": "account", "no": "6107511000263813", "name": "ほげ", "balance": 0 }, { "model_type": "account", "no": "9962914372253968", "name": "ふが", "balance": 0 } ]
-
node0で口座をさらに一つ追加する
- ordererも動作しているので、node0での台帳更新も可能になっています。
ubuntu@node0:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3000/fabric-payment/accounts/ -X POST -d '{"name":"ぴよ"}' | jq . { "model_type": "account", "no": "6028010551522005", "name": "ぴよ", "balance": 0 }
ubuntu@node1:~$ curl -H "Content-Type: application/json" -H "Authorization: Bearer 4302E85F23783F132740B8A701B93534" http://localhost:3001/fabric-payment/accounts/ | jq . [ { "model_type": "account", "no": "6028010551522005", "name": "ぴよ", "balance": 0 }, { "model_type": "account", "no": "6107511000263813", "name": "ほげ", "balance": 0 }, { "model_type": "account", "no": "9962914372253968", "name": "ふが", "balance": 0 } ]
Hyperledger/fabricのネットワークを終了する
-
Hyperledger/fabricネットワークを終了する
ubuntu@node0:~/fabric-payment-sample-docker/swarm-kafka$ ./terminate.sh <<NFSサーバのIP>> <<共有ディレクトリ>>
- docker単体の場合と異なり、NFSの設定を引数で与えます。
- 今回のスクリプトや設定ファイルでは、hyperledger/fabricの認証局の情報はコンテナ削除と同時に消滅します。そのため、認証用暗号鍵ファイルが残っていると、Hyperledger/fabricネットワークを再度立ち上げた時に認証エラーが発生します。これを防ぐために、
terminate.sh
内でNFSに保管されている暗号鍵ファイルを消去しています。
- 今回のスクリプトや設定ファイルでは、hyperledger/fabricの認証局の情報はコンテナ削除と同時に消滅します。そのため、認証用暗号鍵ファイルが残っていると、Hyperledger/fabricネットワークを再度立ち上げた時に認証エラーが発生します。これを防ぐために、
- node1のdockerに、stopされているがrmされていないコンテナが残る場合があります。これはchaincode用コンテナなど、swarm stack管理下に無いコンテナはstackを削除してもrmできないからです。
- docker単体の場合と異なり、NFSの設定を引数で与えます。
最後に
無事にdocker swarmクラスタ上でHyperledger/fabricネットワークを分散動作させることができました。時間があれば、kubernetesでも試してみたいですね!