超级账本 Hyperledger Fabric2.0 多机集群部署

基于Raft排序的Fabric2.0 多机集群部署教程

基于Raft排序的Fabric2.0 多机集群部署

Fabric运行环境go语言,docker等自行搭建,该处不进行描述。
Raft是Hyperledger Fabric 1.4.1中新增的排序服务模块,这个教程将介绍如何部署一个基于Raft排序服务的多机Fabric2.0网络。

1、用Raft排序服务启动byfn示例

BYFN是学习Hyperledger Fabric的一个很好的例子:它包含了Fabric网络的所有元素,并且在byfn.sh中完整表现出来。当我们不加任何参数运行这个脚本时,它将启动一个包含2个机构、4个peer和1个orderer(使用solo排序)的Fabric网络。byfn.sh的参数-o用来指定排序服务的类型:

# 2.0以后默认是 etcdraft -i指定docker容器版本。 eg:./byfn.sh up -i 2.0.1
./byfn.sh up -o <kafka | etcdraft> -i  <imagetag>

最新的BYFN网络设计中包含了5个orderer的密码学资料。如果使用Solo或Kafka排序服务,将值运行第一个Orderer(参见docker-compose-cli.yaml中的定义)。

当我们指定raft作为排序服务时的一个区别之处在于,使用configtxgen生成创世区块我们需要指定configtx.yaml中的SampleMultiNodeEtcdRaft配置端。其他的操作都保持不变。

最后,我们还需要启动其他4个orderer,这些内容在docker-compose-etcdraft2.yaml中定义。

下面时基于raft排序的BYFN网络启动后的情况,你可以看到有5个orderer在运行:

超级账本 Hyperledger Fabric2.0 多机集群部署
下面是基于Raft排序服务的BYFN网络的拓扑示意图:

超级账本 Hyperledger Fabric2.0 多机集群部署
在下面的内容中,我们将不再使用BYFN脚本,而是从零开始来学习如何构建多主机的Raft排序的Fabric网络。

2、Hyperledger Fabric多机部署的不同方案

由于Hyperledger Fabric的组件以容器形式部署,当这些容器都在本机时会很顺利的工作。但是当这些容器需要运行在不同的主机上时,我们需要找出让它们彼此通信的办法。

虽然Hyperledger Fabric官方没有给出正式的推荐方案,目前大致有三种方案:

使用静态IP:通过指定容器运行的主机IP,容器之间就可以彼此通信。可以在docker-compose文件中使用extra_hosts方法来指定主机IP,当容器运行后,就可以在/etc/hosts文件中看到这些项。这一方案容易理解,我们也不需要依赖于外部组件,缺点在于所有的东西都是静态配置的,不利于需要动态修改配置的应用场景。

使用docker swarm:Docker Swarm是Docker环境中的原生容器编排服务。简而言之,Docker Swarm为跨主机的容器提供了一个叠加网络层,使容器彼此之间能够通信,就像在一台主机上一样。这一方案的好处在于原始的配置只需要简单修改就可以使用,也不需要在配置中硬编码像IP地址这样的静态信息。缺点在于需要依赖外部组件Docker Swarm。在这个教程中我们将使用这一方案。

使用Kubernetes:k8s使目前最流行的容器编排工具,其机制类似于Docker Swarm。我们已经注意到有一些教程尝试利用k8s来进行fabric的多机部署,但是使用k8s的难度要明显高于前两种方案。

3、Fabrc2.0 Raft多机演示环境搭建

我们需要将容器分发到4个主机,本教程使用的是局域网下的四台主机。系统为Ubuntu和centos均可以。可以自己随便设置,保证能互相联通
分别为:

  1. 192.168.1.156,作为host1
  2. 192.168.1.25, 作为host2
  3. 192.168.1.27, 作为host3
  4. 192.168.1.27, 作为host4

超级账本 Hyperledger Fabric2.0 多机集群部署
在Fabric网络启动运行后,我们将使用Fabcar链码进行测试。总体流程如下:

  • 准备4台可以互相通信的主机,均为linu内核。
  • 构建一个叠加网络,将4个主机都加入该网络
  • 在主机1上准备所有资料,包括密码学资料、通道配置交易、每个节点的docker-compose文件等。然后拷贝到其他主机。
  • 使用docker-compose启动所有组件
  • 创建通道mychannel并将所有peer加入该通道
  • 安装并实例化Fabcar链码
  • 调用查询链码方法

4、Fabric Raft多机演示

4.1 准备主机

该处不进行详细说明。

4.2 使用Docker Swarm构建叠加网络

现在我们可以打开4个终端,分别对应每个主机:

# eg:  ssh -i root@192.168.1.156 -p 22
ssh -i <key> ubuntu@<public IP> -p <port>

从Host 1执行如下命令:

# 本例中我选择的是192.168.1.156作为主机
# 执行命令 docker swarm init --advertise-addr 192.168.1.156
docker swarm init --advertise-addr <host-1 ip address>
docker swarm join-token manager

运行结果如下:

超级账本 Hyperledger Fabric2.0 多机集群部署
使用最后的输出,将其他节点以管理者身份加入swarm。
此处为:

docker swarm join --token SWMTKN-1-1xf0ab69g80df3awfclw82iv5n35hto2cjhgkbvcywtg4vhw6z-		977vgxp1hjo8gxzq23dkxi164 192.168.1.156:2377

从host 2/3/4执行如下命令:

docker swarm join --token SWMTKN-1-1xf0ab69g80df3awfclw82iv5n35hto2cjhgkbvcywtg4vhw6z-		977vgxp1hjo8gxzq23dkxi164 192.168.1.156:2377  

超级账本 Hyperledger Fabric2.0 多机集群部署
从host 1创建叠加网络first-network:

docker network create --attachable --driver overlay first-network
docker network ls

运行结果为:

超级账本 Hyperledger Fabric2.0 多机集群部署
在其他3台主机上,我们可以看到这个网络:

超级账本 Hyperledger Fabric2.0 多机集群部署
超级账本 Hyperledger Fabric2.0 多机集群部署
超级账本 Hyperledger Fabric2.0 多机集群部署

4.3 在host 1上准备资料

一个关键的环节时确保所有的Farbic成员使用相同的密码学资料。我们将使用host 1来创建这些密码学资料,然后拷贝到其他主机。

理论上,我们只需要确保个体身份(证书和签名私钥)遵循所要求的规范。一个机构的证书应当由同一个CA签发 —— 例如org1的证书应当由ca.org1签发。出于简化目的,在本教程中,我们在host 1上创建所有的密码学资料,然后将整个目录拷贝到其他主机。

首先进入fabric-samples目录,如果还没有fabric-samples,自行在github上面去当去该项目,然后创建一个raft-4node-swarm目录。

在host 1上执行如下命令:

cd fabric-samples
mkdir raft-4node-swarm
cd raft-4node-swarm

直接从first-network拷贝crypto-config.yaml和configtx.yaml文件:

cp ../first-network/crypto-config.yaml .
cp ../first-network/configtx.yaml .
mkdir scripts
cp ../first-network/scripts/* ./scripts

其中 crypto-config.yaml 用于生成MSP相关证书,育有组织架构和节点数和first-network一样,所以不作修改。
其中configtx.yaml用于生成创世区块,交易通道配置等,由于节点的通信地址变化,所以共识机制配置中排序节点的通信地址要更改,更改内容如下:

更改前:
超级账本 Hyperledger Fabric2.0 多机集群部署
超级账本 Hyperledger Fabric2.0 多机集群部署
更改后:
超级账本 Hyperledger Fabric2.0 多机集群部署

超级账本 Hyperledger Fabric2.0 多机集群部署

然后根据配置文件生成必要的密码学资料:

../bin/cryptogen generate --config=./crypto-config.yaml
export FABRIC_CFG_PATH=$PWD
mkdir channel-artifacts
../bin/configtxgen -profile SampleMultiNodeEtcdRaft -outputBlock ./channel-artifacts/genesis.block -channelID byfn-sys-channel
../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

现在我们为所有主机准备docker-compose文件,主要基于BYFN中的文件,需要创建6个docker-compose文件以及一个env文件:

  • base/peer-base.yaml
  • base/docker-compose-peer.yaml
  • host1.yaml
  • host2.yaml
  • host3.yaml
  • host4.yaml
  • .env

4.3.1 base/peer-base.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

services:
  peer-base:
    image: hyperledger/fabric-peer:$IMAGE_TAG
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      # the following setting starts chaincode containers on the same
      # bridge network as the peers
      # https://docs.docker.com/compose/networking/
      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=first-network
      - FABRIC_LOGGING_SPEC=INFO
      #- FABRIC_LOGGING_SPEC=DEBUG
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start

  orderer-base:
    image: hyperledger/fabric-orderer:$IMAGE_TAG
    environment:
      - FABRIC_LOGGING_SPEC=INFO
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
      # enabled TLS
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
      - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
      - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
      - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1
      - ORDERER_KAFKA_VERBOSE=true
      - ORDERER_GENERAL_CLUSTER_CLIENTCERTIFICATE=/var/hyperledger/orderer/tls/server.crt
      - ORDERER_GENERAL_CLUSTER_CLIENTPRIVATEKEY=/var/hyperledger/orderer/tls/server.key
      - ORDERER_GENERAL_CLUSTER_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: orderer

4.3.2 base/docker-compose-base.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

services:

  orderer.example.com:
    container_name: orderer.example.com
    extends:
      file: peer-base.yaml
      service: orderer-base
    volumes:
        - ../channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
        - ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
        - ../crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
        - orderer.example.com:/var/hyperledger/production/orderer
    ports:
      - 7050:7050

  peer0.org1.example.com:
    container_name: peer0.org1.example.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.org1.example.com
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org1.example.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org1.example.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls:/etc/hyperledger/fabric/tls
        - peer0.org1.example.com:/var/hyperledger/production
    ports:
      - 7051:7051

  peer1.org1.example.com:
    container_name: peer1.org1.example.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer1.org1.example.com
      - CORE_PEER_ADDRESS=peer1.org1.example.com:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer1.org1.example.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls:/etc/hyperledger/fabric/tls
        - peer1.org1.example.com:/var/hyperledger/production
    ports:
      - 7051:7051

  peer0.org2.example.com:
    container_name: peer0.org2.example.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.org2.example.com
      - CORE_PEER_ADDRESS=peer0.org2.example.com:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org2.example.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer1.org2.example.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls:/etc/hyperledger/fabric/tls
        - peer0.org2.example.com:/var/hyperledger/production
    ports:
      - 7051:7051

  peer1.org2.example.com:
    container_name: peer1.org2.example.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer1.org2.example.com
      - CORE_PEER_ADDRESS=peer1.org2.example.com:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer1.org2.example.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.example.com:7051
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.example.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
    volumes:
        - /var/run/:/host/var/run/
        - ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/msp:/etc/hyperledger/fabric/msp
        - ../crypto-config/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls:/etc/hyperledger/fabric/tls
        - peer1.org2.example.com:/var/hyperledger/production
    ports:
      - 7051:7051

4.3.3 host1.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

volumes:
  orderer.example.com:
  orderer5.example.com:
  peer0.org1.example.com:

networks:
  byfn:
    external:
      name: first-network

services:

  orderer.example.com:
    extends:
      file:   base/docker-compose-base.yaml
      service: orderer.example.com
    container_name: orderer.example.com
    networks:
      - byfn

  orderer5.example.com:
    extends:
      file: base/peer-base.yaml
      service: orderer-base
    container_name: orderer5.example.com
    networks:
    - byfn
    volumes:
        - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer5.example.com/msp:/var/hyperledger/orderer/msp
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer5.example.com/tls/:/var/hyperledger/orderer/tls
        - orderer5.example.com:/var/hyperledger/production/orderer
    ports:
    - 8050:7050

  peer0.org1.example.com:
    container_name: peer0.org1.example.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.org1.example.com
    networks:
      - byfn

  cli:
    container_name: cli
    image: hyperledger/fabric-tools:$IMAGE_TAG
    tty: true
    stdin_open: true
    environment:
      - SYS_CHANNEL=$SYS_CHANNEL
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      #- FABRIC_LOGGING_SPEC=DEBUG
      - FABRIC_LOGGING_SPEC=INFO
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.org1.example.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
      - 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_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
        - /var/run/:/host/var/run/
        - ./../chaincode/:/opt/gopath/src/github.com/chaincode
        - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
        - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
        - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    depends_on:
      - orderer.example.com
      - peer0.org1.example.com
    networks:
      - byfn

4.3.4 host2.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

volumes:
  orderer2.example.com:
  peer1.org1.example.com:

networks:
  byfn:
    external:
      name: first-network

services:

  orderer2.example.com:
    extends:
      file: base/peer-base.yaml
      service: orderer-base
    container_name: orderer2.example.com
    networks:
    - byfn
    volumes:
        - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/msp:/var/hyperledger/orderer/msp
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer2.example.com/tls/:/var/hyperledger/orderer/tls
        - orderer2.example.com:/var/hyperledger/production/orderer
    ports:
    - 7050:7050

  peer1.org1.example.com:
    container_name: peer1.org1.example.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer1.org1.example.com
    networks:
      - byfn

4.3.5 host3.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

volumes:
  orderer3.example.com:  
  peer0.org2.example.com:

networks:
  byfn:
    external:
      name: first-network

services:

  orderer3.example.com:
    extends:
      file: base/peer-base.yaml
      service: orderer-base
    container_name: orderer3.example.com
    networks:
    - byfn
    volumes:
        - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/msp:/var/hyperledger/orderer/msp
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer3.example.com/tls/:/var/hyperledger/orderer/tls
        - orderer3.example.com:/var/hyperledger/production/orderer
    ports:
    - 7050:7050

  peer0.org2.example.com:
    container_name: peer0.org2.example.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.org2.example.com
    networks:
      - byfn

4.3.6 host4.yaml

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

version: '2'

volumes:
  orderer4.example.com:
  peer1.org2.example.com:

networks:
  byfn:
    external:
      name: first-network

services:

  orderer4.example.com:
    extends:
      file: base/peer-base.yaml
      service: orderer-base
    container_name: orderer4.example.com
    networks:
    - byfn
    volumes:
        - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer4.example.com/msp:/var/hyperledger/orderer/msp
        - ./crypto-config/ordererOrganizations/example.com/orderers/orderer4.example.com/tls/:/var/hyperledger/orderer/tls
        - orderer4.example.com:/var/hyperledger/production/orderer
    ports:
    - 7050:7050

  peer1.org2.example.com:
    container_name: peer1.org2.example.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer1.org2.example.com
    networks:
      - byfn

4.3.7 .env

COMPOSE_PROJECT_NAME=net
IMAGE_TAG=2.0.0
SYS_CHANNEL=byfn-sys-channel

下面是目录中的内容:

超级账本 Hyperledger Fabric2.0 多机集群部署
下面是针对BYFN中的文件所作的修改:

  • base/peer-base.yaml中,CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE修改为
    我们之前创建的叠加网络first-network
  • base/docker-compose-base.yaml中,由于所有的peers都在不同的主机上,我们
    将端口映射改回7051:7051。在每个peer的环境变量中也进行了相应的修改。
  • 在所有的hostn.yaml文件中,我们添加叠加网络first-network

现在我们在host 1上准备好了所有资料,将该目录拷贝到其他主机。由于不能跨EC2实例拷贝文件,我们使用本地机器进行桥接操作,将准备好的文件分别发送到其他3台主机上去:

# 在host1上执行
cd ..
tar cf raft-4node-swarm.tar raft-4node-swarm
scp raft-4node-swarm.tar root@192.168.1.25:/root/go/src/github.com/hyperledger/fabric-samples
scp raft-4node-swarm.tar root@192.168.1.27:/root/go/src/github.com/hyperledger/fabric-samples
scp raft-4node-swarm.tar root@192.168.1.28:/root/go/src/github.com/hyperledger/fabric-samples
#在host1、host2、host3上分别执行
cd /root/go/src/github.com/hyperledger/fabric-samples
rm -rf raft-4node-swarm
tar xf raft-4node-swarm.tar
cd raft-4node-swarm

现在所有的节点都有了同样的密码学资料和docker-compose文件,我们可以启动容器了。

4.4 分别启动各主机上的容器

注意在启动前,检查各主机上的docker环境是否一致?最好保持一致,重点检查一下docker使用的阿里镜像地址是否一致。

我们使用docker-compose启动全部主机:

# on Host 1, 2, 3 and 4, bring up corresponding yaml file
docker-compose -f hostn.yaml up -d

为mychannel通道创建创世区块:

docker exec cli peer channel create -o orderer.example.com:7050 -c mychannel \
       -f ./channel-artifacts/channel.tx --tls true \
       --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

执行成功后:
超级账本 Hyperledger Fabric2.0 多机集群部署
将peer0.org1加入mychannel:

docker exec cli peer channel join -b mychannel.block

将peer1.org1加入mychannel:

docker exec -e CORE_PEER_ADDRESS=peer1.org1.example.com:7051 \
       -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/ca.crt \
       cli peer channel join -b mychannel.block

将peer0.org2加入mychannel:

docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \
       -e CORE_PEER_ADDRESS=peer0.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \
       -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
       cli peer channel join -b mychannel.block

将peer1.org2 加入mychannel:

docker exec -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp \
       -e CORE_PEER_ADDRESS=peer1.org2.example.com:7051 -e CORE_PEER_LOCALMSPID="Org2MSP" \
       -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt \
       cli peer channel join -b mychannel.block

4.6 安装并实例化Fabcar链码

进入到docker的cli终端

docker exec -it cli bash

查看环境变量

env

超级账本 Hyperledger Fabric2.0 多机集群部署

重点关注

  • CORE_PEER_LOCALMSPID=Org2MSP
  • CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peer
  • Organizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
  • CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
  • CORE_PEER_ADDRESS=peer0.org2.example.com:7051

4.6.1 打包合约

由于要打包合约此处我们使用 peer lifecycle chaincode package
在容器内部执行命令

peer lifecycle chaincode package mycc1.tar.gz --path /opt/gopath/src/github.com/chaincode/abstore/go/ --lang golang --label mycc_1
mycc2.tar.gz :打包合约包文件名 
--path 智能合约路径,可以在host1.yaml中查看cli容器的数据卷配置查询
--lang 智能合约语言 支持golang、node、java
--label  智能合约标签,描述作用

执行完成后,查看当前目录,出现mycc1.tar.gz
超级账本 Hyperledger Fabric2.0 多机集群部署

4.6.2 部署合约到节点

继续在cli执行以下命令

# mycc2.tar.g 智能合约打包位置
peer lifecycle chaincode install mycc1.tar.gz

控制台输出
超级账本 Hyperledger Fabric2.0 多机集群部署
验证合约安装是否安装到节点

peer lifecycle chaincode queryinstalled

出现如下结果表示安装成功
超级账本 Hyperledger Fabric2.0 多机集群部署
但是此时,在宿主机执行 docker ps 发现目前合约容器还未启动。

4.6.3 当前组织同意合约定义

2.0智能合约由合约定义控制。当通道成员批准合约定义时,该批准作为组织对其接受的合约参数的投票。这些经过批准的组织定义允许通道成员在链码在通道上使用之前对链码达成一致。链码定义包括以下参数,这些参数需要在组织之间保持一致:

名称: 智能合约名称
版本: 与给定的合约包相关联的版本号或值。如果您升级了合约二进制文件,那么您也需要更改合约版本。
序列: 定义链码的次数。此值为整数,用于跟踪合约升级。例如,当您第一次安装并批准一个chaincode定义时,序列号将是1。下次升级合约时,序列号将增加到2。
背书策略: 哪些组织需要执行和验证事务输出。背书策略可以表示为传递给CLI或SDK的字符串,也可以在通道配置中引用策略。默认情况下,背书策略被设置为通道/应用程序/背书,这默认要求通道中的大多数组织对交易进行背书。
集合配置: 指向与您的chaincode关联的私有数据集合定义文件的路径。有关私有数据收集的更多信息,请参见私有数据体系结构参考。
初始化: 所有的链码需要包含一个初始化函数来初始化链码。默认情况下,这个函数永远不会执行。但是,您可以使用chaincode定义来请求Init函数是可调用的。如果请求执行Init,则fabric将确保在调用任何其他函数之前调用Init,并且只调用一次。
ESCC/VSCC插件: 自定义认证或验证插件的名称。

cli容器输入以下命令:

peer lifecycle chaincode approveformyorg --tls true \
 --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
 --channelID mychannel --name mycc1 --version 1 --init-required --package-id mycc_1:aa699dad960f7244415b3133713bb5222657382e1694c926f175bf177f573737 --sequence 1 --waitForEvent

命令解释:

--tls 是否启动tls
--ca ca证书路径
--channelID 智能合约安装通道
--name 合约名
--version 合约版本
--package-id queryinstalled查询的合约ID
--sequence 序列号
--waitForEvent 等待peer提交交易返回
--init-required 合约是否必须执行init

执行成功后控制台日志:
超级账本 Hyperledger Fabric2.0 多机集群部署能看到通过orderer.example.com产生了一个交易

4.6.4 检查合约定义是否满足策略

2.0的智能合约的部署必须满足一定合约定义策略,策略的定义在通道配置中具体定义
控制台输入以下命令:

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name mycc1  --version 1 --sequence 1 --output json --init-required

输出以下结果,可以得知当前合约获取了Org1MSP的同意,参考4.6.3,而还没得到Org2MSP的定义
超级账本 Hyperledger Fabric2.0 多机集群部署

查看原本的lifecycle策略定义是满足过半数即可
超级账本 Hyperledger Fabric2.0 多机集群部署

现在明显不满足,我们还是执行commit合约看一下会怎么样
超级账本 Hyperledger Fabric2.0 多机集群部署
chaincode definition not agreed to by this org (Org2MSP) 链码合约定义还没取得Org2MSP的同意

这时候我们需要把Org2MSP也同意这个合约定义,切换环境变量为peer0.org2.example.com的配置

export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051

重复执行4.6.2 跟4.6.3操作后,再执行策略查询,可以看到两个都true了,满足策略。
超级账本 Hyperledger Fabric2.0 多机集群部署

4.6.5 提交合约

在满足合约定义的策略后,可以提交合约
控制台执行以下命令提交合约

peer lifecycle chaincode commit -o orderer.example.com:7050 \
 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
 --channelID mychannel --name mycc1 --peerAddresses peer0.org1.example.com:7051 \
 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
 --peerAddresses peer0.org2.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
 --version 1 --sequence 1 --init-required
--tls 是否启动tls
--ca ca证书路径
--channelID 智能合约安装通道
--name 合约名
--version 合约版本
--package-id queryinstalled查询的合约ID
--sequence 序列号
--waitForEvent 等待peer提交交易返回
--init-required 合约是否必须执行init
--peerAddresses 节点路径 
--tlsRootCertFiles 节点ca根证书路径(--peerAddresses --tlsRootCertFiles  连用,可多个节点,多个节点即将合约部署到对应节点集合上)

控制台输出日志:
超级账本 Hyperledger Fabric2.0 多机集群部署

在宿主机中查看智能合约容器,此时合约容器已经启动
超级账本 Hyperledger Fabric2.0 多机集群部署

4.6.6 查看节点已提交合约

cli容器内输入以下命令

peer lifecycle chaincode querycommitted --channelID mychannel --name mycc1

超级账本 Hyperledger Fabric2.0 多机集群部署

4.6.7 操作合约

fabric智能合约操作主要有invoke跟query,此处与1.x完全一致
初始化合约,执行init方法,设置a:100 b:100

 peer chaincode invoke -o orderer.example.com:7050 --tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel -n mycc1 --peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses peer0.org2.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt \
--isInit -c '{"Args":["Init","a","100","b","100"]}'

控制台输出:

2020-04-20 09:18:48.685 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

查询a的余额

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

输出值为100

#调用 invoke方法, a ->b 转账20

peer chaincode invoke -o orderer.example.com:7050 --tls true \
--cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem \
-C mychannel -n mycc1 --peerAddresses peer0.org1.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt \
--peerAddresses peer0.org2.example.com:7051 \
--tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt  \
-c  '{"Args":["invoke","a","b","20"]}' 

再次查询a时,输出为80

5、总结

在本教程中,我们基于BYFN示例进行修改,构建了一个基于Raft排序集群的
Hyperledger Fabric2.0网络,使用Docker Swarm来实现多主机容器的通信。

参考:

  • https://blog.csdn.net/qq_28540443/article/details/104318163
  • https://yq.aliyun.com/articles/740509
上一篇:fabric2.0 部署详解—(3)—配置并添加组织org3


下一篇:[C++]LeetCode376.摆动序列