1.why
kubernetes是使用go语言编写的,对于很多同学来说,可能对这种语言机制不甚熟悉。掌握调试方法,一方面能够精准定位问题,另一方面对学习相关语言也有反向促进机制。摩刀不误砍柴功。只要有源码,任何问题都是可以解决的,剩下的只是时间问题。
2.准备工作
- 安装delve
delve是目前最方便用于调试golang的工具,安装delve有两种方法:
- 使用go命令:
go get -u github.com/derekparker/delve/cmd/dlv
- 使用源码
https://github.com/derekparker/delve
make install
2.编译kubernetes组件
- 通过make help查看如何编译带调试信息的kubernetes组件
[newcent@localhost kubernetes-1.9.2]$ make help
--------------------------------------------------------------------------------
all
# Build code.
#
# Args:
# WHAT: Directory names to build. If any of these directories has a 'main'
# package, the build will produce executable files under _output/go/bin.
# If not specified, "everything" will be built.
# GOFLAGS: Extra flags to pass to 'go' when building.
# GOLDFLAGS: Extra linking flags passed to 'go' when building.
# GOGCFLAGS: Additional go compile flags passed to 'go' when building.
#
# Example:
# make
# make all
# make all WHAT=cmd/kubelet GOFLAGS=-v
# make all GOGCFLAGS="-N -l"
# Note: Use the -N -l options to disable compiler optimizations an inlining.
# Using these build options allows you to subsequently use source
# debugging tools like delve.
---------------------------------------------------------------------------------
......
- 使用make all GOGCFLAGS="-N -l"编译kubernetes组件
3.调试kubelet
- 将编译kubelet拷贝到相应的node上
- 在node上通过dlv启动kubelet
dlv exec ./kubelet --headless -l 192.168.122.12:1234 -- --logtostderr=true --v=0 --allow-privileged=false --address=0.0.0.0 --hostname-override=node1 --pod-infra-container-image=gcr.io/google_ctainers/pause-amd64:3.0 --kubeconfig=/etc/kubernetes/kubelet.kubeconfig --cgroup-driver=systemd
--headless -l 192.168.122.12:1234指定启动一个调试server端,因为编译kubernetes组件往往不会在node上编译,node上也没有相应的源码,通过这一机制,可以在编译节点上启动dlv client,调试相关代码。
- 在编译节点上连接server端
[newcent@localhost kubernetes-1.9.2]$ dlv connect 192.168.122.12:1234
Type 'help' for list of commands.
(dlv) b main.main
Breakpoint 1 set at 0x394496b for main.main() ./_output/local/go/src/k8s.io/kubernetes/cmd/kubelet/kubelet.go:44
(dlv) c
> main.main() ./_output/local/go/src/k8s.io/kubernetes/cmd/kubelet/kubelet.go:44 (hits goroutine(1):1 total:1) (PC: 0x394496b)
Warning: debugging optimized function
Warning: listing may not match stale executable
39: func die(err error) {
40: fmt.Fprintf(os.Stderr, "error: %v\n", err)
41: os.Exit(1)
42: }
43:
=> 44: func main() {
45: // construct KubeletFlags object and register command line flags mapping
46: kubeletFlags := options.NewKubeletFlags()
47: kubeletFlags.AddFlags(pflag.CommandLine)
48:
49: fmt.Printf("args: %s\n", os.Args[0])
(dlv)
4.delve使用方法(附)
命令 | 描述 |
---|---|
args | 打印函数参数 |
break | 设置断点 |
brekpoints | 打印活跃断点 |
clear | 删除断点 |
check? | 在当前位置创建一个检查点 |
checkpoints | 打印存在的检查点 |
clear-checkpoint | 删除检查点 |
clearall | 删除多个断点 |
condition | 设置条件断点 |
config? | 改变配置参数 |
continue | 继续执行 |
disassemble | 反汇编器 |
exit | 退出调式 |
frame? | 在不同的帧上执行命令 |
funcs | 打印函数列表 |
goroutine | 展示当前协程 |
help | 打印帮助文档 |
list | 展示源代码 |
locals | 打印局部变量 |
next | 跳到下一行源代码 |
on? | 当断点被命中后执行一个命令 |
打印表达式 | |
regs | 打印CPU寄存器内容 |
restart | 从checkpoint或事件开始重启进程 |
rewind? | 回退知道断点或程序终止 |
set | 改变一个变量的值 |
source | 执行一个包含delve命令列表的文件 |
stack | 打印调用栈 |
step | 单步执行 |
step-instruction | 单个CPU指令执行 |
stepout | 跳出当前函数 |
thread | 切换至某个具体的函数 |
threads | 打印每一个所跟踪的线程信息 |
trace | 设置一个跟踪点 |
types | 打出类型列表 |
vars? | 打印封装变量 |