HyperLedger Fabirc 2.0(链码容器运行在peer容器中)

986 阅读3分钟

使用扩展构建器和启动器在peer容器内部构建、运行链码。在Fabric2.0之前,链码的构建和运行由peer节点的实现,是一种强耦合的模式,peer必须依赖本地宿主机的docker来构建和启动链码容器。Fabric2.0将链码的构建和运行逻辑抽离出来了,用户可以自定义构建起和启动器来实现链码的构建和运行。基于自定义的扩展构建器和启动器,可以实现在peer容器内部构建链码和运行链码。

扩展构建启动器

Hyperledger Fabric扩展构建器和启动器基于Heroku Buildpacks,是一套程序脚本的集合,可以支持发现链码、执行链码功能。

扩展构建启动器由以下4部分程序脚本组成:

  • detect 接收两个参数CHAINCODE_SOURCE_DIR、CHAINCODE_METADATA_DIR,确定是否应使用此buildpack来构建和启动chaincode程序包。
  • build 接收三个参数CHAINCODE_SOURCE_DIR、CHAINCODE_METADATA_DIR、BUILD_OUTPUT_DIR将chaincode源码包转换为可执行的chaincode包。
  • release(可选)接收两个参数BUILD_OUTPUT_DIR、RELEASE_OUTPUT_DIR,向peer提供有关链码的元数据。
  • run (可选)接收两个参数BUILD_OUTPUT_DIR、RUN_METADATA_DIR,运行链码。

这里可以参考官方文档实现

实现external-builder

  1. 创建external-builder/bin文件夹。

  2. 实现detect,在bin目录下创建detect文件(无需后缀)。以detect返回码来决定构建和启动,返回码为0,则启用buidpack,否则使用docker build的方式。

    #!/bin/sh
    
    # Copyright IBM Corp. All Rights Reserved.
    # 
    # SPDX-License-Identifier: Apache-2.0
    
    set -euo pipefail
    
    if [ "$#" -ne 2 ]; then
        >&2 echo "Expected 2 directories got $#"
        exit 2
    fi
    
    >&2 jq . "$2/metadata.json"
    
    if [ "$(jq -r .type "$2/metadata.json" | tr '[:upper:]' '[:lower:]')" != "golang" ]; then
        >&2 echo "only golang chaincode supported"
        exit 1
    fi
    
  3. 实现build,在bin目录下创建build文件。build对chaincode源码进行编译,并存储到peer指定的目录中。

    #!/bin/sh
    
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    
    set -euo pipefail
    
    if [ "$#" -ne 3 ]; then
        >&2 echo "Expected 3 directories got $#"
        exit 1
    fi
    
    SOURCE=$1
    METADATA=$2
    OUTPUT=$3
    
    >&2 jq . "$2/metadata.json"
    
    if [[ "$(jq -r .label "$METADATA/metadata.json")" == *fail* ]]; then
        >&2 echo "Exiting with failure..."
        exit 1
    fi
    
    GO_PACKAGE_PATH="$(jq -r .path "$METADATA/metadata.json")"
    if [ -f "$SOURCE/src/go.mod" ]; then
        cd "$SOURCE/src"
        go build -v -mod=readonly -o "$OUTPUT/chaincode" "$GO_PACKAGE_PATH"
    else
        GO111MODULE=off go build -v  -o "$OUTPUT/chaincode" "$GO_PACKAGE_PATH"
    fi
    
    # copy index metadata if present
    if [ -d "$SOURCE/META-INF" ]; then
        cp -a "$SOURCE/META-INF" "$OUTPUT"
    fi
    
  4. 实现release,在bin目录下创建release文件。复制编译后的链码相关文件,为run过程做准备。

    #!/bin/sh
    
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    
    set -euo pipefail
    
    if [ "$#" -ne 2 ]; then
        >&2 echo "Expected 2 directories got $#"
        exit 2
    fi
    
    
    BLD="$1"
    RELEASE="$2"
    
    if [ -d "$BLD/META-INF" ] ; then
       cp -a "$BLD/META-INF"/* "$RELEASE"
    fi
    
  5. 实现run,在bin目录下创建run文件。run将会为chaincode生成一个chaincode.json文件(包含一些tls证书,chaincode id等必要信息),最后使用chaincode.json 文件配和chaincode二进制文件来运行chaincode。

    #!/bin/sh
    
    # Copyright IBM Corp. All Rights Reserved.
    #
    # SPDX-License-Identifier: Apache-2.0
    
    set -euo pipefail
    
    if [ "$#" -ne 2 ]; then
        >&2 echo "Expected 2 directories got $#"
        exit 1
    fi
    
    OUTPUT=$1
    ARTIFACTS=$2
    
    # shellcheck disable=SC2155
    export CORE_CHAINCODE_ID_NAME="$(jq -r .chaincode_id "$ARTIFACTS/chaincode.json")"
    export CORE_PEER_TLS_ENABLED="true"
    export CORE_TLS_CLIENT_CERT_FILE="$ARTIFACTS/client.crt"
    export CORE_TLS_CLIENT_KEY_FILE="$ARTIFACTS/client.key"
    export CORE_PEER_TLS_ROOTCERT_FILE="$ARTIFACTS/root.crt"
    export CORE_PEER_LOCALMSPID="$(jq -r .mspid "$ARTIFACTS/chaincode.json")"
    
    jq -r .client_cert "$ARTIFACTS/chaincode.json" > "$CORE_TLS_CLIENT_CERT_FILE"
    jq -r .client_key  "$ARTIFACTS/chaincode.json" > "$CORE_TLS_CLIENT_KEY_FILE"
    jq -r .root_cert   "$ARTIFACTS/chaincode.json" > "$CORE_PEER_TLS_ROOTCERT_FILE"
    
    if [ -z "$(jq -r .client_cert "$ARTIFACTS/chaincode.json")" ]; then
        export CORE_PEER_TLS_ENABLED="false"
    fi
    
    exec "$OUTPUT/chaincode" -peer.address="$(jq -r .peer_address "$ARTIFACTS/chaincode.json")"
    
  6. 赋予以上4个文件可执行权限

    chmod -R 777 ./ 
    

配置扩展构建启动器

修改core.yaml(当然你也可以直接获取这个文件core.yaml),添加扩展构建启动器配置,peer启动时会读取这个文件。

externalBuilders:
        - path: /etc/hyperledger/external-builder
          name: external-builder
          environmentWhitelist:
            - GOPROXY
            - GONOPROXY
            - GOSUMDB
            - GONOSUMDB
            - GOCACHE
            - GOPATH
            - GOROOT
            - HOME
            - XDG_CACHE_HOME

上述的环境变量列表是peer将这些环境变量传给chaincode。

重新构建peer镜像

这里重新构建镜像,是因为原生镜像没有包含go环境和jq命令,将external-builder和core.yaml文件打到镜像中,后面只需替换镜像即可实现cc运行在peer容器中,方便使用。

构建镜像

创建peer-with-external-builder目录,并将扩展构建器和core.yaml拷贝至这里,获取fabric源码并切换到v2.0.0。

完整结构如下:

.
├── Dockerfile
├── core.yaml
├── external-builder
└── fabric

具体的Dockerfile如下:

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0

ARG GO_VER=1.13.4
ARG ALPINE_VER=3.10

FROM golang:${GO_VER}-alpine${ALPINE_VER} as peer-base
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache tzdata jq

FROM golang:${GO_VER}-alpine${ALPINE_VER} as golang
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories
RUN apk add --no-cache \
	bash \
	gcc \
	git \
	make \
	musl-dev 
ADD . $GOPATH/src/github.com/hyperledger
WORKDIR $GOPATH/src/github.com/hyperledger/fabric

FROM golang as peer
ARG GO_TAGS=""
RUN make peer GO_TAGS=${GO_TAGS}

FROM peer-base
ENV FABRIC_CFG_PATH /etc/hyperledger/fabric
ENV CGO_ENABLED=0
VOLUME /etc/hyperledger/fabric
VOLUME /var/hyperledger
COPY --from=peer /go/src/github.com/hyperledger/fabric/build/bin /usr/local/bin
COPY --from=peer /go/src/github.com/hyperledger/fabric/sampleconfig/msp ${FABRIC_CFG_PATH}/msp
COPY --from=peer /go/src/github.com/hyperledger/core.yaml ${FABRIC_CFG_PATH}
COPY --from=peer /go/src/github.com/hyperledger/external-builder /etc/hyperledger/external-builder
EXPOSE 7051
CMD ["peer","node","start"]

打包镜像

docker build -f Dockerfile -t fabric-peer:2.0.0-external-builder .

当然你也可以直接获取我打包好的镜像

docker pull tianrandailoving/fabric-peer:2.0.0-external-builder

test-network测试

使用官方fabric-samples的test-network快速创建fabric网络验证可扩展构建器。

获取test-network启动脚本及相应的二进制工具包文件

curl -sSL https://bit.ly/2ysbOFE | bash -s -- 2.0.0

脚本获取之后,进入test-network目录,修改docker目录下的docker-compose-test-net.yaml文件,将peer镜像替换成我们刚刚打好的镜像。

启动test-network网络,在test-network目录下执行

./network.sh up createChannel

部署链码

./network.sh deployCC

链码部署成功后,可进peer容器,使用top查看进程,可以发现链码以一个进程的方式运行在peer容器中了。

总结

使用自定义扩展构建器,可以脱离原来docker build的方式,自定义扩展构建器可以使cc作为一个单独的进程运行在peer中,也可以实现cc运行在k8s的pod中。

附上源码