fabric的链码安装后回直接生成一个docker容器,并在其中运行。我们修改了链码,必须要重新部署非常麻烦,fabric 为我们提供了开发模式,可以直接进行开发和调试。
但是有没有办法走生产模式的方法直接对容器进行调试呢?当然是可以的。
首先需要链码为可调试的。默认情况下,链码编译出来是有符号表的,但是局部变量被优化了,导致我们没法调试。所以我们需要重新编译并打包peer镜像。
其次需要为容器添加上链码运行的容器安装上gdb,方便我们进行调试。
然后需要把源码拷贝进链码容器。
最后就可以调试链码了。
所以我们需要修改编译参数:
在源码 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,以最简单的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
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
docker cp chaincode/go/chaincode_example02 8102daa6788f:/chaincode/input/src/github.com/hyperledger/fabric/chaincode/go/
docker ps
获取链码idCONTAINER 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"docker exec -it 8102daa6788 bash
执行ps aux
结果如下,则pid为1USER 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
docker inspect -f {{.State.Pid}} 8102daa6788f
结果如下:68530
sudo nsenter -t 68530 -m -p gdb -p 1
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)
该方法还是较为麻烦,只是提供了一种调试容器中的链码的可能性。常规开发模式下,还是使用开发模式进行调试更为方便快捷。