美文网首页
Hyperledger Fabric 1.0 实战(四)多机部署

Hyperledger Fabric 1.0 实战(四)多机部署

作者: 李孝伟 | 来源:发表于2018-04-03 19:39 被阅读444次

    节点服务和数据存储都使用docker容器进行管理的,docker作为一个轻量级的虚拟化工具,docker容器可以理解为一个最小化的操作系统;每个节点都需要启动一个docker容器,服务和数据是隔离的。单机部署就可以理解为:一个机器上跑了多个虚拟机;多机部署可以理解为把多个虚拟机部署到多个机器上。

    本文主要是让大家更深入的理解配置文件,如果已经有一定的理解可以直接看基于kafka的多机部署实例,有完整的配置文件:
    https://www.jianshu.com/p/9c84673374a5

    以下是整个运行步骤:

     基于 hyperledger/fabric/examples/e2e_cli/架构搭建 4个peer  1个order 的多服务器架构 --深入
        目标机器:
            10.0.200.111    orderer.lychee.com
            10.0.200.113    peer0.org1.lychee.com
            10.0.200.114    peer1.org1.lychee.com
            10.0.200.115    peer0.org2.lychee.com
            10.0.200.116    peer1.org2.lychee.com
        
        1 工具了解(会自动编译)
            configtxlator   配置文件生成工具
            cryptogen   证书生成工具
    
        2 创建证书与配置文件 文件配置需要格式严格设置
            # 参数通道名称,涉及文件:crypto-config.yaml实体证书信息, configtx.yaml创始区块配置文件,docker-compose-e2e.yaml 证书服务器docker配置,域、节点数等修改时,需要同时修改这几个文件。
            ./generateArtifacts.sh lycheechannel
        
            2.1 generateArtifacts.sh 脚本文件说明
                generateCerts 证书生成
                replacePrivateKey 私钥替换
                generateChannelArtifacts 创始区块配置文件生成
    
                cryptogen generate --config=./crypto-config.yaml #根据这个文件可以为组织和其中的成员生成数字证书和签名密钥,生成的文件都保存到crypto-config文件夹
    
                export FABRIC_CFG_PATH=$PWD
                configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block   #生成排序服务创世区块
                #TwoOrgsOrdererGenesis为configtx.yaml中的profiles之一。
                #./channel-artifacts/genesis.block为生成的创世块的文件名及保存位置。
                
                configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel  #生成通道配置创世区块
                #mychannel为通道名称
                    #TwoOrgsChannel为configtx.yaml中的profiles之一。
                
                configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP  #生成组织锚节点,锚节点负责代表组织与其他组织中的节点进行 Gossip 通信
                configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
                其中Org1MSP,Org2MSP为组织名称,在configtx.yaml中有设置。
                最终,我们在channel-artifacts文件夹中,应该是能够看到4个文件。
                channel-artifacts/ 
                ├── channel.tx 
                ├── genesis.block 
                ├── Org1MSPanchors.tx 
                └── Org2MSPanchors.tx
    
                
            2.2 crypto-config.yaml 证书文件说明
                MSP证书是超级账本网络实体的身份标识,实体在通信和交易时使用证书进行签名和验证。生产证书需要crypto-config.yaml文件。定义所有的组织,OrdererOrgs排序服务组织、PeerOrgs节点组织;主要是包括服务所在域名、名称、包含的节点数等,详见文件;
    
            2.3 configtx.yaml 创始区块配置文件
                生成创世区块依赖文件configtx.yaml。configtx.yaml这个文件里面配置了由2个Org参与的Orderer共识配置TwoOrgsOrdererGenesis,以及由2个Org 参与的Channel配置:TwoOrgsChannel。Orderer可以设置共识的算法是Solo还是Kafka,以及共识时区块大小,超时时间 等,我们使用默认值即可,不用更改。而Peer节点的配置包含了MSP的配置,锚节点的配置。如果我们有更多的Org,或者有更多的Channel,那么 就可以根据模板进行对应的修改。
    
            2.4 docker-compose-e2e.yaml 文件说明
                此文件为docker-compose创建启动docker的配置文件;定义了两个ca证书服务容器;关于docker启动配置参数说明,见docker-compose配置文件说明.txt。在多机部署的时候,不再需要此文件;单机部署的时候可以直接用这个文件编译:
                ./network_setup.sh up 
                关于network_setup.sh脚本,up即启动容器,down则使用docker ps 枚举后在用docker rm。5台节点的启动看后续配置文件说明。  
    
        3 docker-compose常用命令
    
            docker-compose up ,这两个容器都是在前台运行的。我们可以指定-d命令以daemon的方式启动容器。除此之外,docker-compose还支持下面参数:
                --verbose :输出详细信息
                -f 制定一个非docker-compose.yml命名的yaml文件
                -p 设置一个项目名称(默认是directory名)
            docker-compose的动作包括:
                build :构建服务
                kill -s SIGINT :给服务发送特定的信号。
                logs :输出日志
                port :输出绑定的端口
                ps :输出运行的容器
                pull :pull服务的image
                rm :删除停止的容器
                run : 运行某个服务,例如docker-compose run web python manage.py shell
                start :运行某个服务中存在的容器。
                stop :停止某个服务中存在的容器。
                up :create + run + attach容器到服务。
                scale :设置服务运行的容器数量。例如:docker-compose scale web=2 worker=3   
    
        4 分别配置docker-compose.yaml文件
    
            4.1 配置orderer节点yaml
                cp docker-compose-cli.yaml docker-compose-orderer.yaml
                #orderer服务器上我们只需要保留order设置,其他peer和cli设置都可以删除。orderer可以不设置extra_hosts。注意域、名称等一致性。详见实例文件
    
            4.2 配置peer节点的yaml
                cp docker-compose-cli.yaml docker-compose-peer.yaml
                #修改docker-compose-peer.yaml,去掉orderer的配置,只保留一个peer和cli,因为我们要多级部署,节点与节点之前又是通过主机名通讯,所以需要修改容器中的host文件,也就是extra_hosts设置,修改后的peer配置如下:
                peer0.org1.example.com:
                    container_name: peer0.org1.example.com
                    extends:
                            file:  base/docker-compose-base.yaml
                            service: peer0.org1.example.com
                    extra_hosts:
                        - "orderer.example.com:10.174.13.185" # host:ip 在peer容器的/etc/hosts增加记录。             
                cli也需要能够和各个节点通讯,所以cli下面也需要添加extra_hosts设置,去掉无效的依赖,否则容易启动失败,启动顺序非常重要,并且去掉command这一行(调用scripts.sh命令,这个是创建通道、部署链码测试脚本),因为我们是每个peer都会有个对应的客户端,也就是cli,所以我只需要去手动执行一次命令,而不是自动运行(创建通道等只需要运行一次)。主要定义了一些环境变量、卷轴挂载、网络说明等。
                注意路径映射,否则容易找不到文件。其他peer节点复制后将名称、地址修改即可。
    
            4.3 docker-compose-base.yaml 文件说明
                所有peer和orderer都依赖这个文件,这个是基础的extends扩展;主要定义一些环境变量msp和tls位置、msp和tls卷轴映射、端口映射、gossip地址等。这个文件也要修改,因为是多机部署,所以端口映射可以改为一样。
    
    
        5 多节点分发配置
            每个机器都要求安卓docker等工具,所以建议在一个环境配置好后,保存镜像,然后再用此镜像创建其他节点。
            分发后,需要修改其他peer节点的docker-compose-peer.yaml文件,主要是修改名称和依赖。
        
        6 启动Fabric
        
            5.6.1 启动orderer节点
                docker-compose -f docker-compose-orderer.yaml up -d
                #启动后,可以用docker ps 查看启动的容器,会有一个为orderer.lychee.com的节点
    
            5.6.2 启动peer节点
                docker-compose -f docker-compose-peer.yaml up –d
                #启动后,可以看到两个容器,peer0.org1.lychee.com和lycheecli两个容器。
                #登陆其他节点,同样的命令启动。
    
        7 创建通道和部署、实例化、测试链码
    
            7.1 创建channel测试chaincode
                选择任意一个peer,执行一下命令:
                docker exec -it lycheecli bash  #切入到lycheecli容器中;结果类似:
                root@b41e67d40583:/opt/gopath/src/github.com/hyperledger/fabric/peer#
                
                ./scripts/script.sh mychannel   #创建名称为mychannel的通道并测试链码
            
            7.2 script.sh脚本文件说明(摘取部分命令说明,详见配置文件)
                #在orderer上创建一个channel,channel配置文件为./channel-artifacts/channel.tx
                peer channel create -o orderer.lychee.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt 
                
                #更新通道上锚节点信息
                peer channel update -o orderer.lychee.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt
                
                #加入通道,尝试5次
                peer channel join -b $CHANNEL_NAME.block  >&log.txt
                
                #安装链码,先要配置环境
                peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/lychees/chaincode/go/chaincode_lychee02 >&log.txt
    
                #实例化链码,先要配置环境
                peer chaincode instantiate -o orderer.lychee.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR       ('Org1MSP.member','Org2MSP.member')" >&log.txt
    
                #链码调用,查询
                peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt
    
                #链码调用,invoke
                peer chaincode invoke -o orderer.lychee.com:7050 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt
        
        8 结果
            ===================== All GOOD, End-2-End execution completed ===================== 
            出现以上内容,则这简单的5个节点的多机部署就OK了
    
    

    以下是所有的配置文件:

    crypto-config.yaml实体证书信息
    # 
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    #
    
    # ---------------------------------------------------------------------------
    # "OrdererOrgs" - Definition of organizations managing orderer nodes
    # ---------------------------------------------------------------------------
    OrdererOrgs:
      # ---------------------------------------------------------------------------
      # Orderer
      # ---------------------------------------------------------------------------
      - Name: Orderer
        Domain: lychee.com
        # ---------------------------------------------------------------------------
        # "Specs" - See PeerOrgs below for complete description
        # ---------------------------------------------------------------------------
        Specs:
          - Hostname: orderer
    # ---------------------------------------------------------------------------
    # "PeerOrgs" - Definition of organizations managing peer nodes
    # ---------------------------------------------------------------------------
    PeerOrgs:
      # ---------------------------------------------------------------------------
      # Org1
      # ---------------------------------------------------------------------------
      - Name: Org1
        Domain: org1.lychee.com
        # ---------------------------------------------------------------------------
        # "Specs"
        # ---------------------------------------------------------------------------
        # Uncomment this section to enable the explicit definition of hosts in your
        # configuration.  Most users will want to use Template, below
        #
        # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
        #   - Hostname:   (Required) The desired hostname, sans the domain.
        #   - CommonName: (Optional) Specifies the template or explicit override for
        #                 the CN.  By default, this is the template:
        #
        #                              "{{.Hostname}}.{{.Domain}}"
        #
        #                 which obtains its values from the Spec.Hostname and
        #                 Org.Domain, respectively.
        # ---------------------------------------------------------------------------
        # Specs:
        #   - Hostname: foo # implicitly "foo.org1.lychee.com"
        #     CommonName: foo27.org5.lychee.com # overrides Hostname-based FQDN set above
        #   - Hostname: bar
        #   - Hostname: baz
        # ---------------------------------------------------------------------------
        # "Template"
        # ---------------------------------------------------------------------------
        # Allows for the definition of 1 or more hosts that are created sequentially
        # from a template. By default, this looks like "peer%d" from 0 to Count-1.
        # You may override the number of nodes (Count), the starting index (Start)
        # or the template used to construct the name (Hostname).
        #
        # Note: Template and Specs are not mutually exclusive.  You may define both
        # sections and the aggregate nodes will be created for you.  Take care with
        # name collisions
        # ---------------------------------------------------------------------------
        Template:
          Count: 2
          # Start: 5
          # Hostname: {{.Prefix}}{{.Index}} # default
        # ---------------------------------------------------------------------------
        # "Users"
        # ---------------------------------------------------------------------------
        # Count: The number of user accounts _in addition_ to Admin
        # ---------------------------------------------------------------------------
        Users:
          Count: 1
      # ---------------------------------------------------------------------------
      # Org2: See "Org1" for full specification
      # ---------------------------------------------------------------------------
      - Name: Org2
        Domain: org2.lychee.com
        Template:
          Count: 2
        Users:
          Count: 1
    
    
    configtx.yaml创始区块配置文件
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    #
    
    ---
    ################################################################################
    #
    #   Profile
    #
    #   - Different configuration profiles may be encoded here to be specified
    #   as parameters to the configtxgen tool
    #
    ################################################################################
    Profiles:
    
        TwoOrgsOrdererGenesis:
            Orderer:
                <<: *OrdererDefaults
                Organizations:
                    - *OrdererOrg
            Consortiums:
                SampleConsortium:
                    Organizations:
                        - *Org1
                        - *Org2
        TwoOrgsChannel:
            Consortium: SampleConsortium
            Application:
                <<: *ApplicationDefaults
                Organizations:
                    - *Org1
                    - *Org2
    
    ################################################################################
    #
    #   Section: Organizations
    #
    #   - This section defines the different organizational identities which will
    #   be referenced later in the configuration.
    #
    ################################################################################
    Organizations:
    
        # SampleOrg defines an MSP using the sampleconfig.  It should never be used
        # in production but may be used as a template for other definitions
        - &OrdererOrg
            # DefaultOrg defines the organization which is used in the sampleconfig
            # of the fabric.git development environment
            Name: OrdererOrg
    
            # ID to load the MSP definition as
            ID: OrdererMSP
    
            # MSPDir is the filesystem path which contains the MSP configuration
            MSPDir: crypto-config/ordererOrganizations/lychee.com/msp
    
        - &Org1
            # DefaultOrg defines the organization which is used in the sampleconfig
            # of the fabric.git development environment
            Name: Org1MSP
    
            # ID to load the MSP definition as
            ID: Org1MSP
    
            MSPDir: crypto-config/peerOrganizations/org1.lychee.com/msp
    
            AnchorPeers:
                # AnchorPeers defines the location of peers which can be used
                # for cross org gossip communication.  Note, this value is only
                # encoded in the genesis block in the Application section context
                - Host: peer0.org1.lychee.com
                  Port: 7051
    
        - &Org2
            # DefaultOrg defines the organization which is used in the sampleconfig
            # of the fabric.git development environment
            Name: Org2MSP
    
    
            # ID to load the MSP definition as
            ID: Org2MSP
    
            MSPDir: crypto-config/peerOrganizations/org2.lychee.com/msp
    
            AnchorPeers:
                # AnchorPeers defines the location of peers which can be used
                # for cross org gossip communication.  Note, this value is only
                # encoded in the genesis block in the Application section context
                - Host: peer0.org2.lychee.com
                  Port: 7051
    
    ################################################################################
    #
    #   SECTION: Orderer
    #
    #   - This section defines the values to encode into a config transaction or
    #   genesis block for orderer related parameters
    #
    ################################################################################
    Orderer: &OrdererDefaults
    
        # Orderer Type: The orderer implementation to start
        # Available types are "solo" and "kafka"
        OrdererType: solo
    
        Addresses:
            - orderer.lychee.com:7050
    
        # Batch Timeout: The amount of time to wait before creating a batch
        BatchTimeout: 2s
    
        # Batch Size: Controls the number of messages batched into a block
        BatchSize:
    
            # Max Message Count: The maximum number of messages to permit in a batch
            MaxMessageCount: 10
    
            # Absolute Max Bytes: The absolute maximum number of bytes allowed for
            # the serialized messages in a batch.
            AbsoluteMaxBytes: 98 MB
    
            # Preferred Max Bytes: The preferred maximum number of bytes allowed for
            # the serialized messages in a batch. A message larger than the preferred
            # max bytes will result in a batch larger than preferred max bytes.
            PreferredMaxBytes: 512 KB
    
        Kafka:
            # Brokers: A list of Kafka brokers to which the orderer connects
            # NOTE: Use IP:port notation
            Brokers:
                - 127.0.0.1:9092
    
        # Organizations is the list of orgs which are defined as participants on
        # the orderer side of the network
        Organizations:
    
    ################################################################################
    #
    #   SECTION: Application
    #
    #   - This section defines the values to encode into a config transaction or
    #   genesis block for application related parameters
    #
    ################################################################################
    Application: &ApplicationDefaults
    
        # Organizations is the list of orgs which are defined as participants on
        # the application side of the network
        Organizations:
    
    
    generateArtifacts.sh运行脚本
    #!/bin/bash +x
    #
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    #
    
    
    #set -e
    
    CHANNEL_NAME=$1
    : ${CHANNEL_NAME:="mychannel"}
    echo $CHANNEL_NAME
    
    export FABRIC_ROOT=$PWD/../..
    export FABRIC_CFG_PATH=$PWD
    echo
    
    OS_ARCH=$(echo "$(uname -s|tr '[:upper:]' '[:lower:]'|sed 's/mingw64_nt.*/windows/')-$(uname -m | sed 's/x86_64/amd64/g')" | awk '{print tolower($0)}')
    
    ## Using docker-compose template replace private key file names with constants
    function replacePrivateKey () {
            ARCH=`uname -s | grep Darwin`
            if [ "$ARCH" == "Darwin" ]; then
                    OPTS="-it"
            else
                    OPTS="-i"
            fi
    
            cp docker-compose-e2e-template.yaml docker-compose-e2e.yaml
    
            CURRENT_DIR=$PWD
            cd crypto-config/peerOrganizations/org1.lychee.com/ca/
            PRIV_KEY=$(ls *_sk)
            cd $CURRENT_DIR
            sed $OPTS "s/CA1_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
            cd crypto-config/peerOrganizations/org2.lychee.com/ca/
            PRIV_KEY=$(ls *_sk)
            cd $CURRENT_DIR
            sed $OPTS "s/CA2_PRIVATE_KEY/${PRIV_KEY}/g" docker-compose-e2e.yaml
    }
    
    ## Generates Org certs using cryptogen tool
    function generateCerts (){
            CRYPTOGEN=$FABRIC_ROOT/release/$OS_ARCH/bin/cryptogen
    
            if [ -f "$CRYPTOGEN" ]; then
                echo "Using cryptogen -> $CRYPTOGEN"
            else
                echo "Building cryptogen"
                make -C $FABRIC_ROOT release
            fi
    
            echo
            echo "##########################################################"
            echo "##### Generate certificates using cryptogen tool #########"
            echo "##########################################################"
            $CRYPTOGEN generate --config=./crypto-config.yaml
            echo
    }
    
    ## Generate orderer genesis block , channel configuration transaction and anchor peer update transactions
    function generateChannelArtifacts() {
    
            CONFIGTXGEN=$FABRIC_ROOT/release/$OS_ARCH/bin/configtxgen
            if [ -f "$CONFIGTXGEN" ]; then
                echo "Using configtxgen -> $CONFIGTXGEN"
            else
                echo "Building configtxgen"
                make -C $FABRIC_ROOT release
            fi
    
            echo "##########################################################"
            echo "#########  Generating Orderer Genesis block ##############"
            echo "##########################################################"
            # Note: For some unknown reason (at least for now) the block file can't be
    
            # named orderer.genesis.block or the orderer will fail to launch!
            $CONFIGTXGEN -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
    
            echo
            echo "#################################################################"
            echo "### Generating channel configuration transaction 'channel.tx' ###"
            echo "#################################################################"
            $CONFIGTXGEN -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
    
            echo
            echo "#################################################################"
            echo "#######    Generating anchor peer update for Org1MSP   ##########"
            echo "#################################################################"
            $CONFIGTXGEN -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
    
            echo
            echo "#################################################################"
            echo "#######    Generating anchor peer update for Org2MSP   ##########"
            echo "#################################################################"
            $CONFIGTXGEN -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
            echo
    }
    
    generateCerts
    replacePrivateKey
    generateChannelArtifacts
    
    
    docker-compose-peer.yaml docker peer容器配置文件
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    #
    
    version: '2'
    
    services:
    
      peer0.org1.lychee.com:
        container_name: peer0.org1.lychee.com
        extends:
          file:  base/docker-compose-base.yaml
          service: peer0.org1.lychee.com
        extra_hosts:
          - "orderer.lychee.com:10.0.200.111"
      lycheecli:
        container_name: lycheecli
        image: hyperledger/fabric-tools
        tty: true
        environment:
          - GOPATH=/opt/gopath
          - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
          - CORE_LOGGING_LEVEL=DEBUG
          - CORE_PEER_ID=lycheecli
          - CORE_PEER_ADDRESS=peer0.org1.lychee.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.lychee.com/peers/peer0.org1.lychee.com/tls/server.crt
          - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.lychee.com/peers/peer0.org1.lychee.com/tls/server.key
          - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.lychee.com/peers/peer0.org1.lychee.com/tls/ca.crt
          - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.lychee.com/users/Admin@org1.lychee.com/msp
        working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
        volumes:
            - /var/run/:/host/var/run/
            - ../chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/lychees/chaincode/go
            - ./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:
          - peer0.org1.lychee.com
        extra_hosts:
          - "orderer.lychee.com:10.0.200.111"
          - "peer0.org1.lychee.com:10.0.200.113"
          - "peer1.org1.lychee.com:10.0.200.114"
          - "peer0.org2.lychee.com:10.0.200.115"
          - "peer1.org2.lychee.com:10.0.200.116"
    
    
    docker-compose-base.yaml docker peer基本配置
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    #
    
    version: '2'
    
    services:
    
      orderer.lychee.com:
        container_name: orderer.lychee.com
        image: hyperledger/fabric-orderer
        environment:
          - ORDERER_GENERAL_LOGLEVEL=debug
          - 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]
        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/lychee.com/orderers/orderer.lychee.com/msp:/var/hyperledger/orderer/msp
        - ../crypto-config/ordererOrganizations/lychee.com/orderers/orderer.lychee.com/tls/:/var/hyperledger/orderer/tls
        ports:
         - 7050:7050
    
      peer0.org1.lychee.com:
        container_name: peer0.org1.lychee.com
        extends:
          file: peer-base.yaml
          service: peer-base
        environment:
          - CORE_PEER_ID=peer0.org1.lychee.com
          - CORE_PEER_ADDRESS=peer0.org1.lychee.com:7051
          - CORE_PEER_CHAINCODELISTENADDRESS=peer0.org1.lychee.com:7052
          - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org1.lychee.com:7051
          - CORE_PEER_LOCALMSPID=Org1MSP
        volumes:
            - /var/run/:/host/var/run/
            - ../crypto-config/peerOrganizations/org1.lychee.com/peers/peer0.org1.lychee.com/msp:/etc/hyperledger/fabric/msp
            - ../crypto-config/peerOrganizations/org1.lychee.com/peers/peer0.org1.lychee.com/tls:/etc/hyperledger/fabric/tls
        ports:
          - 7051:7051
          - 7052:7052
          - 7053:7053
    
      peer1.org1.lychee.com:
        container_name: peer1.org1.lychee.com
        extends:
          file: peer-base.yaml
          service: peer-base
        environment:
          - CORE_PEER_ID=peer1.org1.lychee.com
          - CORE_PEER_ADDRESS=peer1.org1.lychee.com:7051
          - CORE_PEER_CHAINCODELISTENADDRESS=peer1.org1.lychee.com:7052
          - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org1.lychee.com:7051
          - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org1.lychee.com:7051
          - CORE_PEER_LOCALMSPID=Org1MSP
        volumes:
            - /var/run/:/host/var/run/
            - ../crypto-config/peerOrganizations/org1.lychee.com/peers/peer1.org1.lychee.com/msp:/etc/hyperledger/fabric/msp
            - ../crypto-config/peerOrganizations/org1.lychee.com/peers/peer1.org1.lychee.com/tls:/etc/hyperledger/fabric/tls
    
        ports:
          - 7051:7051
          - 7052:7052
          - 7053:7053
      peer0.org2.lychee.com:
        container_name: peer0.org2.lychee.com
        extends:
          file: peer-base.yaml
          service: peer-base
        environment:
          - CORE_PEER_ID=peer0.org2.lychee.com
          - CORE_PEER_ADDRESS=peer0.org2.lychee.com:7051
          - CORE_PEER_CHAINCODELISTENADDRESS=peer0.org2.lychee.com:7052
          - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org2.lychee.com:7051
          - CORE_PEER_LOCALMSPID=Org2MSP
        volumes:
            - /var/run/:/host/var/run/
            - ../crypto-config/peerOrganizations/org2.lychee.com/peers/peer0.org2.lychee.com/msp:/etc/hyperledger/fabric/msp
            - ../crypto-config/peerOrganizations/org2.lychee.com/peers/peer0.org2.lychee.com/tls:/etc/hyperledger/fabric/tls
        ports:
          - 7051:7051
          - 7052:7052
          - 7053:7053
      peer1.org2.lychee.com:
        container_name: peer1.org2.lychee.com
        extends:
          file: peer-base.yaml
          service: peer-base
        environment:
          - CORE_PEER_ID=peer1.org2.lychee.com
          - CORE_PEER_ADDRESS=peer1.org2.lychee.com:7051
          - CORE_PEER_CHAINCODELISTENADDRESS=peer1.org2.lychee.com:7052
          - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer1.org2.lychee.com:7051
          - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org2.lychee.com:7051
          - CORE_PEER_LOCALMSPID=Org2MSP
        volumes:
            - /var/run/:/host/var/run/
            - ../crypto-config/peerOrganizations/org2.lychee.com/peers/peer1.org2.lychee.com/msp:/etc/hyperledger/fabric/msp
            - ../crypto-config/peerOrganizations/org2.lychee.com/peers/peer1.org2.lychee.com/tls:/etc/hyperledger/fabric/tls
        ports:
          - 7051:7051
          - 7052:7052
          - 7053:7053
    
    
    scripts.sh测试脚本
    #!/bin/bash
    # Copyright London Stock Exchange Group All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    #
    echo
    echo " ____    _____      _      ____    _____           _____   ____    _____ "
    echo "/ ___|  |_   _|    / \    |  _ \  |_   _|         | ____| |___ \  | ____|"
    echo "\___ \    | |     / _ \   | |_) |   | |    _____  |  _|     __) | |  _|  "
    echo " ___) |   | |    / ___ \  |  _ <    | |   |_____| | |___   / __/  | |___ "
    echo "|____/    |_|   /_/   \_\ |_| \_\   |_|           |_____| |_____| |_____|"
    echo
    
    CHANNEL_NAME="$1"
    : ${CHANNEL_NAME:="mychannel"}
    : ${TIMEOUT:="60"}
    COUNTER=1
    MAX_RETRY=5
    ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/lychee.com/orderers/orderer.lychee.com/msp/tlscacerts/tlsca.lychee.com-cert.pem
    
    echo "Channel name : "$CHANNEL_NAME
    
    verifyResult () {
            if [ $1 -ne 0 ] ; then
                    echo "!!!!!!!!!!!!!!! "$2" !!!!!!!!!!!!!!!!"
                    echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
                    echo
                    exit 1
            fi
    }
    setGlobals () {
    
            if [ $1 -eq 0 -o $1 -eq 1 ] ; then
                    CORE_PEER_LOCALMSPID="Org1MSP"
                    CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.lychee.com/peers/peer0.org1.lychee.com/tls/ca.crt
                    CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.lychee.com/users/Admin@org1.lychee.com/msp
                    if [ $1 -eq 0 ]; then
                            CORE_PEER_ADDRESS=peer0.org1.lychee.com:7051
                    else
                            CORE_PEER_ADDRESS=peer1.org1.lychee.com:7051
                    fi
            else
                    CORE_PEER_LOCALMSPID="Org2MSP"
                    CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.lychee.com/peers/peer0.org2.lychee.com/tls/ca.crt
                    CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.lychee.com/users/Admin@org2.lychee.com/msp
                    if [ $1 -eq 2 ]; then
                            CORE_PEER_ADDRESS=peer0.org2.lychee.com:7051
                    else
                            CORE_PEER_ADDRESS=peer1.org2.lychee.com:7051
                    fi
            fi
    
            env |grep CORE
    }
    
    createChannel() {
            setGlobals 0
    
            if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
                    peer channel create -o orderer.lychee.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt
            else
                    peer channel create -o orderer.lychee.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt
            fi
            res=$?
            cat log.txt
            verifyResult $res "Channel creation failed"
            echo "===================== Channel \"$CHANNEL_NAME\" is created successfully ===================== "
            echo
    }
    
    updateAnchorPeers() {
            PEER=$1
            setGlobals $PEER
    
            if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
                    peer channel update -o orderer.lychee.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx >&log.txt
            else
                    peer channel update -o orderer.lychee.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt
            fi
            res=$?
            cat log.txt
            verifyResult $res "Anchor peer update failed"
            echo "===================== Anchor peers for org \"$CORE_PEER_LOCALMSPID\" on \"$CHANNEL_NAME\" is updated successfully ===================== "
            sleep 5
            echo
    }
    
    
    ## Sometimes Join takes time hence RETRY atleast for 5 times
    joinWithRetry () {
            peer channel join -b $CHANNEL_NAME.block  >&log.txt
            res=$?
            cat log.txt
            if [ $res -ne 0 -a $COUNTER -lt $MAX_RETRY ]; then
                    COUNTER=` expr $COUNTER + 1`
                    echo "PEER$1 failed to join the channel, Retry after 2 seconds"
                    sleep 2
                    joinWithRetry $1
            else
                    COUNTER=1
            fi
            verifyResult $res "After $MAX_RETRY attempts, PEER$ch has failed to Join the Channel"
    }
    
    joinChannel () {
            for ch in 0 1 2 3; do
                    setGlobals $ch
                    joinWithRetry $ch
                    echo "===================== PEER$ch joined on the channel \"$CHANNEL_NAME\" ===================== "
                    sleep 2
                    echo
            done
    }
    
    installChaincode () {
            PEER=$1
            setGlobals $PEER
            peer chaincode install -n mycc -v 1.0 -p github.com/hyperledger/fabric/lychees/chaincode/go/chaincode_lychee02 >&log.txt
            res=$?
            cat log.txt
            verifyResult $res "Chaincode installation on remote peer PEER$PEER has Failed"
            echo "===================== Chaincode is installed on remote peer PEER$PEER ===================== "
            echo
    }
    
    instantiateChaincode () {
            PEER=$1
            setGlobals $PEER
            # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
            # lets supply it directly as we know it using the "-o" option
            if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
                    peer chaincode instantiate -o orderer.lychee.com:7050 -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')" >&log.txt
            else
                    peer chaincode instantiate -o orderer.lychee.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a","100","b","200"]}' -P "OR       ('Org1MSP.member','Org2MSP.member')" >&log.txt
            fi
            res=$?
            cat log.txt
            verifyResult $res "Chaincode instantiation on PEER$PEER on channel '$CHANNEL_NAME' failed"
            echo "===================== Chaincode Instantiation on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
            echo
    }
    
    
    chaincodeQuery () {
      PEER=$1
      echo "===================== Querying on PEER$PEER on channel '$CHANNEL_NAME'... ===================== "
      setGlobals $PEER
      local rc=1
      local starttime=$(date +%s)
    
      # continue to poll
      # we either get a successful response, or reach TIMEOUT
      while test "$(($(date +%s)-starttime))" -lt "$TIMEOUT" -a $rc -ne 0
      do
         sleep 3
         echo "Attempting to Query PEER$PEER ...$(($(date +%s)-starttime)) secs"
         peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}' >&log.txt
         test $? -eq 0 && VALUE=$(cat log.txt | awk '/Query Result/ {print $NF}')
         test "$VALUE" = "$2" && let rc=0
      done
      echo
      cat log.txt
      if test $rc -eq 0 ; then
            echo "===================== Query on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
      else
            echo "!!!!!!!!!!!!!!! Query result on PEER$PEER is INVALID !!!!!!!!!!!!!!!!"
            echo "================== ERROR !!! FAILED to execute End-2-End Scenario =================="
            echo
            exit 1
      fi
    }
    
    
    chaincodeInvoke () {
            PEER=$1
            setGlobals $PEER
            # while 'peer chaincode' command can get the orderer endpoint from the peer (if join was successful),
            # lets supply it directly as we know it using the "-o" option
            if [ -z "$CORE_PEER_TLS_ENABLED" -o "$CORE_PEER_TLS_ENABLED" = "false" ]; then
                    peer chaincode invoke -o orderer.lychee.com:7050 -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt
            else
                    peer chaincode invoke -o orderer.lychee.com:7050  --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}' >&log.txt
            fi
            res=$?
            cat log.txt
            verifyResult $res "Invoke execution on PEER$PEER failed "
            echo "===================== Invoke transaction on PEER$PEER on channel '$CHANNEL_NAME' is successful ===================== "
            echo
    }
    
    
    ## Create channel
    echo "Creating channel..."
    createChannel
    
    ## Join all the peers to the channel
    echo "Having all peers join the channel..."
    joinChannel
    
    ## Set the anchor peers for each org in the channel
    echo "Updating anchor peers for org1..."
    updateAnchorPeers 0
    echo "Updating anchor peers for org2..."
    updateAnchorPeers 2
    
    ## Install chaincode on Peer0/Org1 and Peer2/Org2
    echo "Installing chaincode on org1/peer0..."
    installChaincode 0
    echo "Install chaincode on org2/peer2..."
    installChaincode 2
    
    #Instantiate chaincode on Peer2/Org2
    echo "Instantiating chaincode on org2/peer2..."
    instantiateChaincode 2
    
    #Query on chaincode on Peer0/Org1
    echo "Querying chaincode on org1/peer0..."
    chaincodeQuery 0 100
    
    #Invoke on chaincode on Peer0/Org1
    echo "Sending invoke transaction on org1/peer0..."
    chaincodeInvoke 0
    
    ## Install chaincode on Peer3/Org2
    echo "Installing chaincode on org2/peer3..."
    installChaincode 3
    
    #Query on chaincode on Peer3/Org2, check if the result is 90
    echo "Querying chaincode on org2/peer3..."
    chaincodeQuery 3 90
    
    echo
    echo "===================== All GOOD, End-2-End execution completed ===================== "
    echo
    
    echo
    echo " _____   _   _   ____            _____   ____    _____ "
    echo "| ____| | \ | | |  _ \          | ____| |___ \  | ____|"
    echo "|  _|   |  \| | | | | |  _____  |  _|     __) | |  _|  "
    echo "| |___  | |\  | | |_| | |_____| | |___   / __/  | |___ "
    echo "|_____| |_| \_| |____/          |_____| |_____| |_____|"
    echo
    
    exit 0
    
    
    chaincode_example02.go智能合约代码
    /*
    Copyright IBM Corp. 2016 All Rights Reserved.
    
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at
    
             http://www.apache.org/licenses/LICENSE-2.0
    
    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
    */
    
    package main
    
    //WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
    //calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
    //to be modified as well with the new ID of chaincode_example02.
    //chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
    //hard-coding.
    
    import (
        "fmt"
        "strconv"
    
        "github.com/hyperledger/fabric/core/chaincode/shim"
        pb "github.com/hyperledger/fabric/protos/peer"
    )
    
    // SimpleChaincode example simple Chaincode implementation
    type SimpleChaincode struct {
    }
    
    func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
        fmt.Println("ex02 Init")
        _, args := stub.GetFunctionAndParameters()
        var A, B string    // Entities
        var Aval, Bval int // Asset holdings
        var err error
    
        if len(args) != 4 {
            return shim.Error("Incorrect number of arguments. Expecting 4")
        }
    
        // Initialize the chaincode
        A = args[0]
        Aval, err = strconv.Atoi(args[1])
        if err != nil {
            return shim.Error("Expecting integer value for asset holding")
        }
        B = args[2]
        Bval, err = strconv.Atoi(args[3])
        if err != nil {
            return shim.Error("Expecting integer value for asset holding")
        }
        fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
    
        // Write the state to the ledger
        err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
        if err != nil {
            return shim.Error(err.Error())
        }
    
        err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
        if err != nil {
            return shim.Error(err.Error())
        }
    
        return shim.Success(nil)
    }
    
    func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
        fmt.Println("ex02 Invoke")
        function, args := stub.GetFunctionAndParameters()
        if function == "invoke" {
            // Make payment of X units from A to B
            return t.invoke(stub, args)
        } else if function == "delete" {
            // Deletes an entity from its state
            return t.delete(stub, args)
        } else if function == "query" {
            // the old "Query" is now implemtned in invoke
            return t.query(stub, args)
        }
    
        return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
    }
    
    // Transaction makes payment of X units from A to B
    func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var A, B string    // Entities
        var Aval, Bval int // Asset holdings
        var X int          // Transaction value
        var err error
    
        if len(args) != 3 {
            return shim.Error("Incorrect number of arguments. Expecting 3")
        }
    
        A = args[0]
        B = args[1]
    
        // Get the state from the ledger
        // TODO: will be nice to have a GetAllState call to ledger
        Avalbytes, err := stub.GetState(A)
        if err != nil {
            return shim.Error("Failed to get state")
        }
        if Avalbytes == nil {
            return shim.Error("Entity not found")
        }
        Aval, _ = strconv.Atoi(string(Avalbytes))
    
        Bvalbytes, err := stub.GetState(B)
        if err != nil {
            return shim.Error("Failed to get state")
        }
        if Bvalbytes == nil {
            return shim.Error("Entity not found")
        }
        Bval, _ = strconv.Atoi(string(Bvalbytes))
    
        // Perform the execution
        X, err = strconv.Atoi(args[2])
        if err != nil {
            return shim.Error("Invalid transaction amount, expecting a integer value")
        }
        Aval = Aval - X
        Bval = Bval + X
        fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)
    
        // Write the state back to the ledger
        err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
        if err != nil {
            return shim.Error(err.Error())
        }
    
        err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
        if err != nil {
            return shim.Error(err.Error())
        }
    
        return shim.Success(nil)
    }
    
    // Deletes an entity from state
    func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        if len(args) != 1 {
            return shim.Error("Incorrect number of arguments. Expecting 1")
        }
    
        A := args[0]
    
        // Delete the key from the state in ledger
        err := stub.DelState(A)
        if err != nil {
            return shim.Error("Failed to delete state")
        }
    
        return shim.Success(nil)
    }
    
    // query callback representing the query of a chaincode
    func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var A string // Entities
        var err error
    
        if len(args) != 1 {
            return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
        }
    
        A = args[0]
    
        // Get the state from the ledger
        Avalbytes, err := stub.GetState(A)
        if err != nil {
            jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
            return shim.Error(jsonResp)
        }
    
        if Avalbytes == nil {
            jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
            return shim.Error(jsonResp)
        }
    
        jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
        fmt.Printf("Query Response:%s\n", jsonResp)
        return shim.Success(Avalbytes)
    }
    
    func main() {
        err := shim.Start(new(SimpleChaincode))
        if err != nil {
            fmt.Printf("Error starting Simple chaincode: %s", err)
        }
    }
    
    

    以上便是所有文件,一定要注意格式和路径,否则就会出现bad_request

    相关文章

      网友评论

          本文标题:Hyperledger Fabric 1.0 实战(四)多机部署

          本文链接:https://www.haomeiwen.com/subject/iqbchftx.html