基于Docker Swarm Mode搭建Hyperledger Fabric V1.0多主机区块链平台

这是一篇简要翻译的文章,亲测有效,因为目前关于搭建多主机hyperledger fabric的文章除了像 (http://www.cnblogs.com/studyzy/tag/Fabric/) 使用官方的 e2e_cli 代码进行部署外,其他并没有见到别的什么方式。这篇博客获得了不少的✨,所以自己搭了一遍,当然做这个的直接看原链接就可以,就当留个笔记。原文地址链接: https://medium.com/@wahabjawed/hyperledger-fabric-on-multiple-hosts-a33b08ef24f

Hyperledger Fabric 1.0及到目前最新的1.2的版本与之前的0.6版本在架构上又很大的不同,进行了模块化的解耦及对节点角色的重新定义。0.6的使用过程相对简单,简要记录一下:

  1. 启动网络:包括启动根节点,然后其他peer节点加入
  2. 部署(deploy) chaincode:可以使用SDK,也可以直接使用postman之类的可以操作restful API的工具发送POST请求,deploy结束会返回一个ChainID的字符串。
  3. 利用上一步返回的chainID,调用SDK或者使用postman实现Invoke,query,get_chainlist等操作。

1.0以后的版本中取消了restful的方式,只能使用SDK了!

如何在单机上运行

Hyperledger Fabric的运行是依赖于Docker的,各组件运行在不同的容器中,为了使这些容器彼此通信,可以通过创建一个网络然后将容器加入进去,当运行官方示例fabric-samplesFirst Network时,主要是运行 docker-compose-cli.yaml文件,从中可以看出,创建了一个byfn网络,然后所有容器attach到这个网络中。

Hyperledger Fabric给出了很好的关于单机运行的示例,即在同一主机上运行多个不同的docker容器,通过不同端口来模拟多主机之间的通信,但在实际环境中,我们需要将服务运行在多主机的分布式系统中。

如何在多主机上运行

当需要在多主机上运行hyperledger fabric时,容器之间不能直接进行互相通信(因为docker会自动分配不同的子网地址给每个容器)。因此,需要有一种方式使得这多个主机上的容器能相互进行通信(其实跨主机容器通信可以通过一些方法来实现,比如使用OVS+GREFlannel或者直接路由等方式)。现在,我们直接可以使用docker swarm来实现(具体可查看docker swarm的官方文档)。

网络拓扑结构

将要构建的网络架构如下图所示,该架构中包含了最基本的Hyperledger Fabric 1.0的组件,我们只需要两台主机,组件分布为包括:

  • 1个CA服务(在节点 1 上)
  • 1个Orderer排序服务(在节点 1 上)
  • 1个普通节点Peer0 (组织 1 的节点 0, 在节点 1 上)
  • 一个CouchDB0 (连接到Peer0来存储状态,在节点 1上)
  • 一个CouchDB1 (连接到Peer1来存储状态,在节点 2上)
  • 1个普通节点Peer1 (组织 1 的节点 1, 在节点 2 上)
  • 1个客户端Cli(在节点 2 上)

对于这两台主机:
节点1: 192.168.245.235 (Ubuntu 16.04)
节点2:192.168.245.236 (Ubuntu 16.04)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pN48v2f8-1596319710406)(https://cdn-images-1.medium.com/max/1600/1*3-DR8ffADZyN3k_hyv_1fQ.png)]

现在开始整个搭建过程。

创建 Docker Swarm Mode 网络

  • 初始化 swarm (更多详情参见docker swarm官方文档),在节点1上执行
$ docker swarm init

后续过程概述为:节点1创建swarm,然后节点2manager身份加入创建的swarm中。

  • 节点1上执行:
$ docker swarm join-token manager

输出就会像是:

docker swarm join — token SWMTKN-1–3as8cvf3yxk8e7zj98954jhjza3w75mngmxh543llgpo0c8k7z-61zyibtaqjjimkqj8p6t9lwgu 192.168.245.235:2377

复制这段命令,然后在节点2中执行,成功输出结果会是一个字符串,这个不再理会。

  • 节点1上执行如下命令创建网络:
$ docker network create --attachable --driver overlay mynetwork

mynetwork是网络名称,可以自己取,但后续配置需要保持一致
使用docker network ls可以查看目前docker中有哪些网络。

  • 克隆仓库到主机上。分别在节点1节点2上执行:
$ git clone https://github.com/hesonglin006/Build-Multi-Host-Network-Hyperledger.git
  • 创建网络的Artifacts。在节点1上:
cd Build-Multi-Host-Network-Hyperledger/
./bmhn.sh

上述命令会执行bmhn.sh这个脚本文件,创建所需要的身份认证文件,证书和密钥等。运行成功后,可以看到当前目录下会有crypto-configchannel-artifacts这两个文件夹,复制这两个文件夹到节点2同样的位置(放到节点2的Build-Multi-Host-Network-Hyperledger文件夹下)。

设置网络

如前面所述,在节点1上需要运行一个CA服务,一个Orderer服务,一个Peer0还有一个CouchDB0,下面将使用脚本依次启动:

  • CA 服务
    创建脚本,给与execute权限,然后执行,脚本内容为:
#!/bin/sh
docker run --rm \
-it \
--network="mynetwork" \
--name ca.example.com \
-p 7054:7054 \
-e FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server-config \
-e FABRIC_CA_SERVER_CA_NAME=ca.example.com \
-e FABRIC_CA_SERVER_CA_CERTFILE=/etc/hyperledger/fabric-ca-server-config/ca.org1.example.com-cert.pem \
-e FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/{替换成自己实际的key} \
-v $(pwd)/crypto-config/peerOrganizations/org1.example.com/ca/:/etc/hyperledger/fabric-ca-server-config \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork hyperledger/fabric-ca sh \
-c 'fabric-ca-server start -b admin:adminpw -d'
  • Orderer 服务
#!/bin/sh
docker run --rm -it \
--network="mynetwork" \
--name orderer.example.com \
-p 7050:7050 \
-e ORDERER_GENERAL_LOGLEVEL=debug \
-e ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 \
-e ORDERER_GENERAL_LISTENPORT=7050 \
-e ORDERER_GENERAL_GENESISMETHOD=file \
-e ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block \
-e ORDERER_GENERAL_LOCALMSPID=OrdererMSP \
-e ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp \
-e ORDERER_GENERAL_TLS_ENABLED=false \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork \
-v $(pwd)/channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block \
-v $(pwd)/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp \
-w /opt/gopath/src/github.com/hyperledger/fabric hyperledger/fabric-orderer orderer
  • CouchDB0用来连接到Peer0
#!/bin/sh
docker run --rm -it \
--network="mynetwork" \
--name couchdb0 \
-p 5984:5984 \
-e COUCHDB_USER=admin \
-e COUCHDB_PASSWORD=password \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork hyperledger/fabric-couchdb
  • Peer0
#!/bin/sh
docker run --rm -it \
--link orderer.example.com:orderer.example.com \
--network="mynetwork" \
--name peer0.org1.example.com \
-p 8051:7051 \
-p 8053:7053 \
-e CORE_LEDGER_STATE_STATEDATABASE=CouchDB \
-e CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0:5984 \
-e CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin \
-e CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password \
-e CORE_PEER_ADDRESSAUTODETECT=true \
-e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
-e CORE_LOGGING_LEVEL=DEBUG \
-e CORE_PEER_NETWORKID=peer0.org1.example.com \
-e CORE_NEXT=true \
-e CORE_PEER_ENDORSER_ENABLED=true \
-e CORE_PEER_ID=peer0.org1.example.com \
-e CORE_PEER_PROFILE_ENABLED=true \
-e CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer.example.com:7050 \
-e CORE_PEER_GOSSIP_IGNORESECURITY=true \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork \
-e CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051 \
-e CORE_PEER_TLS_ENABLED=false \
-e CORE_PEER_GOSSIP_USELEADERELECTION=false \
-e CORE_PEER_GOSSIP_ORGLEADER=true \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-v /var/run/:/host/var/run/ \
-v $(pwd)/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp \
-w /opt/gopath/src/github.com/hyperledger/fabric/peer hyperledger/fabric-peer peer node start

如果都启动成功,使用 docker ps 查看正处在运行状态的容器,如下图所示:
pic1
接下来在节点2上执行脚本,启动一个Peer1服务及CouchDB1的服务:

  • CouchDB1用来连接到Peer1
#!/bin/sh
docker run --rm -it \
--network="mynetwork" \
--name couchdb1 \
-p 6984:5984 \
-e COUCHDB_USER=admin \
-e COUCHDB_PASSWORD=password \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork hyperledger/fabric-couchdb
  • Peer1
#!/bin/sh
docker run --rm -it \
--network="mynetwork" \
--link orderer.example.com:orderer.example.com \
--link peer0.org1.example.com:peer0.org1.example.com \
--name peer1.org1.example.com \
-p 9051:7051 \
-p 9053:7053 \
-e CORE_LEDGER_STATE_STATEDATABASE=CouchDB \
-e CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb1:5984 \
-e CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin \
-e CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=password \
-e CORE_PEER_ADDRESSAUTODETECT=true \
-e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
-e CORE_LOGGING_LEVEL=DEBUG \
-e CORE_PEER_NETWORKID=peer1.org1.example.com \
-e CORE_NEXT=true \
-e CORE_PEER_ENDORSER_ENABLED=true \
-e CORE_PEER_ID=peer1.org1.example.com \
-e CORE_PEER_PROFILE_ENABLED=true \
-e CORE_PEER_COMMITTER_LEDGER_ORDERER=orderer.example.com:7050 \
-e CORE_PEER_GOSSIP_ORGLEADER=true \
-e CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051 \
-e CORE_PEER_GOSSIP_IGNORESECURITY=true \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork \
-e CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051 \
-e CORE_PEER_GOSSIP_USELEADERELECTION=false \
-e CORE_PEER_TLS_ENABLED=false \
-v /var/run/:/host/var/run/ \
-v $(pwd)/crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp \
-w /opt/gopath/src/github.com/hyperledger/fabric/peer hyperledger/fabric-peer peer node start
  • 客户端Cli
#!/bin/sh
docker run --rm -it \
--network="mynetwork" \
--name cli \
--link orderer.example.com:orderer.example.com \
--link peer0.org1.example.com:peer0.org1.example.com \
--link peer1.org1.example.com:peer1.org1.example.com \
-p 12051:7051 \
-p 12053:7053 \
-e GOPATH=/opt/gopath \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_TLS_ENABLED=false \
-e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
-e CORE_LOGGING_LEVEL=DEBUG \
-e CORE_PEER_ID=cli \
-e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \
-e CORE_PEER_NETWORKID=cli \
-e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork \
-v /var/run/:/host/var/run/ \
-v $(pwd)/chaincode/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go \
-v $(pwd)/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ \
-v $(pwd)/scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ \
-v $(pwd)/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts \
-w /opt/gopath/src/github.com/hyperledger/fabric/peer hyperledger/fabric-tools /bin/bash -c './scripts/script.sh'

执行Cli的脚本,实际上将会执行当前目录下./scripts/script.sh,其将会:

  • 创建通道,实例中通道名称为mychannel
  • Peer0Peer1加入通道
  • 一旦成功加入通道,更新锚节点(即组织中负责和排序节点通信的节点,可以静态指定,也可以执行选举算法选出)
  • 在两个peer上安装链码
    如果运行成功,会出现下图所示:
    pic3

节点2运行完上述脚本后,会启动三个容器,如下图所示:
pic2

测试网络

进入CLI容器中

现在网络运行起来了,我们需要从节点2上invoke链码到两个peer上,在节点 2 上执行:

#!/bin/sh
docker run --rm -it \
--network="mynetwork" \
--name cli \
--link orderer.example.com:orderer.example.com \
--link peer0.org1.example.com:peer0.org1.example.com \
--link peer1.org1.example.com:peer1.org1.example.com \
-p 12051:7051 \
-p 12053:7053 \
-e GOPATH=/opt/gopath \
-e CORE_PEER_LOCALMSPID=Org1MSP \
-e CORE_PEER_TLS_ENABLED=false \
-e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
-e CORE_LOGGING_LEVEL=DEBUG \
-e CORE_PEER_ID=cli \
-e CORE_PEER_ADDRESS=peer0.org1.example.com:7051 \
-e CORE_PEER_NETWORKID=cli \
-e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp \
-e CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=mynetwork \
-v /var/run/:/host/var/run/ \
-v $(pwd)/chaincode/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go \
-v $(pwd)/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ \
-v $(pwd)/scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ \
-v $(pwd)/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts \
-w /opt/gopath/src/github.com/hyperledger/fabric/peer hyperledger/fabric-tools /bin/bash

执行上述脚本后,会进入到CLI 容器中,我们将会执行命令来instantiate,invoke和query容器中的链码。
pic4

####实例化链码####
首先需要设置一些环境变量,粘贴如下的环境变量设置命令到刚才进入的CLI容器中:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp

CORE_PEER_LOCALMSPID="Org1MSP"

CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

CORE_PEER_ADDRESS=peer0.org1.example.com:7051

现在我们可以初始化链码,在刚才的CLI容器中继续执行:

peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"

该命令将会初始化链码并且设置初始值为:a=100,b=200。

此时,可以通过couchDBweb界面来查看,因为数据是以二进制来保存的,所以不会看到实际的值(事实上是hash值)但可以看到包括键mycca的记录。

节点1上:
http://localhost:5984/_utils/#/database/mychannel/_all_docs,可以看到:
pic5

节点2上:
http://localhost:6984/_utils/#/database/mychannel/_all_docs,可以看到:
pic6

####在Peer1上查询链码####
在节点2上,还是在刚才的CLI容器中,首先需要设置环境变量,代码如下:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp

CORE_PEER_LOCALMSPID="Org1MSP"

CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

CORE_PEER_ADDRESS=peer1.org1.example.com:7051

为了确认链码已经被正确安装且couchDB中的状态值已经被正确初始化,我们先来查询一下a的值:

peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'

结果如下所示:
pic7
可以看出此时a的值为100

####在Peer0上Invoke链码####
还是在节点2上的CLI容器中,首先需要更改环境变量,执行如下代码:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp

CORE_PEER_LOCALMSPID="Org1MSP"

CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

CORE_PEER_ADDRESS=peer0.org1.example.com:7051

现在执行invoke操作,主要是从a转10给b,代码如下:

peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n mycc -c '{"Args":["invoke","a","b","10"]}'

执行结果如下:
pic8

####查询链码####
经过刚才的转账操作后,现在a的值应该变为了90,我们从peer0上查询看看结果,执行代码如下:

peer chaincode query -C mychannel -n mycc -c '{"Args":["query","a"]}'

结果如图:
pic9

从图中可以看出,a的值已经为了90,同理,查看b的值,已经变为了210
pic10

通过以上步骤,恭喜!你已经搭建好了多主机环境的基于Hyperledger Fabric 1.0的区块链平台。

后续应该通过使用SDK(目前Go和NodeJS已经相对完善,Python处于开发中)来完成对区块链平台的开发。

####写在后面####
区块链能否落地将是目前区块链发展中最为重要的一点,目前各种应用及场景都在探索中(物联网,供应链,征信,众筹等等等等)。

未来FinTech2.0的三驾马车:认知物联网+区块链+人工智能

Keep Fighting!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页
评论

打赏作者

zhiaini06

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值