vagrant(ベイグラント)を使って、HyperLedger Fabric v1.1の環境を簡単構築

# １．目的
HyperLedger Fabricの環境を構築する場合、必要なツールや作業が多く、必要なツールが欠けていたり、作業漏れがあるとエラーが発生し、立ち上げることができず、かなり労力を要します。今後他のマシンに時間をかけず環境構築をするためには仮想マシン環境構築ツールであるvagrantを使用して、簡単に環境を構築できるようにしたいと思います。HyperLedger FabricにはVagrantfileが提供されており、仮想マシンで実行する環境は提供されていますが、それを使っても別に必要なツールや、設定が必要だったりするので、手間をかけずに済むようにカスタマイズしていきます。本ページでは仮想マシンを使用して、HyperLedger Fabricの基本的なネットワーク（４．HyperLedger Fabricの構成参照）で起動を行うことを目的としています。

# ２.HyperLedger Fabricとは
オープンソースのブロックチェーンプラットフォームのひとつです。ビットコインやイーサリアムのブロックチェーンは誰でもウォレットを作成することなどにより、そのブロックチェーンのノードとして参加することができ、取引履歴も全て開示されています。それに対し、HyperLedger Fabricは以下のような特徴があります。

- 認証されたノードでなければそのブロックチェーンに参加できず誰でも参加できるわけではない
- 取引履歴も外部へ開示していない
- 複数の特定の管理主体(企業など)で運用されることを想定したブロックチェーン
- ブロックチェーン＝仮想通貨のイメージがありますが、トランザクションの検証に対しての報酬がないため仮想通貨がありません（複数の特定の管理主体がサービスのためブロックチェーンを使うため報酬を用意する必要がない）

# ３．vagrantとは
仮想マシンの開発環境の構築と共有を簡単に行うことができるツールです。
Vagrantfileという設定ファイルを使用し、仮想マシンのメモリ、ディスク容量やツールのインストールなどを自動で行い、Vagrantfileがあればどのマシンにも同じ仮想マシン環境を構築することができます。

# ４．　HyperLedger Fabricの構成
今回構築するHyperLedgerの構成ですが、サンプルのbasic-networkを使用していて、以下のような構成になります。各ノードはdocker上で起動します。
![HyperLedgerネットワーク図.png](https://qiita-image-store.s3.amazonaws.com/0/253290/2aafffc5-c669-06dd-6991-35a795ce7499.png)
各ノードの簡単な説明です。

- CA ・・・認証局。参加するノードの認証を行います。
- Order ・・・ トランザクションの順序を制御します
- Peer ・・・トランザクションの検証を行います。
- couchdb ・・・キーバリューストアタイプのデータベース
- CLI ・・・コマンドラインでchaincodeの実行ができます。chaincodeのインストールもここで実施します。[chaincodeについてはここ参照](https://qiita.com/yukike/private/f3654bae36e8c68e1f6c "HyperLedger v1.1でchaincodeを実行する")

# ５．前提知識
以下より、環境構築していきますが、本ページは以下の知識があることを想定に記載しています。

- Linuxコマンドの基本的な知識
- gitの基本的な知識
- dockerの基本的な知識

# ６．環境
- ホストOS windows10 32bit
 - vagrant 2.0.4
 - virtualbox 5.2.8
 - git 2.16.2
 - Tera Term 4.98
 
※１　vagrant起動のためにWindows PowerShellを使用しています。バージョン2以下の場合は起動できないので、その場合はバージョンアップしてください。
※２　BIOSのIntel Virtualization Technologyが無効になっていると起動できない場合があります。vagrantを起動してもエラーになってしまう場合はご確認お願いします。

- 仮想OS Ubuntu 16.0.4
 - HyperLedger Fabric release1.1
 - docker 18.03.1-ce

# ７．ホストOS　インストール
以下のツールをインストール
vagrant
https://www.vagrantup.com/
virtualbox
https://www.virtualbox.org/
git
https://git-scm.com/
Tera Term
https://ja.osdn.net/projects/ttssh2/

## ８．１　vagrantのプラグイン vagrant-disksizeをインストールする
vagrant-disksizeプラグインをインストールすることによりディスク容量の変更ができるようになります。
コマンドプロンプトで以下のコマンドを実行します。

```
vagrant plugin install vagrant-disksize
```

# ９．HyperLedger Fabricをクローン
windows上で任意のフォルダ(ここではC:\hyperledger11)を作成し、
コマンドプロンプトから以下のコマンドを実行してHyperLedger Fabricをgithubからクローンします。

```
cd C:\hyperledger11
git clone -b release-1.1 https://github.com/hyperledger/fabric.git
```

# １０．Vagrantfileを編集
以下に仮想マシンの設定を記載するVagrantfileがあるので、これをエディタで開き編集していきます。

```sh:Vagrantfile格納場所
C:\hyperledger11\fabric\devenv\Vagrantfile
```

## １０．１　仮想マシンメモリの変更
筆者のマシンスペックの問題からメモリを1024MBに変更。メモリが多いマシンなら必要ありません。

```sh:Vagrantfile
#49行目付近を変更する
前：vb.customize ['modifyvm', :id, '--memory', '4096']
後：vb.customize ['modifyvm', :id, '--memory', '1024']
```

## １０．２　ディスク容量を増やす
デフォルトだと仮想マシンの容量が10GBと少ないので、30GBに増量します。

```sh:Vagrantfile
  #36行目付近に以下を挿入
  config.disksize.size = '30GB'
```

## １０．３　必要ツール(cryptogen,configtxgenなど)のインストール
必要なツールを自動でインストールするために以下のコマンドを追加します。`config.vm.provision :shell, :inline => "コマンド"`で仮想マシンが実行するコマンドを定義することができます。秘密鍵に関するツールらしいです。

```sh:Vagrantfile
  #89行目付近に以下を挿入。必要なツールをインストールします。またホームディレクトリ上にパスを張ってしまうため、/binにツールをコピーしておきます。
  config.vm.provision :shell, :inline => "curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/v1.0.5/scripts/bootstrap.sh | bash -s 1.0.5"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/cryptogen /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/configtxgen /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/configtxlator /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/orderer /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/peer /bin"
```

## １０．４　Nodejsインストール
HyperLedgerではNodejsを使用することができますが、8.x系までサポートされていて、最新版はサポートされていません。そのため、8.x系をインストールします。ついでにnpmの5.6.0のインストールも行っておきます（npmは最新で問題ないと思うが念のためバージョンを指定）。

```
  # nodejs 8.xをインストール
  config.vm.provision :shell, :inline => "curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -"
  config.vm.provision :shell, :inline => "sudo apt-get install -y nodejs"
  # npm 5.6.0をインストール
  config.vm.provision :shell, :inline => "sudo npm install -g npm@5.6.0"
```

## １０．５　HyperLedger Fabricのサンプルソース取得
動作確認で使用するHyperLedger Fabricのサンプルソースを取得します。ここでcdコマンドを入れているのは、この後のサンプルソース実施する中でNodejs、npmを使用しますが、サンプルソースの格納場所を共通ディレクトリ(/opt/gopath/src/github.com/hyperledger)にすると`npm install`したときにエラーになるためです。 また所有者がrootになるので所有者を`vagrant`に変更しておきます。

```sh:Vagrantfile
  # HyperLedgerのサンプルソース取得。
  config.vm.provision :shell, :inline => "cd /home/vagrant"
  config.vm.provision :shell, :inline => "git clone https://github.com/hyperledger/fabric-samples.git"
  # 所有者がrootになるので所有者を自分に変更しておく
  config.vm.provision :shell, :inline => "sudo chown -R vagrant:vagrant fabric-samples/"
```

## １０．６　共有ディレクトリ
Varantfile上で、ホストＰＣと仮想マシンの共有ディレクトリを設定しています。特に修正の必要はありませんが、変更したい場合は以下を修正してください。

```sh:Vagrantfile
#44行目付近　共通ディレクトリ　ホストＰＣ　C:\hyperledger11\　仮想マシン　/opt/gopath/src/github.com/hyperledger
  config.vm.synced_folder "../..", "/opt/gopath/src/github.com/hyperledger"
```

## １０．７　Vagrantfileまとめ
以上の修正した結果、以下のようになります。

```sh:Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Copyright IBM Corp All Rights Reserved
#
# SPDX-License-Identifier: Apache-2.0
#
# This vagrantfile creates a VM with the development environment
# configured and ready to go.
#
# The setup script (env var $script) in this file installs docker.
# This is not in the setup.sh file because the docker install needs
# to be secure when running on a real linux machine.
# The docker environment that is installed by this script is not secure,
# it depends on the host being secure.
#
# At the end of the setup script in this file, a call is made
# to run setup.sh to create the developer environment.

# This is the mount point for the sync_folders of the source
SRCMOUNT = "/hyperledger"
LOCALDEV = "/local-dev"

$script = <<SCRIPT
set -x

echo "127.0.0.1 couchdb" | tee -a /etc/hosts

cd #{SRCMOUNT}/fabric/devenv
./setup.sh

SCRIPT

Vagrant.require_version ">= 1.7.4"
Vagrant.configure('2') do |config|
  config.vm.box = "ubuntu/xenial64"
  config.disksize.size = '30GB'

  config.vm.network :forwarded_port, guest: 7050, host: 7050, id: "orderer", host_ip: "localhost", auto_correct: true # fabric orderer service
  config.vm.network :forwarded_port, guest: 7051, host: 7051, id: "peer", host_ip: "localhost", auto_correct: true # fabric peer service
  config.vm.network :forwarded_port, guest: 7053, host: 7053, id: "peer_event", host_ip: "localhost", auto_correct: true # fabric peer event service
  config.vm.network :forwarded_port, guest: 7054, host: 7054, id: "ca", host_ip: "localhost", auto_correct: true # fabric-ca service
  config.vm.network :forwarded_port, guest: 5984, host: 15984, id: "couchdb", host_ip: "localhost", auto_correct: true # CouchDB service
  config.vm.synced_folder "../..", "#{SRCMOUNT}"
  config.vm.synced_folder "../..", "/opt/gopath/src/github.com/hyperledger"
  config.vm.synced_folder ENV.fetch('LOCALDEVDIR', "../.."), "#{LOCALDEV}"
  config.vm.provider :virtualbox do |vb|
    vb.name = "hyperledger"
    vb.customize ['modifyvm', :id, '--memory', '1024']
    vb.cpus = 2

    storage_backend = ENV['DOCKER_STORAGE_BACKEND']
    case storage_backend
    when nil,"","aufs","AUFS"
      # No extra work to be done
    when "btrfs","BTRFS"
      # Add a second disk for the btrfs volume
      IO.popen("VBoxManage list systemproperties") { |f|

        success = false
        while line = f.gets do
          # Find the directory where the machine images are stored
          machine_folder = line.sub(/^Default machine folder:\s*/,"")

          if line != machine_folder
            btrfs_disk = File.join(machine_folder, vb.name, 'btrfs.vdi')

            unless File.exist?(btrfs_disk)
              # Create the disk if it doesn't already exist
              vb.customize ['createhd', '--filename', btrfs_disk, '--format', 'VDI', '--size', 20 * 1024]
            end

            # Add the disk to the VM
            vb.customize ['storageattach', :id, '--storagectl', 'SATA Controller', '--port', 1, '--device', 0, '--type', 'hdd', '--medium', btrfs_disk]
            success = true

            break
          end
        end
        raise Vagrant::Errors::VagrantError.new, "Could not provision btrfs disk" if !success
      }
    else
      raise Vagrant::Errors::VagrantError.new, "Unknown storage backend type: #{storage_backend}"
    end

  end
  config.vm.provision :shell, inline: $script
  # Add yukike
  # 必要なツールのダウンロード cryptogen,configtxgenなど
  config.vm.provision :shell, :inline => "curl -sSL https://goo.gl/byy2Qj | bash -s 1.0.5"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/cryptogen /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/configtxgen /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/configtxlator /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/orderer /bin"
  config.vm.provision :shell, :inline => "sudo cp /home/vagrant/bin/peer /bin"
  # nodejs 8.xをインストール
  config.vm.provision :shell, :inline => "curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -"
  config.vm.provision :shell, :inline => "sudo apt-get install -y nodejs"
  # npm 5.6.0をインストール
  config.vm.provision :shell, :inline => "sudo npm install -g npm@5.6.0"
  # HyperLedgerのサンプルソース取得
  config.vm.provision :shell, :inline => "cd /home/vagrant"
  config.vm.provision :shell, :inline => "git clone https://github.com/hyperledger/fabric-samples.git"
  # 所有者がrootになるので所有者を自分に変更しておく
  config.vm.provision :shell, :inline => "sudo chown -R vagrant:vagrant fabric-samples/"
end
```

## １０．８　setup.shの修正
Vagrantfileと同じフォルダにsetup.shがありますが、Vagrantfileから呼び出して、仮想マシンのセットアップを行っています。私の環境で確認したところ、setup.shの以下のdockerのコマンドでエラーになってしまいました。テストコマンドで削除しても影響ないので削除します。

```sh:setup.sh
# 58行目を削除
# Test docker
docker run --rm busybox echo All good
```

# １１．vagrantを起動し、仮想マシンを立ち上げる
コマンドプロンプトで以下のコマンドを実行し、vagrantを起動します。初回起動時は30分程度かかります。エラーなく終了すれば仮想マシンの起動完了です。エラーになってしまった場合、コマンドプロンプトで`vagrant provision`で再度設定を行うことができます。エラーになった場合でも仮想マシンは起動されていますので、仮想マシン上でコマンド入力してもOKです。

```
cd C:\hyperledger11\fabric\devenv
vagrant up
```

# １２．Tera Termを使用して、sshでログイン
仮想マシンが起動したら、Tera Termでログインします。コマンドプロンプトで`vagrant ssh`としてもログインできますが、Tera Termを使うほうがなにかと便利なのでTera Termを使用します。

ログイン画面は以下のように設定します。ポート番号はデフォルトだと22だと思いますので、2222に変更してください。
![TeraTerm_login1.png](https://qiita-image-store.s3.amazonaws.com/0/253290/03a65f32-68f7-795c-acf8-3e73244cca6b.png)
この画面では続行ボタンを押下します。
![TeraTerm_login2.png](https://qiita-image-store.s3.amazonaws.com/0/253290/2160bda8-2862-aaa9-4f93-880f79699e44.png)
秘密鍵は`C:\hyperledger11\fabric\devenv\.vagrant\machines\default\virtualbox\private_key`を指定してください
![TeraTerm_login3.png](https://qiita-image-store.s3.amazonaws.com/0/253290/9436f4cf-e658-b5dd-e567-857049748b3b.png)

# １３．起動シェル修正
以降は仮想マシン上での作業になります。以下の起動シェルを実行すれば、HyperLedgerに必要なノードが立ち上げるようになりますが、起動後にchaincodeのインストールやインスタンス化を行っています。chaincodeの定義は自分で行いたいのでここではコメントアウトします。

```sh:/home/vagrant/fabric-samples/fabcar/startFabric.sh
# この以下の行をコメントアウト
#docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode install -n fabcar -v 1.0 -p "$CC_SRC_PATH" -l "$LANGUAGE"
#docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n fabcar -l "$LANGUAGE" -v 1.0 -c '{"Args":[""]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
#sleep 10
#docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"initLedger","Args":[""]}
```

# １４．HyperLedger Fabricを起動する
HyperLedger Fabricを実行します。実行が終わったら、以下のコマンドでHyperLedgerのdockerが起動しているか確認します。以下のような画面になっていれば問題ありません。

```
#HyperLedger Fabric実行シェル(シェルの中でdockerを使用しているため`sudo`が必要)
cd /home/vagrant/fabric-samples/fabcar/
sudo ./startFabric.sh
#dockerの起動しているイメージを表示するコマンド
sudo docker ps
```

![HyperLedger_start.png](https://qiita-image-store.s3.amazonaws.com/0/253290/847851d9-2cef-2f6d-d007-4cc942dc56a5.png)

# １５．chaincodeの実行
次は動作確認のため、chaincodeを実行しますが、長くなりましたので [別のページ](https://qiita.com/yukike/private/f3654bae36e8c68e1f6c "HyperLedger v1.1でchaincodeを実行する")にまとめます。