Hyperledger Fabric链码作为外部服务

链码作为外部服务

Fabric v2.0支持链码在Fabric环境外部署和执行。允许用户管理与节点保持独立的链码运行。这种方案激励了Fabric中的链码云部署,例如Kubernetes。代替了在每一个节点上面构建与运行链码。链码可以作为一个服务运行,它的生命周期将可以在Fabric环境外进行管理。这种措施利用Fabirc v2.0的外部构建和运行功能。其功能具有允许操作者通过程序构建,运行,发现链码对节点进行扩展。在读取本文内容之前,应该对外部构建与扩展较为熟悉。

在外部构建功能可以使用之前,链码包内容要求指定的编程语言的源代码进行构建并作为链码二进制文件运行。新的外部构建和运行功能允许用户有选择地定制化构建过程。将链码作为外部服务运行。构建过程允许指定链码运行服务的端点信息。因此包内容可以简单地由外部链码运行服务端点信息和用于安全通信的TLS归档组成。TLS是可选的,但是除了简单的测试环境以外,强烈建议所有环境都使用TLS。

接下来的部分将描述如何将链码配置为外部服务:

打包链码

通过Fabric V2.0版本的chaincode lifecycle,链码可以被打包并以.tar.gz格式进行安装。下面的myccpackage.tgz归档说明了要求的结构:

tar xvfz myccpackage.tgz
code.tar.gz
metadata.json

code.tar.gz归档要求

code.tar.gz归档必须包含链码端点的连接信息。该信息将在/bin/release步骤处打包进connection.json(见下面)。在这里直接将connection.json打包进code.tar.gz,所以release步骤可以直接从这里复制。

  • address - 可以被peer节点访问的链码服务端点,必须指定以:格式。
  • dial_timeout - 等待连接完成的间隔时间,字符串类型并需要指定单位,如"10s","500ms","1m",默认为"3s".
  • tls_required - 是否使用TLS加密。如果为false则不要求使用下面四个属性
  • client_auth_required - 如果为true则需要是定客户端权限认证的key_path,cert_path.默认为false.
  • key_path - 秘钥文件的路径
  • cert_path - 证书文件的路径
  • root_cert_path - 根证书文件路径。

例如:

{
  "address": "your.chaincode.host.com:9999",
  "dial_timeout": "10s",
  "tls_required": true,
  "client_auth_required": "true",
  "key_path": "path/rooted/in/release/directory/key.pem",
  "cert_path": "path/rooted/in/release/directory/cert.pem",
  "root_cert_path": "path/rooted/in/release/directory/rootcert.pem"
}

TLS文件可以放在code.tar.gz归档的任何地方,因为.tar.gz文件夹内的文件内容将会提供给外部链码构建脚本。bin/release脚本,将会将文件移动到合适的位置。

metadata.json文件要求

当使用链码作为外部服务时,需要在metadata.json文件中设置type字段,为了指定使用的是外部服务,例如:

{"path":"","type":"external","label":"mycc"}

配置节点对外部链码进行处理

这个过程和外部构建与扩展介绍的内容是相似的。利用这些脚本来定义外部链码信息。这些脚本位于peer节点的文件系统并且可以访问并处理peer节点处的core.yaml文件中chaincode部分定义的externalBuilders元素。

创建peer节点上的外部构建器和运行器脚本

为了配置链码作为外部服务,必须使用以下脚本文件:

  • detect - 检测metadata.json文件中type是否设置为external并接受链码包。
  • build - 构建链码并将构建的归档放置在BUILD_OUTPUT_DIR位置。脚本提取connection.json文件中的链码端点信息并将code.tar.gz文件中的其他归档文件放置在指定位置。
  • release - 拷贝被构建的归档(在connection.sjon文件中)到指定位置。

注意到对于链码作为外部服务,没有要求外部构建器和运行器bin/run脚本。
脚本文件要求存在peer节点的文件夹内:

    <peer的环境下完全正确的路径>
    └── bin
        ├── build
        ├── detect
        └── release

使peer节点的core.yaml文件包括externalBuilder

最后,为了让peer节点能够使用外部构建器和运行器脚本,需要修改位于peer节点的core.yaml文件中的chaincode部分,使它包括externalBuilder配置元素。

externalBuilders:
     - name: myexternal
       path: <peer的环境下完全正确的路径> #就是上面的那个路径

外部构建和运行的脚本文件模板

为了帮助理解在链码作为外部服务时,每一个脚本需要包含哪些工作,这一部分包含bin/detect,bin/build,bin/release脚本示例。
这些例子使用jq命令对json个数数据进行转换,可以通过运行jq --version检查是否安装该工具。否则,需要安装jq或者对脚本文件进行适当的修改。

/bin/detect

bin/detect脚本的职责是决定是否使用buildpack对链码包进行构建和运行。对于链码作为外部服务,脚本需要检测metadata.json文件中的type是否被设置为externalpeer节点通过两个参数调用该脚本:

bin/detect CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR

一个典型的detect脚本应该包含:

#!/bin/bash

set -euo pipefail

if [ "$#" -ne 2 ]; then
    >&2 echo "Expected 2 directories got $#"
    exit 2
fi

#检测`type`是否被设置为`external`
if [ "$(jq -r .type "$2/metadata.json")" == "external" ]; then
    exit 0
fi

exit 1

metadata.json文件应该包含以下关键点:

{"path":"","type":"external","label":"mycc"}

/bin/build

bin/build脚本的职责是构建,编译,以及转换链码包内容到可以被releaserun使用的归档中。对于链码作为外部服务,该脚本拷贝connection.json文件到BUILD_OUTPUT_DIR.peer节点通过三个参数调用该脚本:

bin/build CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR BUILD_OUTPUT_DIR

一个典型的build脚本应该包含:

#!/bin/bash

set -euo pipefail

if [ "$#" -ne 3 ]; then
    >&2 echo "Expected 3 directories got $#"
    exit 1
fi

SOURCE=$1
OUTPUT=$3

#检查connection.json文件是否存在
if [ ! -f "$SOURCE/connection.json" ]  ; then
    >&2 echo "$SOURCE/connection.json not found"
    exit 1
fi

#如果需要的话在这里做更多验证

#简单拷贝端点信息到指定的输出位置
cp $SOURCE/connection.json $OUTPUT/connection.json

exit 0

/bin/release

bin/release脚本的职责是为peer节点提供链码元数据。对于链码作为外部服务,bin/release脚本作用是为peer提供放置在RELEASE_OUTPUT_DIR位置的connection.json文件。peer节点通过两个参数调用该脚本:

bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR

一个典型的release脚本应该包含:

#!/bin/bash

set -euo pipefail

set -x

if [ "$#" -ne 2 ]; then
    >&2 echo "Expected 2 directories got $#"
    exit 2
fi

BLD="$1"
RELEASE="$2"

#外部链码期望归档被放置在"$RELEASE"/chaincode/server路径下
if [ -f $BLD/connection.json ]; then
   mkdir -p "$RELEASE"/chaincode/server
   cp $BLD/connection.json "$RELEASE"/chaincode/server
   exit 0
fi

exit 1

编写链码作为外部服务运行

当前,将链码作为外部服务运行模板只支持GO语言链码shim.在Fabric v2.0,Go shim API添加了ChaincodeServer类型。开发者可以使用它创建链码服务。InvokeQueryAPI不受影响。开发者需要写shim.ChaincodeServerAPI,然后选择构建链码并在外部环境中运行。这里有一个简单的链码程序模板用来说明这种模式:

package main

import (
        "fmt"

        "github.com/hyperledger/fabric-chaincode-go/shim"
        pb "github.com/hyperledger/fabric-protos-go/peer"
)

// SimpleChaincode 模板简单链码实现
type SimpleChaincode struct {
}

func (s *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
        // 初始化代码
}

func (s *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
        // 调用代码
}

//NOTE - ccid 和端点信息参数很难在这里编码说明,可以通过多种标准方式指定
func main() {
       //ccid 设计用来安装链码实例 (使用“peer lifecycle chaincode install <package>” 命令) for instance
        ccid := "mycc:fcbf8724572d42e859a7dd9a7cd8e2efb84058292017df6e3d89178b64e6c831"

        server := &shim.ChaincodeServer{
                        CCID: ccid,
                        Address: "myhost:9999"
                        CC: new(SimpleChaincode),
                        TLSProps: shim.TLSProperties{
                                Disabled: true,
                        },
                }
        err := server.Start()
        if err != nil {
                fmt.Printf("Error starting Simple chaincode: %s", err)
        }
}

将链码作为外部服务运行关键的是使用shim.ChaincodeServer.使用的新的链码服务shimAPIshim.ChaincodeServer属性描述如下:

  • CCID(string):CCID应该匹配peer节点上的链码包。CCID与被安装的链码关联,在使用peer lifecycle chaincode install <package>CLI命令返回。这可以在安装后使用peer lifecycle chaincode queryinstalled命令获得。
  • Address(string):链码服务的监听地址。
  • CC(Chaincode):处理初始化和调用的链码
  • TLSProps(TLSProperties):链码服务的TLS属性。
  • KaOpts(keepalive.ServerParameters):保持连接选项,默认为空

部署链码

当GO语言链码准备好部署后,可以通过Packageing chaincode部分解释的内容对链码进行打包。并通过chaincode lifecycle部分内容对链码进行部署。

将链码作为外部服务运行

根据指定的编写链码作为外部服务运行部分创建链码,并选择构建可运行的链码环境如Kubernetes或者直接在peer主机上运行。

使用链码作为外部服务模板,将不再要求在每一个节点上安装链码。当链码端点在peer节点上部署并运行后,可以继续正常地实例化和调用链码。

posted @ 2019-12-27 10:18  触不可及`  阅读(469)  评论(0编辑  收藏