Docker for Mac で Hyperledger Fabric の開発環境を立ち上げる

チェーンコードの実装やアプリケーションの開発にあたって、開発環境が必要になります。
今回は開発環境の立ち上げを行ってみました。

# 開発環境を構築する3つの方法

## Vagrant を利用

:note: http://hyperledger-fabric.readthedocs.io/en/latest/Setup/Chaincode-setup/#option-1-vagrant-development-environment

Hyperledger Fabric リポジトリの `devenv` ディレクトリ下に、Vagrantfile とプロビジョニング用のスクリプトが用意されているため、それを使用して構築します。

- Vagrant, VirtualBox をインストール
    - refs: https://github.com/hyperledger/fabric/blob/master/docs/dev-setup/devenv.md
- Hyperleder Fabric リポジトリをクローンし、`devenv` ディレクトリ下に移動
- `vagrant up` を実行して仮想マシンを起動・プロビジョニング
    - 必要なパッケージがインストールされた専用の Vagrant Box (Ubuntu) が利用される
    - Vagrant Box のダウンロードに20分、起動・プロビジョニングに20分ほどかかった
- `vagrant ssh` でサーバに入る
- `make membersrvc && membersrvc` でメンバーシップサービスを起動
- `make peer && peer node start --peer-chaincodedev` でピアを起動

しかし、この方法では構築する中でいくつか問題が発生し、かなりしんどかったです。

- Docker のインストールに必要な GPG キーが取得できない(こちらと同じ方法で解決: http://qiita.com/togana/items/cf3bf9bb7cf28923b221)
- JavaSDK のバージョン選択が上手くいかない(プロビジョニングは進行)
- Node のバージョンが古いため(v0.12.7)、NodeSDK のユニットテストが通らない

既知の問題もあるようですし、次の Docker を使用した環境構築の方が非常に簡単なのでおすすめです。

## Docker for Mac/Windows を利用

:note: http://hyperledger-fabric.readthedocs.io/en/latest/Setup/Chaincode-setup/#option-2-docker-for-mac-or-windows

Hyperledger Fabric はそれぞれのサービスが Docker コンテナになっており、Mac/Windows 上に直接コンテナを起動することができます。

- Docker をインストール
    - 公式サイト https://docker.github.io/engine/installation/
    - Homebrew Cask があれば `brew cask install docker`
- 必要な Docker イメージを Pull する
    - `docker pull hyperledger/fabric-peer:latest`
    - `docker pull hyperledger/fabric-membersrvc:latest`
    - 10分から15分程度で完了した
- Docker Compose でメンバーシップサービスとピアのコンテナを構築
    - Docker Compose 用の設定ファイルが公式で提供されているので、任意の場所に `docker-compose.yml` として設置する
    - `docker-compose up` でメンバーシップサービスとピアのコンテナが起動する

コンテナ起動時の `docker-compose.yml` は以下です。

```
membersrvc:
  image: hyperledger/fabric-membersrvc
  command: membersrvc
vp0:
  image: hyperledger/fabric-peer
  environment:
    - CORE_PEER_ADDRESSAUTODETECT=true
    - CORE_VM_ENDPOINT=http://172.17.0.1:2375
    - CORE_LOGGING_LEVEL=DEBUG
    - CORE_PEER_ID=vp0
    - CORE_PEER_PKI_ECA_PADDR=membersrvc:7054
    - CORE_PEER_PKI_TCA_PADDR=membersrvc:7054
    - CORE_PEER_PKI_TLSCA_PADDR=membersrvc:7054
    - CORE_SECURITY_ENABLED=true
    - CORE_SECURITY_ENROLLID=test_vp0
    - CORE_SECURITY_ENROLLSECRET=MwYpmSRjupbT
  links:
    - membersrvc
  command: sh -c "sleep 5; peer node start --peer-chaincodedev"
```

それぞれ、コンテナ構築時に使用する Docker イメージ、構築後の実行コマンド、環境変数などが指定されます。

## Docker Toolbox を利用

:note: http://hyperledger-fabric.readthedocs.io/en/latest/Setup/Chaincode-setup/#option-3-docker-toolbox

Docker for Mac/Windows と同様の手順で構築可能です。

Docker for Mac/Windows との違いは、Docker が稼働する仮想環境がネイティブか VirtualBox かの違いだけです。
Docker for Mac/Windows はネイティブ上に稼働し、Docker Toolbox は VirtualBox 上に稼働します。

# Docker for Mac の使い方メモ

今回は Docker for Mac を使って構築しました。

## コンテナの構築・起動

```
% docker-compose up
Creating docker_membersrvc_1
Creating docker_vp0_1
Attaching to docker_membersrvc_1, docker_vp0_1
```

## コンテナの停止

```
% docker-compose stop
Stopping docker_membersrvc_1 ... done
Stopping docker_vp0_1 ... done
```

## コンテナの削除

```
% docker-compose rm
Going to remove docker_vp0_1, docker_membersrvc_1
Are you sure? [yN] y
Removing docker_vp0_1 ... done
Removing docker_membersrvc_1 ... done
```

## コンテナプロセスの確認

```
% docker ps
CONTAINER ID        IMAGE                           COMMAND                  CREATED             STATUS              PORTS                                                      NAMES
11bdfd641d57        hyperledger/fabric-peer         "sh -c 'sleep 5; peer"   20 hours ago        Up 28 seconds       0.0.0.0:7050-7051->7050-7051/tcp, 0.0.0.0:7053->7053/tcp   docker_vp0_1
b2e60ea30a40        hyperledger/fabric-membersrvc   "membersrvc"             20 hours ago        Up 29 seconds       0.0.0.0:7054->7054/tcp                                     docker_membersrvc_1
```

## コンテナ内部に入る

```
% docker exec -it 11bdfd641d57 /bin/bash
root@11bdfd641d57:/opt/gopath/src/github.com/hyperledger/fabric# pstree -Aalunp
sh,1 -c sleep 5; peer node start --peer-chaincodedev
  `-peer,8 node start --peer-chaincodedev
      |-{peer},9
      |-{peer},10
      |-{peer},11
      |-{peer},12
      |-{peer},13
      |-{peer},14
      |-{peer},15
      `-{peer},16
```

# 動作テスト

起動したコンテナでの動作テストを、REST API を使って行います。
REST API は 7050 ポートを使用します。

## Registrar API でのログイン

`membersrvc/membersrvc.yml` に初期のログイン情報があるので、その情報を使って任意のユーザにログインします。

```
% curl -X POST -H 'Content-Type: application/json' -d '{"enrollId":"jim","enrollSecret":"6avZQLwcUe9b"}' http://localhost:7050/registrar

{"OK":"Login successful for user 'jim'."}
```

## Chaincode API でのチェーンコード設置・実行・参照

Docker for Mac で構築した場合、ローカル環境上にチェーンコードをビルドし、実行することでチェーンコードを起動・ピアに登録することができます。

まずは `$GOPATH` 下に `chaincode_example02.go` というサンプルをダウンロードします。

```
% mkdir -p $GOPATH/src/github.com/chaincode_example02/
% cd $GOPATH/src/github.com/chaincode_example02
% curl GET https://raw.githubusercontent.com/hyperledger/fabric/master/examples/chaincode/go/chaincode_example02/chaincode_example02.go > chaincode_example02.go
```

サンプルコードには Hyperledger Fabric リポジトリのコードが必要なので、こちらも `$GOPATH` 下にクローンします。

```
% mkdir -p $GOPATH/src/github.com/hyperledger
% cd $GOPATH/src/github.com/hyperledger
% git clone https://github.com/hyperledger/fabric.git
```

再びサンプルコードのあるディレクトリまで戻って、`go build` します。

```
% cd $GOPATH/src/github.com/chaincode_example02
% go build
```

`chaincode_example02` が作成されるので、実行します。
実行する際に任意のチェーンコードID名と、起動しているピアコンテナのアドレスを指定します。

```
% CORE_CHAINCODE_ID_NAME=mycc CORE_PEER_ADDRESS=0.0.0.0:7051 ./chaincode_example02
19:00:56.500 [shim] INFO : error with chaincode log level: logger: invalid log level level=
19:00:56.500 [shim] DEBU : Peer address: 0.0.0.0:7051
19:00:56.503 [shim] DEBU : os.Args returns: [./chaincode_example02]
19:00:56.505 [shim] DEBU : Registering.. sending REGISTER
19:00:56.510 [shim] DEBU : []Received message REGISTERED from shim
19:00:56.510 [shim] DEBU : []Handling ChaincodeMessage of type: REGISTERED(state:created)
19:00:56.510 [shim] DEBU : Received REGISTERED, ready for invocations
```

これでピアにチェーンコードが登録され、任意のチェーンコードID名を使用してデプロイ・実行できるようになります。

下記を実行して登録したチェーンコードをデプロイします。
初期値として `a` に `1000`、`b` に `2000` をセットするようになっています。

```
% echo '{
  "jsonrpc": "2.0",
  "method": "deploy",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "mycc"
    },
    "ctorMsg": {
      "function": "init",
      "args": ["a", "1000", "b", "2000"]
    },
    "secureContext": "jim"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- http://localhost:7050/chaincode

{"jsonrpc":"2.0","result":{"status":"OK","message":"mycc"},"id":1}
```

デプロイしたチェーンコードを指定して、invoke してみます。
`a` から `b` に `100` を渡すような処理です。

```
% echo '{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "mycc"
    },
    "ctorMsg": {
      "function": "invoke",
      "args": ["a", "b", "100"]
    },
    "secureContext": "jim"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- http://localhost:7050/chaincode

{"jsonrpc":"2.0","result":{"status":"OK","message":"d0e86638-778c-4a50-9d72-a160b8b6d74f"},"id":1}
```

query で処理が正常に完了したかを確認します。
`a` を指定すると結果は `900` に、`b` を指定すると結果は `2100` になりました。

```
% echo '{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "mycc"
    },
    "ctorMsg": {
      "function": "query",
      "args": ["a"]
    },
    "secureContext": "jim"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- http://localhost:7050/chaincode

{"jsonrpc":"2.0","result":{"status":"OK","message":"900"},"id":1}
```

```
% echo '{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
    "type": 1,
    "chaincodeID": {
      "name": "mycc"
    },
    "ctorMsg": {
      "function": "query",
      "args": ["b"]
    },
    "secureContext": "jim"
  },
  "id": 1
}' | 
curl -X POST -H 'Content-Type: application/json' -d @- http://localhost:7050/chaincode

{"jsonrpc":"2.0","result":{"status":"OK","message":"2100"},"id":1}
```