fabric如何定制chaincode运行container

CodingCode · · 323 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

以golang语言chaincode为例子,当前golang chaincode是编译成一个叫chaincode的静态可执行文件,然后peer基于fabric-baseos为chaincode创建一个image,并把可执行文件chaincode打入新的image;然后在运行的时候使用root身份调用chaincode --peer.address=...

有些时候我们可能会有一些新的需求:

  1. 在调用chaincode可执行程序之前做些其他的额外工作,例如设置环境等等。
  2. 让chaincode运行在普通用户空间,而不是root用户。
  3. 另外fabric-baseos包含的内容太少,很多常用的linux工具都没有打进去。

下面几个地方可以修改来达到上述目的:

  1. core/chaincode/platforms/platforms.go

在build chaincode image的时候创建一个app用户,下面例子使用peer的当前运行用户,作为chaincode的运行用户。

func (r *Registry) GenerateDockerfile(ccType, name, version string) (string, error) {
    ...
    buf = append(buf, fmt.Sprintf("ENV CORE_CHAINCODE_BUILDLEVEL=%s", metadata.Version))

+   // Set chaincode execution user
+   u, err := user.Current()
+   if err != nil {
+       return "", fmt.Errorf("Failed to get current user: %s", err)
+   }
+   logger.Debugf("Current username=%s, uid=%s", u.Username, u.Uid)
+   g, err := user.LookupGroupId(u.Gid)
+   if err != nil {
+       return "", fmt.Errorf("Failed to get current group: %s", err)
+   }
+   logger.Debugf("Current groupname=%s, gid=%s", g.Name, g.Gid)
+   buf = append(buf, fmt.Sprintf("RUN groupadd -g %s %s && useradd -u %s -g %s -s /bin/bash %s", g.Gid, g.Name, u.Uid, g.Name, u.Username))

    // ----------------------------------------------------------------------------------------------------
    // Finalize it
    // ----------------------------------------------------------------------------------------------------
    ...
}
  1. core/chaincode/platforms/util/utils.go

创建一个entrypoint.sh入口脚本,代替原来的chaincode,这样我们可以在entrypoint.sh里面做很多工作,然后在脚本的最后launch chaincode就可以了。

func DockerBuild(opts DockerBuildOptions) error {
    ...
    if err != nil {
        return fmt.Errorf("Error uploading input to container: %s", err)
    }

+   entrypointBody := `#!/usr/bin/env sh
+
+ echo "Entry of chaincode"
+ #
+ # Do whatever expected
+ #
+ exec su -p ccuser -c "$@"
+ `
+    // put entrypoint.sh into chaincode image, just like chaincode binary
+    var buf bytes.Buffer
+    tw := tar.NewWriter(&buf)
+    hdr := &tar.Header{
+            Name: "entrypoint.sh",
+            Mode: 0755,
+            Size: int64(len(entrypointBody)),
+    }
+    err = tw.WriteHeader(hdr)
+    if err != nil {
+        return fmt.Errorf("Error writing entrypoint header: %s", err)
+    }
+    _, err = tw.Write([]byte(entrypointBody))
+    if err != nil {
+        return fmt.Errorf("Error writing entrypoint body: %s", err)
+    }
+    err = tw.Close()
+    if err != nil {
+        return fmt.Errorf("Error closing entrypoint: %s", err)
+    }
+
+    type St struct {
+        *bytes.Buffer
+    }
+    in := St{bytes.NewBufferString(string(buf.Bytes()))}
+    err = client.UploadToContainer(container.ID, docker.UploadToContainerOptions{
+        Path:        "/chaincode/output",
+        InputStream: in,
+    })
+    if err != nil {
+        return fmt.Errorf("Error uploading input to container: %s", err)
+    }

    //-----------------------------------------------------------------------------------
    // Attach stdout buffer to capture possible compilation errors
    //-----------------------------------------------------------------------------------
}
  1. core/chaincode/container_runtime.go

修改chaincode image的入口代码:

func (c *ContainerRuntime) LaunchConfig(cname string, ccType string) (*LaunchConfig, error) {
    ...
        switch ccType {
        case pb.ChaincodeSpec_GOLANG.String(), pb.ChaincodeSpec_CAR.String():
-               lc.Args = []string{"chaincode", fmt.Sprintf("-peer.address=%s", c.PeerAddress)}
+               lc.Args = []string{"entrypoint.sh", fmt.Sprintf("chaincode -peer.address=%s", c.PeerAddress)}  // it's OK
    ...
}
  1. peer的core.yaml文件
###############################################################################
#
#    VM section
#
###############################################################################
vm:
    docker:
        hostConfig:
            CapAdd:
+              - NET_ADMIN
+              - NET_RAW

###############################################################################
#
#    Chaincode section
#
###############################################################################
chaincode:
    # Generic builder environment, suitable for most chaincode types
    builder: $(DOCKER_NS)/fabric-ccenv:latest

    golang:
-       runtime: $(BASE_DOCKER_NS)/fabric-baseos:$(ARCH)-$(BASE_VERSION)
+       runtime: $(BASE_DOCKER_NS)/fabric-baseimage:$(ARCH)-$(BASE_VERSION)

这里我们把fabric-baseos改成了fabric-baseimage,因为fabric-baseos包含的内容太少了,想在entrypoint.sh做一点点事也做不了。当然你可以创建自己baseimage把需要的工具打进去,然后在这里指定就行了。
另外增加了CAP的NET_ADMIN和NET_RAW是为了管理container网络,例如可以要通过iptables限制chaincode网络访问等。

有了这个步骤,我们就可以对chaincode container进行控制管理。


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:CodingCode

查看原文:fabric如何定制chaincode运行container

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

323 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传