背景
最近在看同事之前写的代码,代码中用到了k8s,需要操作k8s资源,导致项目在本地压根就运行不起来。 之前的其他项目,虽然某些方法也在本地的goland中调不通,但是不影响整体逻辑,mock掉无法调用的接口即可。 但是现在显然mock无法使用,因为主要的逻辑就是操作k8s的资源,而k8s环境根本无法mock。
项目有测试环境和正式环境。 测试环境一般是和正式环境完全一致的,测试环境任何步骤都需要能够走通,也就是说,测试环境就是一个合格的,尽全力模拟的真实环境。 如何才能有一个和测试环境一模一样的环境用来debug调试代码呢? 答案就是,我们真的调试远程的代码、进程。
使用工具
在linux服务器上安装golang环境,并安装于之对应的dlv调试工具(专门用来调试 go代码的工具),推荐安装最新的go版本和dlv工具。
安装go教程:Download and install - The Go Programming Language
安装dlv教程:delve/Documentation/installation at master · go-delve/delve · GitHub
安装成功后执行 dlv version,会输出其版本号。 如果系统显示无法找到dlv命令,可以使用如下命令先找到dlv二进制文件所在的位置
find / -name "dlv" 2>/dev/null
然后使用export 让全局临时生效, /root/go/bin 是dlv所在的路径
export PATH=$PATH:/root/go/bin
具体过程
调试分为两种情况,第一种情况是调试web程序,例如gin、begoo,程序已经运行起来了,已经变成了一个进程,这时候,我们需要调试这个进程。 第二种情况是,现在没有进程,但是有二进制文件,要开始运行二进制文件。
第一种情况:调试进程
首先,进程来源于一个已经运行过的二进程文件,我们要保证在编译这个二进制文件的时候,禁止内连优化,因为内连优化会让代码结构重新整合。 到时候在goland上面调试的时候,debug的行将会出现问题。 禁止内连优化的命令:
go build -gcflags "all=-N -l"
其次,要保证本地的代码和进程对应的二进制文件是一致的。 我们可以在本地编译,这样二进制文件和本地调试的代码就是完全一致的。然后再把二进制文件传输到服务器上面。
然后执行如下命令:
# 找到对应的进程号
ps aux | grep "二进制文件名"
# 调试7488进程,同时暴漏服务器的2345端口,让后续goland可以连接
dlv --headless -l 0.0.0.0:2345 attach 7488 --api-version 2
然后打开goland
然后打上断点,就可以debug了。
第二种情况:调试二进制文件
现在有一个 demo 二进制文件
./dlv --listen=:8095 --headless=true --api-version=2 --accept-multiclient exec /home/work/demo -- -d --jobId 3785 --param 'xxx'
-- 是dlv 的命令要求,后续所有的都是demo二进制文件需要的参数
此命令执行之后,程序不会执行,等我们在本地使用goland连接到之后,本地自动进入到main方法中。