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
是否被设置为external
。peer
节点通过两个参数调用该脚本:
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
脚本的职责是构建,编译,以及转换链码包内容到可以被release
和run
使用的归档中。对于链码作为外部服务,该脚本拷贝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
类型。开发者可以使用它创建链码服务。Invoke
和Query
API不受影响。开发者需要写shim.ChaincodeServer
API,然后选择构建链码并在外部环境中运行。这里有一个简单的链码程序模板用来说明这种模式:
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
.使用的新的链码服务shim
APIshim.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
节点上部署并运行后,可以继续正常地实例化和调用链码。