fabric多机搭建

多机搭建前准备 #

这部分实验内容使用的是Ubuntu操作系统,所需要的实验环境与单节点搭建部分相同,包括docker的安装golang的安装fabric的安装等。为了方便,以上环境已在虚拟机中安装完成。

1.网络结构 #

这部分课程我们要搭建一个多机多节点的网络,结构如下。网络中有两个组织分别为org1org2,每个组织各有一个peer节点,同时还有一个orderer节点。

名称 IP hosts 组织机构
Orderer 172.17.0.10 orderer.test.com orderer
Org1peer0 172.17.0.11 peer0.org1.test.com org1
Org2peer0 172.17.0.12 peer0.org2.test.com org2

2.设置网络host #

使用以下命令,我们在三台虚拟机中分别查看当前虚拟机的IP,其中最后一行为本机IP。

cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.10	1cbb99f39f9a

配置所有服务器网络host,在三台虚拟机中都进行以下操作。

vi /etc/hosts

在最后插入(IP与host任意指定,确定后不能更改),写入以下内容后,按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

172.17.0.10 orderer.test.com
172.17.0.11 peer0.org1.test.com
172.17.0.12 peer0.org2.test.com

3.ssh安装 #

在多机搭建的过程中我们会使用到scp命令。Linux scp 命令用于 Linux 之间复制文件和目录。

scpsecure copy 的缩写, scp 是 Linux 系统下基于 ssh 登陆进行安全的远程文件拷贝命令。

以下内容需要在三台虚拟机中都操作。

实验环境中打开终端默认直接进入root用户,在您个人的终端下需要键入su来切换至root用户。接着执行以下命令:

passwd root

输入要修改的root用户密码,此指导书中以123456root用户密码。输出信息如下:

Changing password for user root.
New password: 
BAD PASSWORD: The password is shorter than 8 characters
Retype new password: 
passwd: all authentication tokens updated successfully.

使用以下命令安装ssh,过程中会被询问是否继续安装,输入y并按回车。

sudo apt-get install openssh-server

使用以下命令打开ssh配置文件。

vim /etc/ssh/sshd_config

PermitRootLogin prohibit-password改为PermitRootLogin yes后按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

使用以下命令重启ssh服务。

systemctl restart ssh

生成Fabric证书 #

1.创建项目目录 #

在三台虚拟机上使用以下命令创建相同的项目目录(三台虚拟机项目路径要相同)。

cd ~/hyperledger
mkdir multinodes

2.编写证书文件 #

证书文件的编写过程以及配置的内容与之前单节点搭建时大致相同,唯一不同的是这次我们要设置两个组织。创建证书文件的过程在任意一台主机上完成即可,以下的过程在orderer节点的主机上完成。

首先使用以下命令进入项目目录。

cd ~/hyperledger/multinodes

使用以下命令将模板文件复制到当前目录下。

cryptogen showtemplate > crypto-config.yaml

使用vim将配置文件进行修改,修改如下(与单节点搭建相比我们新增了一个组织二,别的没有任何区别),按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

OrdererOrgs:

  - Name: Orderer
    Domain: test.com
    EnableNodeOUs: true

    Specs:
      - Hostname: orderer
PeerOrgs:
 
  - Name: org1
    Domain: org1.test.com
    EnableNodeOUs: true
    Template:
      Count: 1
    Users:
      Count: 1
      
  - Name: org2
    Domain: org2.test.com
    EnableNodeOUs: true
    Template:
      Count: 1
    Users:
      Count: 1      

3.生成证书文件 #

使用以下命令生成证书文件。

cryptogen generate --config=crypto-config.yaml

使用ls命令查看生成的文件,可以看到生成了crypto-config文件,这里存放所有的证书文件。

ls
crypto-config  crypto-config.yaml

使用scp命令将证书文件复制到其他两台虚拟机中(使用scp命令时会要求输入主机密码,就是我们之前设置的123456)。

scp crypto-config root@172.17.0.11:~/hyperledger/multinodes/
scp crypto-config root@172.17.0.12:~/hyperledger/multinodes/

复制后使用以下命令在其他两台虚拟机的multinodes目录下查看是否复制成功。

ls
crypto-config

生成通道文件 #

1.创世块文件的编写 #

首先回到orderer节点的虚拟机。

首先我们可以参考官方示例项目test-network中的configtx.yaml配置文件,使用以下命令进入其目录。

cd /root/hyperledger/fabric-samples/test-network/configtx

使用ls命令查看文件。

ls
configtx.yaml

使用以下命令将这个配置文件复制到我们的项目路径中。

cp * ~/hyperledger/multinodes

使用以下命令回到我们的项目路径。

cd ~/hyperledger/multinodes

使用vim编辑器将configtx.yaml改为以下内容,写入以下内容后,按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

---
Organizations:

    - &OrdererOrg

        Name: OrdererOrg
        ID: OrdererMSP
        MSPDir: ./crypto-config/ordererOrganizations/test.com/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Writers:
                Type: Signature
                Rule: "OR('OrdererMSP.member')"
            Admins:
                Type: Signature
                Rule: "OR('OrdererMSP.admin')"
        OrdererEndpoints:
            - orderer.test.com:7050

    - &Org1
   
        Name: Org1MSP
        ID: Org1MSP
        MSPDir: ./crypto-config/peerOrganizations/org1.test.com/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.peer', 'Org1MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org1MSP.admin', 'Org1MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org1MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org1MSP.peer')"
        AnchorPeers:
            - Host: peer0.org1.test.com
              Port: 7051

    - &Org2
    
        Name: Org2MSP
        ID: Org2MSP
        MSPDir: ./crypto-config/peerOrganizations/org2.test.com/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.peer', 'Org2MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org2MSP.admin', 'Org2MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org2MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org2MSP.peer')"

        AnchorPeers:
            - Host: peer0.org2.test.com
              Port: 9051


Capabilities:

    Channel: &ChannelCapabilities

        V2_0: true

    Orderer: &OrdererCapabilities

        V2_0: true

    Application: &ApplicationCapabilities

        V2_0: true

Application: &ApplicationDefaults

    Organizations:

    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
        LifecycleEndorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"
        Endorsement:
            Type: ImplicitMeta
            Rule: "MAJORITY Endorsement"

    Capabilities:
        <<: *ApplicationCapabilities

Orderer: &OrdererDefaults

    OrdererType: solo 

    Addresses:
        - orderer.test.com:7050

    EtcdRaft:
        Consenters:
        - Host: orderer.example.com
          Port: 7050
          ClientTLSCert: ../organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt
          ServerTLSCert: ../organizations/ordererOrganizations/example.com/orderers/orderer.example.com/tls/server.crt

    BatchTimeout: 2s
    BatchSize:
        MaxMessageCount: 10
        AbsoluteMaxBytes: 99 MB
        PreferredMaxBytes: 512 KB

    Organizations:

    Policies:
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"
      
        BlockValidation:
            Type: ImplicitMeta
            Rule: "ANY Writers"


Channel: &ChannelDefaults

    Policies:
       
        Readers:
            Type: ImplicitMeta
            Rule: "ANY Readers"
        Writers:
            Type: ImplicitMeta
            Rule: "ANY Writers"
        Admins:
            Type: ImplicitMeta
            Rule: "MAJORITY Admins"

    
    Capabilities:
        <<: *ChannelCapabilities

Profiles:

    TwoOrgsOrdererGenesis:
        <<: *ChannelDefaults
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
            Capabilities:
                <<: *OrdererCapabilities
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *Org1
                    - *Org2
    TwoOrgsChannel:
        Consortium: SampleConsortium
        <<: *ChannelDefaults
        Application:
            <<: *ApplicationDefaults
            Organizations:
                - *Org1
                - *Org2
            Capabilities:
                <<: *ApplicationCapabilities

与单节点搭建的区别:

  • Organizations部分多了Org2的配置。
  • Profiles的部分创世块名称与通道名称不同。单节点搭建部分为soloOrgsOrdererGenesis和soloOrgsChannel,多节点搭建部分为TwoOrgsOrdererGenesis和TwoOrgsChannel。(创世块名称与通道名称自己任意取,但是后面使用命令生成文件时命令要与配置文件所定义的名称一致)
  • Profiles部分创世块配置与通道配置中都多加入了Org2。

2.生成创世块文件和通道文件 #

使用以下命令生成创世区块。

./bin/configtxgen -profile TwoOrgsgenesis -channelID fabric-channel -outputBlock ./channel-artifacts/genesis.block

使用以下命令生成通道文件。

./bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel

使用以下命令为 Org1 定义锚节点。

./bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP

使用以下命令为 Org2 定义锚节点。

./bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP

使用以下命令将生成的文件拷贝到另两台主机(过程中会需要输入宿主机的密码,就是我们之前设置的123456)。

scp -r channel-artifacts root@172.17.0.11:~/hyperledger/multipeer/
scp -r channel-artifacts root@172.17.0.11:~/hyperledger/multipeer/

复制后使用以下命令在其他两台虚拟机的multinodes目录下查看是否复制成功。

ls
channel-artifacts

docker-compose文件编写 #

在单节点实验中我们编写过一个docker-compose文件,在其中我们配置了orderer节点与peer节点。在多机部署的时候我们需要为每台虚拟机都编写一个docker-compose文件来配置相应的节点。多机部署与单机部署的配置文件内容大致相同,下面会介绍单机与多机的异同点。

1.orderer节点 #

使用以下命令在orderer节点的虚拟机的项目路径上创建一个docker-compose.yaml文件。

cd ~/hyperledger/multinodes
vim docker-compose.yaml

写入以下内容后,按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

version: '2'

services:
  orderer.test.com:
    container_name: orderer.test.com
    image: hyperledger/fabric-orderer:latest
    environment:
      - FABRIC_LOGGING_SPEC=INFO
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_LISTENPORT=7050
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
      - 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
    volumes:
      - ./channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
      - ./crypto-config/ordererOrganizations/test.com/orderers/orderer.test.com/msp:/var/hyperledger/orderer/msp
      - ./crypto-config/ordererOrganizations/test.com/orderers/orderer.test.com/tls/:/var/hyperledger/orderer/tls
    ports:
      - 7050:7050
    extra_hosts:
      - "orderer.test.com:172.17.0.10"
      - "peer0.org1.test.com:172.17.0.11"
      - "peer0.org2.test.com:172.17.0.12"

与单机搭建的不同:

  • 没有了卷挂载目录orderer.test.com:/var/hyperledger/production/orderer
  • 单机搭建中的网络名networks: - test改为extra_hosts:,因为我们是多机搭建有真实的IP,所以网络名称都改为真实的IP地址。

2.org1 #

Fabric中peer节点的世界状态数据库默认是Leveldb,在这个部分我们将使用Couchdb。

Fabric的状态存储支持可插拔的模式,兼容LevelDB、CouchDB等存储。Fabric使用CouchDB作为状态存储与其他数据库相比具有较多优势:

  • CouchDB是一种NoSQL解决方案。它是一个面向文档的数据库,其中文档字段存储为键值映射。字段可以是简单的键值对、列表或映射。除了支持类似LevelDB的键控/合成键/键范围查询之外,CouchDB还支持完整的数据富查询功能,比如针对整个区块链数据的非键查询,因为它的数据内容是以JSON格式存储的,并且是完全可查询的。因此,CouchDB可以满足LevelDB不支持的许多用例的链代码、审计和报告需求。
  • CouchDB还可以增强区块链中的遵从性和数据保护的安全性。因为它能够通过筛选和屏蔽事务中的各个属性来实现字段级别的安全性,并且只在需要时授权只读权限。
  • CouchDB属于CAP定理的ap类型(可用性和分区公差)。它使用具有最终一致性的主-主复制模型。更多信息可以在CouchDB文档的最终一致性页面上找到。然而,在每个fabric对等点下,没有数据库副本,对数据库的写操作保证一致和持久(而不是最终的一致性)。
  • CouchDB是Fabric的第一个外部可插入状态数据库,可以而且应该有其他外部数据库选项。例如,IBM为其区块链启用关系数据库。还可能需要cp类型(一致性和分区容忍度)的数据库,以便在不保证应用层的情况下实现数据一致性。

使用以下命令在org1节点的虚拟机的项目路径上创建一个docker-compose.yaml文件。

cd ~/hyperledger/multinodes
vim docker-compose.yaml

写入以下内容后,按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

version: '2'

services:
  couchdb0.org1.test.com:
    container_name: couchdb0.org1.test.com
    image: couchdb:3.1
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=adminpw
    ports:
      - 5984:5984

  peer0.org1.test.com:
    container_name: peer0.org1.test.com
    image: hyperledger/fabric-peer:latest
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer0.org1.test.com
      - CORE_PEER_ADDRESS=peer0.org1.test.com:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org1.test.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.test.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.test.com:7051
      - CORE_PEER_LOCALMSPID=Org1MSP
      - FABRIC_LOGGING_SPEC=INFO
      - 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
      - CORE_CHAINCODE_EXECUTETIMEOUT=300s
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0.org1.test.com:5984
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
    depends_on:
      - couchdb0.org1.test.com

    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    volumes:
      - /var/run/:/host/var/run/
      - ./crypto-config/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/msp:/etc/hyperledger/fabric/msp
      - ./crypto-config/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/tls:/etc/hyperledger/fabric/tls
    ports:
      - 7051:7051
      - 7052:7052
      - 7053:7053
    extra_hosts:
      - "orderer.test.com:172.17.0.10"
      - "peer0.org1.test.com:172.17.0.11"
      - "peer0.org2.test.com:172.17.0.12"
  cli:
    container_name: cli
    image: hyperledger/fabric-tools:latest
    tty: true
    stdin_open: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - FABRIC_LOGGING_SPEC=INFO
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.org1.test.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.test.com/peers/peer0.org1.test.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.test.com/users/Admin@org1.test.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
      - /var/run/:/host/var/run/
      - ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go
      - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
      - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    extra_hosts:
      - "orderer.test.com:172.17.0.10"
      - "peer0.org1.test.com:172.17.0.11"
      - "peer0.org2.test.com:172.17.0.12"

与单机搭建的不同:

  • 多了couchdb的配置。
  • peer0节点环境变量多了CORE_LEDGER_STATE_STATEDATABASE=CouchDB,表示peer0节点的状态数据库采用了couchdb。
  • 多了depends_on: - couchdb0.org1.test.com,表示在couchdb启动后再启动peer0节点。
  • 单机搭建中的网络名networks: - test改为extra_hosts:,因为我们是多机搭建有真实的IP,所以网络名称都改为真实的IP地址。

3.org2 #

组织二的配置文件与组织一基本相同,唯一不同点是把org1改为org2。

使用以下命令在org2节点的虚拟机的项目路径上创建一个docker-compose.yaml文件。

cd ~/hyperledger/multinodes
vim docker-compose.yaml

写入以下内容后,按 Esc 键退回一般模式,然后输入 :wq 命令并回车保存退出文件。

version: '2'

services:
  couchdb0.org2.test.com:
    container_name: couchdb0.org2.test.com
    image: couchdb:3.1
    environment:
      - COUCHDB_USER=admin
      - COUCHDB_PASSWORD=adminpw
    ports:
      - 5984:5984

  peer0.org2.test.com:
    container_name: peer0.org2.test.com
    image: hyperledger/fabric-peer:latest
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_PEER_ID=peer0.org2.test.com
      - CORE_PEER_ADDRESS=peer0.org2.test.com:7051
      - CORE_PEER_LISTENADDRESS=0.0.0.0:7051
      - CORE_PEER_CHAINCODEADDRESS=peer0.org2.test.com:7052
      - CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052
      - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.test.com:7051
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.test.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
      - FABRIC_LOGGING_SPEC=INFO
      - 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
      - CORE_CHAINCODE_EXECUTETIMEOUT=300s
      - CORE_LEDGER_STATE_STATEDATABASE=CouchDB
      - CORE_LEDGER_STATE_COUCHDBCONFIG_COUCHDBADDRESS=couchdb0.org2.test.com:5984
      - CORE_LEDGER_STATE_COUCHDBCONFIG_USERNAME=admin
      - CORE_LEDGER_STATE_COUCHDBCONFIG_PASSWORD=adminpw
    depends_on:
      - couchdb0.org2.test.com

    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start
    volumes:
      - /var/run/:/host/var/run/
      - ./crypto-config/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/msp:/etc/hyperledger/fabric/msp
      - ./crypto-config/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls:/etc/hyperledger/fabric/tls
    ports:
      - 7051:7051
      - 7052:7052
      - 7053:7053
    extra_hosts:
      - "orderer.test.com:172.17.0.10"
      - "peer0.org1.test.com:172.17.0.11"
      - "peer0.org2.test.com:172.17.0.12"
  cli:
    container_name: cli
    image: hyperledger/fabric-tools:latest
    tty: true
    stdin_open: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - FABRIC_LOGGING_SPEC=INFO
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.org2.test.com:7051
      - CORE_PEER_LOCALMSPID=Org2MSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/users/Admin@org2.test.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: /bin/bash
    volumes:
      - /var/run/:/host/var/run/
      - ./chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go
      - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
      - ./channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    extra_hosts:
      - "orderer.test.com:172.17.0.10"
      - "peer0.org1.test.com:172.17.0.11"
      - "peer0.org2.test.com:172.17.0.12"

使用docker-compose启动服务(三台机器均需要)。

docker-compose up
docker ps -a

通道操作 #

本节主要介绍的peer channel命令,peer channel命令主要是用于创建通道以及节点加入通道。

1 创建通道 #

使用docker exec命令进入客户端容器(在Org1主机上操作)。

docker exec -it cli bash

使用以下命令在客户端容器中创建通道(在Org1容器上操作)。

peer channel create -o orderer.test.com:7050 -c mychannel -f ./channel-artifacts/channel.tx --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/test.com/msp/tlscacerts/tlsca.test.com-cert.pem
  • -o, --orderer: orderer节点的地址。
  • -c, --channelID: 要创建的通道的ID, 必须小写, 在250个字符以内。
  • -f, -file: 由configtxgen 生成的通道文件, 用于提交给orderer。
  • -t, --timeout: 创建通道的超时时长, 默认为5s。
  • --tls: 通信时是否使用tls加密。
  • --cafile: 当前orderer节点pem格式的tls证书文件, 要使用绝对路径。
  • orderer节点pem格式的tls证书文件路径为:crypto-config/ordererOrganizations/test.com/orderers/orderer.test.com/msp/tlscacerts/tlsca.test.com-cert.pem。

使用ls命令查看生成的文件(在Org1容器上操作)。

ls
channel-artifacts  crypto  mychannel.block

使用以下命令将通道文件 mychannel.block 拷贝到宿主机(在Org1主机上操作)。

docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/mychannel.block ./

然后使用以下命令拷贝到其他服务器上用于其他节点加入通道(在Org1主机上操作)。

scp mychannel.block root@172.17.0.12:~/hyperledger/multipeer/

使用以下命令将通道文件拷贝到容器中(在Org2主机上操作)。

docker cp mychannel.block cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/

使用以下命令进入 cli 容器(在Org2主机上操作)。

docker exec -it cli bash

2 加入通道 #

将每个组织的每个节点都加入到通道中需要客户端来完成,一个客户端同时只能连接一个peer节点, 如果想要该客户端连接其他节点, 那么就必须修改当前客户端中相关的环境变量。我们当前在docker-compose.yaml文件中所配置的cli连接的是Go组织的peer0节点。

使用以下命令让peer0节点加入通道(在Org1和Org2容器上操作)。

peer channel join -b mychannel.block

-b, --blockpath: block文件路径(通过 peer channel create 命令生成的通道文件)。

输出如下,此时组织的peer0已经加入通道。

 -> INFO 002 Successfully submitted proposal to join channel

3更新锚节点 #

使用以下命令来更新锚节点(在org1和org2容器上操作)。

peer channel update -o orderer.test.com:7050 -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx
  • -o, --orderer: orderer节点的地址。

  • -c, --channelID: 要创建的通道的ID, 必须小写, 在250个字符以内。

  • -f, -file: 由cryptogen 生成的锚节点文件。

安装调用智能合约 #

进入org1虚拟机。

首先我们使用以下命令在项目路径下创建一个文件夹名为chaincode

mkdir chaincode

然后使用以下命令将官方示例的智能合约复制到我们刚刚创建的chaincode文件夹中。

cd ~/hyperledger/fabric-samples/chaincode
cp -r sacc ~/hyperledger/multinodes/chaincode/go/

使用以下命令进入容器。

docker exec -it cli bash

使用以下命令进入链码所在目录。

cd /opt/gopath/src/github.com/hyperledger/fabric-cluster/chaincode/go/sacc

使用以下命令设置go语言依赖包。

go env -w GOPROXY=https://goproxy.cn,direct
go env -w GO111MODULE=on
go mod init sacc
go mod tidy
go mod vendor

使用以下命令回到peer目录下。

cd /opt/gopath/src/github.com/hyperledger/fabric/peer

Fabric生命周期将链码打包在易于阅读的tar文件中,方便协调跨多个组织的安装,使用以下命令打包链码。

peer lifecycle chaincode package sacc.tar.gz \
  --path github.com/chaincode/sacc/go/ \
  --label sacc_1

使用以下命令退出容器。

exit

使用以下命令将打包好的链码复制到Org2虚拟机中。

docker cp cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/sacc.tar.gz ./ 
scp sacc.tar.gz root@172.10.0.12:~/hyperledger/multinodes

在Org2的虚拟机中使用以下命令将打包好的链码复制到cli客户端中。

docker cp ~/hyperledger/multinodes/sacc.tar.gz cli:/opt/gopath/src/github.com/hyperledger/fabric/peer

使用以下命令分别在两个组织的虚拟机上安装链码(Org1和Org2的虚拟机中都要进行以下操作)。

peer lifecycle chaincode install myassetcontract.tar.gz

使用以下命令查询链码(Org1和Org2的虚拟机中都要进行以下操作)。

peer lifecycle chaincode queryinstalled

使用以下命令批准链码(Org1和Org2的虚拟机中都要进行以下操作)。

peer lifecycle chaincode approveformyorg --channelID mychannel --name sacc --version 1.0 --init-required --package-id sacc_1:1d9838e6893e068a94f055e807b18289559af748e5196a79a640b66305a74428 --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/test.com/orderers/orderer.test.com/msp/tlscacerts/tlsca.test.com-cert.pem

使用以下命令查看链码是否就绪(Org1和Org2的虚拟机中都要进行以下操作)。

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name sacc --version 1.0 --init-required --sequence 1 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/test.com/orderers/orderer.test.com/msp/tlscacerts/tlsca.test.com-cert.pem --output json

使用以下命令提交链码(在组织一或者组织二上)。

peer lifecycle chaincode commit -o orderer.test.com:7050 --channelID mychannel --name sacc --version 1.0 --sequence 1 --init-required --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/test.com/orderers/orderer.test.com/msp/tlscacerts/tlsca.test.com-cert.pem --peerAddresses peer0.org1.test.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/tls/ca.crt --peerAddresses peer0.org2.test.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls/ca.crt

使用以下命令将链码初始化。

peer chaincode invoke -o orderer.test.com:7050 --isInit --ordererTLSHostnameOverride orderer.test.com --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/test.com/orderers/orderer.test.com/msp/tlscacerts/tlsca.test.com-cert.pem -C mychannel -n sacc --peerAddresses peer0.org1.test.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/tls/ca.crt --peerAddresses peer0.org2.test.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls/ca.crt -c '{"Args":["a","bb"]}' 
INFO 001 Chaincode invoke successful. result: status:200 

使用以下命令查询数据。

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

使用以下命令调用链码,新增数据。

peer chaincode invoke -o orderer.test.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/test.com/orderers/orderer.test.com/msp/tlscacerts/tlsca.test.com-cert.pem -C mychannel -n sacc --peerAddresses peer0.org1.test.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.test.com/peers/peer0.org1.test.com/tls/ca.crt --peerAddresses peer0.org2.test.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.test.com/peers/peer0.org2.test.com/tls/ca.crt -c '{"Args":["set","a","cc"]}'
INFO 001 Chaincode invoke successful. result: status:200 payload:"cc" 

使用以下命令查询数据。

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