【Hyperledger Composer】インフラ構築チートシート（Ubuntu用）

## このチートシートは何のためのもの？

このチートシートは[前の記事](https://qiita.com/microwavePC/items/05737762d840b6dd1046)の続きです。
前の記事で必要となる諸々のアプリケーションの導入を行った後のインフラ構築部分をこちらに記載しています。
チートシートなので、用語の説明等々はほぼ省略しています。

~~CentOS用のチートシートは[こちら]()。~~ 作成次第リンクを貼ります。

## 前提条件

[前の記事](https://qiita.com/microwavePC/items/05737762d840b6dd1046)と同じく、環境が **Ubuntu 16.04 LTE** であることを前提として作成してあります。
プラットフォームとするHyperledger Fabricのバージョンは **1.2** です。
上記以外のバージョンを利用される場合、インストールする各アプリケーションのバージョンを適切なものに変更してください。

## この手順に沿った場合に最終的に出来上がる環境

Githubにある「[fabric-samples](https://github.com/hyperledger/fabric-samples)」の「[first-network](https://github.com/hyperledger/fabric-samples/tree/release-1.4/first-network)」をベースに、マルチノードとなるよう構築します。
組織（organization）、ピア、CA、オーダラーは、下記の構成とします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140394/572e402a-72d5-55f4-613c-3e6f72f8662f.png)
ホームディレクトリ直下にfabric-samplesをクローンし、それ利用する形で作成します。

この記事では**BNAファイルをインストールための環境構築までの部分**を記載します。
BNAファイルは各々実装・作成したものを利用してください。

※管理者以外のアカウントはBNAファイルのインストール後に作成するため、このチートシート内では触れません。

## インフラ構築手順

###### 1. 稼働中のDockerコンテナをすべて停止・削除する。

```shell:コマンド
docker kill $(docker ps -q)
docker rm $(docker ps -aq)
docker rmi $(docker images dev-* -q)
docker volume prune  #コンテナの残留ファイルが悪影響を及ぼすことがあるため、このコマンドも必要。
```

###### 2. Hyperledger Fabric用に環境変数「FABRIC_VERSION」を追加し、環境変数を再読込する。

```shell:コマンド
echo 'export FABRIC_VERSION=hlfv12' >> ~/.profile
source ~/.profile
```

###### 3. ホームディレクトリ直下に「fabric-sample」のリポジトリをクローンする。

```shell:コマンド
cd ~
git clone https://github.com/mahoney1/fabric-samples.git
cd fabric-samples
```

###### 4. プラットフォームバイナリをダウンロードする。

```shell:コマンド
curl -sSL http://bit.ly/2ysbOFE | bash -s 1.2.0 1.2.0 0.4.10
```

###### 5. Gitのブランチを、マルチノード用のものに切り替える。

```shell:コマンド
#multi-orgブランチの、2018年8月9日時点のリポジトリを使用する。Gitの設定ファイルへ問題なくアクセスされるよう、sudoを付けて実行する。
sudo git checkout c0e55d8d40849afa9d1011b8b778b282a8f9e32f
```

###### 6. サンプルプロジェクト「first-network」に入る。

```shell:コマンド
cd first-network
```

###### 7. 目的とする組織・ピア・CA・オーダラーの構成に応じて、各設定ファイルを修正する。※デフォルトでは、上記表の構成となる。

詳細は[公式ドキュメント](https://hyperledger-fabric.readthedocs.io/en/latest/build_network.html)を参照してください。各ファイルの概要をざっくり記載すると下記の通りです。

- **byfn.sh**<br>
	ネットワークの生成やDockerコンテナの生成、暗号化キーの生成を行うためのスクリプト。<br>
	チャネル名はこの中で定義されている。<br>
- **crypto-config.yaml**<br>
	オーダラーと組織に使用する暗号化キーの生成時に参照される。<br>
	必要に応じて、オーダラーの定義値の修正と、組織の定義値の修正を行う。<br>
- **configtx.yaml**<br>
	必要に応じて、オーダラーの定義値の修正と、組織の定義値の修正を行う。<br>
- **docker-compose-cas.yaml**<br>
	暗号化キーの内、プライベートキーの生成時に参照される。<br>
	必要に応じて、CA用コンテナの設定値の修正を行う。<br>
- **docker-compose-couch.yaml**<br>
	必要に応じて、StateDBと各ピアとの関係に関する設定値の修正を行う。<br>
- **docker-compose-e2e.yaml**<br>
	暗号化キーの内、プライベートキーの生成時に参照される。<br>
	必要に応じて、オーダラーとピアとなる各コンテナの定義と設定の修正を行う。<br>
- **docker-compose-cli.yaml**<br>
	必要に応じて、オーダラーとピアとなる各コンテナの定義と設定の修正を行う。<br>

以降の手順はこれらのファイルに変更を加えていないことを前提に記載しています。
もし変更を加える場合、以降の手順に記載の内容は適宜読み替えて実施してください。

###### 8. first-networkを以下のコマンドでビルドし、最後に大きな文字で「END」と表示されることを確認する。

```shell:コマンド
./byfn.sh -m generate  #このコマンドでスクリプトを実行することよって、各ピアとオーダラーが使用する暗号化キーとGenesisブロック（＝ブロックチェーン上の最初のブロック）が生成される。
./byfn.sh -m up -s couchdb -a  #このコマンドによってシェル内で「docker-compose up」コマンドが実行され、docker-compose.yamlで定義されたサービスが開始される。
```

###### 9. これから追加するカードと重複している既存のカードを確認・削除する。

```shell:コマンド
composer card list  #確認用コマンド
composer card delete -c <カード名>  #このコマンドは、確認用コマンドで見つけた削除対象のカードすべてに対して実行する。
rm -fr ~/.composer
```

###### 10. 組織Org1とOrg2のコネクションプロファイルを作成するための作業ディレクトリを作成する。

```shell:コマンド
mkdir -p /tmp/composer/org1
mkdir -p /tmp/composer/org2
```

###### 11. 接続プロファイルの大元となるJSONファイル（tutorial-network.json）を作成する。

```shell:コマンド
touch /tmp/composer/tutorial-network.json
```

###### 12. tutorial-network.jsonを開き、以下の内容をコピー＆ペーストする。

```json:tutorial-network.json
{
    "name": "tutorial-network",
    "x-type": "hlfv1",
    "version": "1.0.0",
    "channels": {
        "mychannel": {
            "orderers": [
                "orderer.example.com"
            ],
            "peers": {
                "peer0.org1.example.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "eventSource": true
                },
                "peer1.org1.example.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "eventSource": true
                },
                "peer0.org2.example.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "eventSource": true
                },
                "peer1.org2.example.com": {
                    "endorsingPeer": true,
                    "chaincodeQuery": true,
                    "eventSource": true
                }
            }
        }
    },
    "organizations": {
        "Org1": {
            "mspid": "Org1MSP",
            "peers": [
                "peer0.org1.example.com",
                "peer1.org1.example.com"
            ],
            "certificateAuthorities": [
                "ca.org1.example.com"
            ]
        },
        "Org2": {
            "mspid": "Org2MSP",
            "peers": [
                "peer0.org2.example.com",
                "peer1.org2.example.com"
            ],
            "certificateAuthorities": [
                "ca.org2.example.com"
            ]
        }
    },
    "orderers": {
        "orderer.example.com": {
            "url": "grpcs://★★★ここを自身のホスト・ドメインに書き換える★★★:7050",
            "grpcOptions": {
                "ssl-target-name-override": "orderer.example.com"
            },
            "tlsCACerts": {
                "pem": "INSERT_ORDERER_CA_CERT"
            }
        }
    },
    "peers": {
        "peer0.org1.example.com": {
            "url": "grpcs://★★★ここを自身のホスト・ドメインに書き換える★★★:7051",
            "grpcOptions": {
                "ssl-target-name-override": "peer0.org1.example.com"
            },
            "tlsCACerts": {
                "pem": "INSERT_ORG1_CA_CERT"
            }
        },
        "peer1.org1.example.com": {
            "url": "grpcs://★★★ここを自身のホスト・ドメインに書き換える★★★:8051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.org1.example.com"
            },
            "tlsCACerts": {
                "pem": "INSERT_ORG1_CA_CERT"
            }
        },
        "peer0.org2.example.com": {
            "url": "grpcs://★★★ここを自身のホスト・ドメインに書き換える★★★:9051",
            "grpcOptions": {
                "ssl-target-name-override": "peer0.org2.example.com"
            },
            "tlsCACerts": {
                "pem": "INSERT_ORG2_CA_CERT"
            }
        },
        "peer1.org2.example.com": {
            "url": "grpcs://★★★ここを自身のホスト・ドメインに書き換える★★★:10051",
            "grpcOptions": {
                "ssl-target-name-override": "peer1.org2.example.com"
            },
            "tlsCACerts": {
                "pem": "INSERT_ORG2_CA_CERT"
            }
        }
    },
    "certificateAuthorities": {
        "ca.org1.example.com": {
            "url": "https://★★★ここを自身のホスト・ドメインに書き換える★★★:7054",
            "caName": "ca-org1",
            "httpOptions": {
                "verify": false
            }
        },
        "ca.org2.example.com": {
            "url": "https://★★★ここを自身のホスト・ドメインに書き換える★★★:8054",
            "caName": "ca-org2",
            "httpOptions": {
                "verify": false
            }
        }
    }
}
```
「★★★ここを自身のホスト・ドメインに書き換える★★★」と記載している部分は、環境に応じて適切なものに書き換えてください。
localhostにしてしまった場合は外部から接続するときに不便が生じるため、localhostの使用は避けることをお勧めします。


###### 13. 組織「Org1」用の公開鍵情報を、以下のコマンドによって作業用ディレクトリに「ca-org1.txt」というファイル名で書き出す。

```shell:コマンド
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt > /tmp/composer/org1/ca-org1.txt
```
※ca-org1.txtの出力先ディレクトリは、「/tmp/composer/org1」となります。

###### 14. tutorial-network.json内の「INSERT_ORG1_CA_CERT」となっている部分（2箇所）を、ca-org1.txtの内容で置換し、保存する。

置換後は例えば下記のようになります。
鍵は生成するたびに中身が変わります。以下のものをコピーしても使用できませんので、ご注意ください。

```json:tutorial-network.json
　（省略）
            "tlsCACerts": {
                "pem": "-----BEGIN CERTIFICATE-----\nMIICNTCCAdygAwIBAgIRAMNvmQpnXi7uM19BLdha3MwwCgYIKoZIzj0EAwIwbDEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRowGAYDVQQDExF0bHNjYS5l\neGFtcGxlLmNvbTAeFw0xNzA2MjYxMjQ5MjZaFw0yNzA2MjQxMjQ5MjZaMGwxCzAJ\nBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJh\nbmNpc2NvMRQwEgYDVQQKEwtleGFtcGxlLmNvbTEaMBgGA1UEAxMRdGxzY2EuZXhh\nbXBsZS5jb20wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASJn3QUVcKCp+s6lSPE\nP5KlWmE9rEG0kpECsAfW28vZQSIg2Ez+Tp1alA9SYN/5BtL1N6lUUoVhG3lz8uvi\n8zhro18wXTAOBgNVHQ8BAf8EBAMCAaYwDwYDVR0lBAgwBgYEVR0lADAPBgNVHRMB\nAf8EBTADAQH/MCkGA1UdDgQiBCB7ULYTq3+BQqnzwae1RsnwQgJv/HQ5+je2xcDr\nka4MHTAKBggqhkjOPQQDAgNHADBEAiB2hLiS8B1g4J5Qbxu15dVWAZTAXX9xPAvm\n4l25e1oS+gIgBiU/aBwSxY0uambwMB6xtQz0ZE/D4lyTZZcW9SODlOE=\n-----END CERTIFICATE-----\n"
            }
　（省略）
```


###### 15. 組織「Org2」用の公開鍵情報を、以下のコマンドによって作業用ディレクトリに「ca-org2.txt」というファイル名で書き出す。

```shell:コマンド
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt > /tmp/composer/org2/ca-org2.txt
```
※ca-org2.txtの出力先ディレクトリは、「/tmp/composer/org2」となります。

###### 16. tutorial-network.json内の「INSERT_ORG2_CA_CERT」の部分（2箇所）を、ca-org2.txtの内容で置換し、保存する。


###### 17. オーダラー用の公開鍵情報を、以下のコマンドによって作業用ディレクトリに「ca-orderer.txt」というファイル名で書き出す。

```shell:コマンド
awk 'NF {sub(/\r/, ""); printf "%s\\n",$0;}' crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt > /tmp/composer/ca-orderer.txt
```
※ca-orderer.txtの出力先ディレクトリは、「/tmp/composer」となります。

###### 18. tutorial-network.json内の「INSERT_ORDERER_CA_CERT」の部分を、ca-orderer.txtの内容で置換し、保存する。


###### 19. 上の手順で作成・編集したbyfn-network.jsonを、以下の階層・ファイル名となるようコピーする（計2ファイルを作成）。
　　①　	**/tmp/composer/org1/tutorial-network-org1.json**
　　②　	**/tmp/composer/org2/tutorial-network-org2.json**


###### 20. tutorial-network-org1.jsonを開き、versionセクションとchannelセクションの間に、以下の通りにclientセクションを追加する。

```json:BEFORE
…（略）…
    "version": "1.0.0",
    "channel": {
…（略）…
```

```json:AFTER
…（略）…
    "version": "1.0.0",
    "client": {
        "organization": "Org1",
        "connection": {
            "timeout": {
                "peer": {
                    "endorser": "300",
                    "eventHub": "300",
                    "eventReg": "300"
                },
                "orderer": "300"
            }
        }
    },
    "channel": {
…（略）…
```

###### 21. tutorial-network-org2.jsonを開き、versionセクションとchannelセクションの間に、以下の通りにclientセクションを追加する。

```json:BEFORE
…（略）…
    "version": "1.0.0",
    "channel": {
…（略）…
```

```json:AFTER
…（略）…
    "version": "1.0.0",
    "client": {
        "organization": "Org2",
        "connection": {
            "timeout": {
                "peer": {
                    "endorser": "300",
                    "eventHub": "300",
                    "eventReg": "300"
                },
                "orderer": "300"
            }
        }
    },
    "channel": {
…（略）…
```


###### 22. 組織Org1のネットワークで使用するAdminアカウント（Admin@org1.example.com）の公開鍵と秘密鍵を、作業用ディレクトリへコピーする。

```shell:コマンド
cd ~/fabric-samples/first-network
rm /tmp/composer/org1/A*.pem /tmp/composer/org1/*_sk
cp -p crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/A*.pem /tmp/composer/org1
cp -p crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore/*_sk /tmp/composer/org1
```


###### 23. 組織Org2のネットワークで使用するAdminアカウント（Admin@org2.example.com）の公開鍵と秘密鍵を、作業用ディレクトリへコピーする。

```shell:コマンド
cd ~/fabric-samples/first-network
rm /tmp/composer/org2/A*.pem /tmp/composer/org2/*_sk
cp -p crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/signcerts/A*.pem /tmp/composer/org2
cp -p crypto-config/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp/keystore/*_sk /tmp/composer/org2
```


###### 24. 組織Org1・Org2それぞれのAdminアカウント用のビジネスネットワークカードを生成する。

```shell:コマンド
composer card create -p /tmp/composer/org1/tutorial-network-org1.json -u PeerAdmin -c /tmp/composer/org1/Admin@org1.example.com-cert.pem -k /tmp/composer/org1/*_sk -r PeerAdmin -r ChannelAdmin -f PeerAdmin@tutorial-network-org1.card
composer card create -p /tmp/composer/org2/tutorial-network-org2.json -u PeerAdmin -c /tmp/composer/org2/Admin@org2.example.com-cert.pem -k /tmp/composer/org2/*_sk -r PeerAdmin -r ChannelAdmin -f PeerAdmin@tutorial-network-org2.card
```


###### 25. 組織Org1・Org2それぞれのビジネスネットワークカードを、それぞれの組織のウォレットへインポートする。

```shell:コマンド
composer card import -f PeerAdmin@tutorial-network-org1.card --card PeerAdmin@tutorial-network-org1
composer card import -f PeerAdmin@tutorial-network-org2.card --card PeerAdmin@tutorial-network-org2
```

**以上**

## 参考情報

https://hyperledger.github.io/composer/latest/tutorials/deploy-to-fabric-multi-org