在Hyperledger Fabric 2.0中引入的一个新特性,就是可以 使用外部的链码启动器,这种外部启动链码的方式非常适合 使用kubenetes或dowcker swarm来统一管理节点容器和链码容器。 在这片文章中,我们将学习如何使用外部链码启动器在K8s集群 中部署链码。
1、Fabric外部链码实验的前提条件
下面是我们实验的一些前提条件
- 一个kubenetes集群,你可以使用minikube或一个单节点的kubeadmin。在 本文中我们使用kubeadmin
- hyperledger fabric 2.0.1 docker镜像
- hyperledger fabric 2.0.1 预编译程序。我们需要其中的工具来创建 密码学资料和通道交易配置文件。可以从这里下载。
- 从这里下载本文的代码
2、安装预编译程序
使用以下命令安装预编译程序:
1 | wget https://github.com/hyperledger/fabric/releases/download/v2.0.1/hyperledger-fabric-linux-amd64-2.0.1.tar.gz |
3、启动Hyperledger Fabric网络
一旦我们启动了kubernetes集群,就可以启动Fabric网络了。但是我们先要 生成基本的密码学资料以及网络创世区块。在configtx.yaml中有一些修改 以适应fabric 2.0中新的chaincode lifecycle命令,这些修改对于使用外部 链码启动器是必须的。
Fabric区块链网络中包含3个RAFT排序服务节点,2个机构org1和org2各含1个 peer节点以及一个CA。这些信息已经编码在configtx.yaml和crypto-config.yaml 文件中,不需要修改。
有了配置文件,现在我们可以生成fabric区块链网络的密码学资料和创世区块。 我们使用fabricOps.sh脚本:
1 | $ ./fabricOps.sh start |
上面的命令将生成所有的密码学资料,例如节点和CA的证书等,以及通道的 创世区块。
现在需要为Hyperledger Fabric工作负载创建一个新的k8s命名空间,命令如下:
1 | $ kubectl create ns hyperledger |
然后创建一个文件夹来保存Hyperledger Fabric工作负载的持久化数据:
1 | $ mkdir /home/storage |
好了,现在可以开始部署Fabric排序节点了:
1 | $ kubectl create -f orderer-service/ |
使用下面命令检查Fabric网络是否启动正常:
1 | $ kubectl get pods -n hyperledger |
接下来创建org1的工作负载,这主要包含部署机构的CA和peer节点:
1 | $ kubectl create -f org1/ |
同样用下面命令检查Fabric网络节点是否启动:
1 | $ kubectl get pods -n hyperledger |
重复上面的步骤来加载org2的工作负载:
1 | $ kubectl create -f org2/ |
检查Fabric网络情况:
1 | $ kubectl get pods -n hyperledger |
3、设置Fabric网络的通道
一旦部署完Fabric网络的工作负载,我们可以开始创建通道并将peer节点加入通道。 进入org1的cli:
1 | $ kubectl exec -it cli_org1_pod_name sh -n hyperledger |
在这个pod内执行如下命令:
1 | $ peer channel create -o orderer0:7050 -c mychannel -f ./scripts/channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA |
现在mychannel通道已经创建好了,接下来将org1的peer节点加入通道:
1 | $ peer channel join -b mychannel.block |
同样的操作将org2的peer节点加入通道。不过由于org1已经创建了通道, 因此我们需要从排序服务提取通道创世块。首先进入pod:
1 | $ kubectl exec -it cli_org2_pod_name sh -n hyperledger |
然后在pod内执行如下操作:
1 | $ peer channel fetch 0 mychannel.block -c mychannel -o orderer0:7050 --tls --cafile $ORDERER_CA |
然后加入通道:
1 | $ peer channel join -b mychannel.block |
用下面的命令检查当前节点是否已经加入了通道:
1 | $ peer channel list |
4、在Fabric节点安装外部链码
现在开始我们进入真正有趣的环节。我们将部署marbles链码作为外部链码。你可以在Fabric-samples 中找到原始的链码,但是为了将其作为外部链码部署,我们需要在imports和init函数中进行一些修改, 以将其声明为外部链码服务器。
新版本的Hyperledger Fabric同样包含了新的链码处理流程来支持外部方式安装和启动链码。为了 使用外部链码特性,我们也需要使用这一新的流程。
第一件要做的事情就是将peer节点配置为可以处理外部链码。外部链码构建器就是基于buildpack 实现,因此我们创建3个脚本:detect、build和release。这三个脚本必须在peer容器内定义。你可以 在buildpack/bin目录下找到这些脚本。
链码构建器定义在org1目录下的builders-config.yaml中,其中的自定义构建器配置:
1 | # List of directories to treat as external builders and launchers for |
kubernetes使用环境变量来配置peer节点,这些环境变量将覆盖core.yaml中 的默认值。
Fabric 2.0采用了与之前版本不同的方式来打包和安装链码。由于我们要使用 外部链码特性,因此链码代码不需要在peer的pod内进行编译和安装,而是在另一个 pod中进行。在peer进程中唯一需要的就是用来连接外部链码进程的信息。
为此,我们需要打包链码的一些准备。需要一个connection.json文件,其中 包含连接外部链码服务器的信息,例如地址、TLS证书、连接超时配置等。
1 | { |
这个文件需要打包进一个tar文件,code.tar.gz,使用如下命令进行压缩打包:
1 | $ cd chaincode/packaging |
一旦有了code.tar.gz文件,我们需要将其与另一个文件metadata.json一起重新打包。在 metadata.json中包含了链码类型、路径、标签等信息:
1 | {"path":"","type":"external","label":"marbles"} |
使用下面的命令打包:
1 | $ tar cfz marbles-org1.tgz code.tar.gz metadata.json |
一旦有了上面的打包文件,我们就可以使用新的 lifecycle chaincode install 命令来安装链码了:
1 | $ peer lifecycle chaincode install marbles-org1.tgz |
记下来上面的链码包标识符,我们接下来会用到,不过你也可以随时用下面 的命令查询链码包的标识符:
1 | $ peer lifecycle chaincode queryinstalled |
现在我们为org2重复上面的步骤,但是由于我们希望用另一个pod为org2的peer节点提供链码服务, 因此我们需要修改connection.json中的地址配置:
1 | "address": "chaincode-marbles-org2.hyperledger:7052", |
然后重复之前的步骤,在org2的cli pod中执行如下命令:
1 | $ rm -f code.tar.gz |
同样记录链码包的标识符,它应该与之前org1的不同。
当我们安装链码时在peer内部发生了什么?如果定义了外部构建器或启动器, 那么就不会执行内置的链码构建过程。由于我们已经定义了外部构建器, 那么将按下面的顺序执行外部构建脚本:
detect
脚本检测要安装的链码是否在metadata.json中配置为external类型。
如果脚本失败,那么peer将认为这个外部构建器不需要构建链码并尝试其他
外部构建器,直到最终没有可用的外部构建器时,使用内置的docker构建流程。
1 | #!/bin/sh |
如果detect
脚本成功,那么就调用build
脚本。如果在peer内部构建链码,那么
这个脚本应当生成二进制程序。但是由于我们希望作为外部服务,那么只需要简单
的拷贝connection.json文件到build的输出目录就可以了。
1 | #!/bin/sh |
最后,一旦build
脚本执行完毕,就会调用release
脚本。这个脚本负责
提供connection.json文件给peer节点,它只需要将该文件放到release输出目录
就可以了。因此,peer现在知道如何调用链码了。
1 | #!/bin/sh |
5、Fabric外部链码的构建与部署
一旦我们在peer节点上安装了链码,就可以构建并在我们的kubernetes集群上部署 这些链码了。让我们看一下必要的修改。
首先需要import一些必要的模块:
1 | import ( |
需要指出的一点是,在构建代码之前需要定义go.mod文件。最新版本的shim 模块中包含了对外部链码特性的支持 —— 目前只有go 链码开发包支持外部链码。
1 | module github.com/marbles |
其他的变化包括修改链码服务器的监听地址、端口等。因为我们希望使用kubernetes 的yaml描述文件来修改这些配置,因此我们使用os模块来获取这些值:
1 | func main() { |
现在可以用下面的Dockerfile来构建链码镜像:
1 | # This image is a microservice in golang for the Degree chaincode |
链码是使用一个golang的alpine镜像构建的。执行如下命令创建链码镜像:
1 | $ docker build -t chaincode/marbles:1.0 . |
一切顺利的话,就可以部署了。修改链码部署文件org1-chaincode-deployment.yaml 和org2-chaincode-deployment.yaml中的CHAINCODE_CCID变量为你需要安装的链码。
1 | #---------------- Chaincode Deployment --------------------- |
然后进行部署:
1 | $ kubectl create -f chaincode/k8s |
现在fabric网络看起来应该是这样:
1 | $ kubectl get pods -n hyperledgerNAME READY STATUS RESTARTS AGE |
现在我们需要为每个机构审批链码。这是链码生命周期过程的一个新特性, 每个机构都需要同意新链码的定义。我们将为org1审批marble链码定义。 在org1的cli pod内执行如下命令,记得修改CHAINCODE_CCID:
1 | $ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')" |
你可以用如下命令检查整个网络中的审批状态:
1 | $ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-require |
现在让我们为org2批准链码定义。在org2的cli pod中执行如下命令,记得修改CHAINCODE_CCID:
1 | $ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:25a9f6fe26161d29af928228ca1db0c41892e26e46335c84952336ee26d1fd93 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')" |
再次检查链码提交状态:
1 | $ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-required --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')" |
现在我们得到所有机构的批准,让我们将链码定义在通道上提交。可以在任何peer上执行如下操作:
1 | $ peer lifecycle chaincode commit -o orderer0:7050 --channelID mychannel --name marbles --version 1.0 --sequence 1 --init-required --tls true --cafile $ORDERER_CA --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt --signature-policy "AND ('org1MSP.peer','org2MSP.peer')" |
好了,现在链码已经就绪,可以查询和调用了!
6、测试Fabric外部链码
我们可以从cli pod中测试链码的查询和交易调用。首先创建一些宝石:
1 | $ peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses |
创建另一个宝石:
1 | $ peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble","marble2","red","50","tom"]}' --waitForEvent |
查询宝石信息:
1 | $ peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble1"]}' |
也可以执行如下命令查询链码日志:
1 | $ kubectl logs chaincode_pod_name -n hyperledger |
原文链接:How to implement Hyperledger Fabric External Chaincodes within a Kubernetes cluster
汇智网翻译整理,转载请标明出处