gdb调试容器中fabric链码

gdb调试容器中fabric链码

使用场景

fabric的链码安装后回直接生成一个docker容器,并在其中运行。我们修改了链码,必须要重新部署非常麻烦,fabric 为我们提供了开发模式,可以直接进行开发和调试。
但是有没有办法走生产模式的方法直接对容器进行调试呢?当然是可以的。

步骤

首先需要链码为可调试的。默认情况下,链码编译出来是有符号表的,但是局部变量被优化了,导致我们没法调试。所以我们需要重新编译并打包peer镜像。
其次需要为容器添加上链码运行的容器安装上gdb,方便我们进行调试。
然后需要把源码拷贝进链码容器。
最后就可以调试链码了。

修改peer

所以我们需要修改编译参数:
在源码 core\chaincode\platforms\golang\platform.go中的

const staticLDFlagsOpts = "-ldflags \"-linkmode external -extldflags '-static'\""

修改为

const staticLDFlagsOpts = "-gcflags \"-N -l\" -ldflags \"-linkmode external -extldflags '-static'\""

然后重新打包peer镜像。我这里打包了一个1.1版本的可以直接pull:

docker pull xiaobing1994/fabric-peer:x86_64-1.1.0

运行时可以根据需要直接指定镜像或打tag为hyperledger/fabric-peer:x86_64-1.1.0

重新构建运行的基础容器

这里以fabric1.1为例,需要的基础容器是hyperledger/fabric-baseos:x86_64-0.4.6,编写dockerfile如下:

FROM hyperledger/fabric-baseos:x86_64-0.4.6
MAINTAINER xiaobing
RUN apt-get update
RUN apt-get install gdb -y
RUN mkdir -p /chaincode/input/src/github.com/hyperledger/fabric/chaincode/go/

编译容器

docker build -t fabric-baseos:x86_64-0.4.6 .

将tag打为hyperledger/fabric-baseos:x86_64-0.4.6

# 移除以前的tag名
docker rmi hyperledger/fabric-baseos:x86_64-0.4.6
docker tag fabric-baseos:x86_64-0.4.6 hyperledger/fabric-baseos:x86_64-0.4.6

运行fabric,并安装链码

fabric,以最简单的solo为例。这里有一份已经做好的简单的compose文件。为了容器网络正常,请将其放在solo文件夹下
运行服务

docker-compose -f docker-solo.yaml up -d

进入cli容器

docker exec -it cli bash

创建并加入channel

peer channel create -o orderer.example.com:7050 -c mychannel -f ./channel-artifacts/channel.tx
peer channel join -b mychannel.block

安装并初始化链码

peer chaincode install -n mycc -p github.com/hyperledger/fabric/chaincode/go/chaincode_example02 -v 1.0
peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n mycc -c '{"Args":["init", "a", "100", "b", "200"]}' -P "OR ('Org1MSP.member')" -v 1.0

调试链码

  1. 安装nsenter
    nsenter 工具在 util-linux 包2.23版本后包含。 nsenter 可以访问另一个进程的名字空间。nsenter 要正常工作需要有 root 权限。
    cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;
    ./configure --without-ncurses
    make nsenter && sudo cp nsenter /usr/local/bin
    
  2. 拷贝代码进容器
    这里目标地址都是一样,链码位置可以指定自己的链码位置。
    docker cp chaincode/go/chaincode_example02 8102daa6788f:/chaincode/input/src/github.com/hyperledger/fabric/chaincode/go/
    
  3. 查看链码信息
    docker ps 
    
    获取链码id
    CONTAINER ID        IMAGE                                                                                                           COMMAND                  CREATED             STATUS              PORTS   NAMES
    8102daa6788f        solo_default-peer0.org1.example.com-mycc-1.0-d70cdde6b5cc928f7ceae6232bb1077cfa1bf9044c849224fee277e52765db89   "chaincode -peer.add…"   2 minutes ago       Up 2 minutes solo_default-peer0.org1.example.com-mycc-1.0
    
    则容器id为"8102daa6788f"
  4. 进入容器查看链码进程pid
    将对应的id替换为自己的容器id
    docker exec -it 8102daa6788 bash
    
    执行
    ps aux
    
    结果如下,则pid为1
    USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root          1  0.0  0.5  39160 10148 ?        Ssl  07:24   0:00 chaincode -peer.address=peer0.org1.example.com:7052
    root          9  0.5  0.1  18240  3172 pts/0    Ss   07:30   0:00 bash
    root         19  0.0  0.1  34424  2812 pts/0    R+   07:31   0:00 ps aux
    
  5. 查看该容器对应的Pid,注意替换容器id:
    docker inspect -f {{.State.Pid}} 8102daa6788f
    
    结果如下:
    68530
    
  6. 执行调试
    调试命令如下,注意替换容器外部pid和容器内部的id:
    sudo nsenter -t 68530 -m -p gdb -p 1
    
  7. 进行调试
    ubuntu@ubuntu:~$ sudo nsenter -t 68530 -m -p gdb -p 1
    [sudo] password for ubuntu: 
    GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.5) 7.11.1
    Copyright (C) 2016 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later 
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
    and "show warranty" for details
    This GDB was configured as "x86_64-linux-gnu".
    Type "show configuration" for configuration details.
    For bug reporting instructions, please see:
    .
    Find the GDB manual and other documentation resources online at:
    .
    For help, type "help".
    Type "apropos word" to search for commands related to "word".
    Attaching to process 1
    [New LWP 6]
    [New LWP 7]
    [New LWP 8]
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    runtime.futex () at /opt/go/src/runtime/sys_linux_amd64.s:439
    439	/opt/go/src/runtime/sys_linux_amd64.s: No such file or directory.
    warning: Missing auto-load script at offset 0 in section .debug_gdb_scripts
    of file /usr/local/bin/chaincode.
    Use `info auto-load python-scripts [REGEXP]' to list them.
    (gdb) b chaincode_example02.go
    Function "chaincode_example02.go" not defined.
    Make breakpoint pending on future shared library load? (y or [n]) n
    (gdb) b chaincode_example02.go:71
    Breakpoint 1 at 0x9778a1: file /chaincode/input/src/github.com/hyperledger/fabric/chaincode/go/chaincode_example02/chaincode_example02.go, line 71.
    (gdb) l
    434	in /opt/go/src/runtime/sys_linux_amd64.s
    (gdb) c
    Continuing.
    [Switching to Thread 0x7fa61c60f700 (LWP 7)]
    
    Thread 3 "chaincode" hit Breakpoint 1, main.(*SimpleChaincode).Invoke (t=0x113bcc0 , stub=..., ~r1=...) at /chaincode/input/src/github.com/hyperledger/fabric/chaincode/go/chaincode_example02/chaincode_example02.go:71
    71		function, args := stub.GetFunctionAndParameters()
    (gdb) l
    66		return shim.Success(nil)
    67	}
    68	
    69	func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
    70		fmt.Println("ex02 Invoke")
    71		function, args := stub.GetFunctionAndParameters()
    72		if function == "invoke" {
    73			// Make payment of X units from A to B
    74			return t.invoke(stub, args)
    75		} else if function == "delete" {
    (gdb) 
    

总结

该方法还是较为麻烦,只是提供了一种调试容器中的链码的可能性。常规开发模式下,还是使用开发模式进行调试更为方便快捷。

你可能感兴趣的:(超级账本)