如何debug minikube里的golang容器?

wallhaven-x6m7md

问题背景

在学习开源项目时,很多时候光看代码是搞不清楚实际运行时会走哪个逻辑分支,或者无法推测方法参数值。最简单的办法是 debug,熟悉某个功能的执行流程。

我们通常用 delve 去 debug golang 程序,但是很多云原生项目运行在 k8s 环境里,在本地我们可以用 minikube 来模拟 k8s。两者结合产生新问题:如何 debug minikube 里的 golang 容器?

剖析 minikube

在 mac 上运行 docker,无论是官方的 Docker Desktop,还是ColimaOrbStack。都是创建了一个 Linux 虚拟机,然后在虚拟机里运行 docker daemon。

image-20240920195959720

minikube 是一个容器,里面运行着另一个 docker daemon,minikube 里 k8s 的 apiServer、controller、scheduler、etcd,就是通过这个 docker daemon 来创建的容器。如果用 minikube 创建了多个 node,那么每个 node 也是一个容器。

image-20240920213452491

验证

  1. 本地启动 docker

  2. 启动 minikube:minikube start --registry-mirror=https://dockerproxy.net

  3. 登录到 minikube 容器:minikube ssh

  4. 查看minikube 里的 docker daemon 进程

    1. image-20240920202427320
  5. 查看 k8s control plane 容器

    1. image-20240920202706902

运行在 minikube 里的 pod,就是用 minikube 容器里的 docker daemon 创建的容器。

image-20240920203100565

image-20240920203017421

这和 docker 官方的 docker in docker 容器类似,都是在容器内部运行独立的 docker daemon 进程。还有一种简单方式实现容器内部使用 docker,就是将宿主机的 docker daemon socke 挂载到容器里,然后容器里的 docker cli 调用该 socket 进行创建容器、构建镜像等,常用于 CI/CD 流水线。

在 mac 上只能看到 minikube 的容器,看不到minikube 内部的容器,近一步证实这是不同的 docker daemon 进程。

image-20240920212246054

我们知道容器就是通过 namespace 技术实现资源隔离,通过 cgroup 实现资源限制,归根结底就是宿主机上的一个进程。所以上面的 minikube 容器,minikube 里运行的 pod,以及我们自己用 docker run 的容器,都是虚拟机里的进程。而父namespace 是可以看到子 namespace 的进程,那么在虚拟机里,我们是可以看到上诉所有容器对应的进程。

我这里启动了一个容器,并指定 pid namespace 是宿主机(虚拟机)的。可以看到 pod 容器进程,k8s apiServer 进程,以及两个 docker daemon 进程(一个是虚拟机里的,一个是 minikube 容器里的)。

image-20240920215032917

解决方案

从上诉可知,运行在 minikube 里,pod 内部的进程,在虚拟机里是能看到的。那我们最开始的问题“如何 debug minikube 里的 golang 容器?”,就变成了“如何 debug 虚拟机里的 golang 进程?”。

如何在虚拟机里运行 golang 的 debug 程序 delve 呢?很简单,启动一个包含 delve 程序,同时设置 host pid namespace 的 docker 容器即可。

这里以调试 open kruise 为例

准备可调试的 kruise 镜像

一般 golang 程序二进制都是进行编译优化的,例如内联优化,这会导致实际运行的代码行数和本地代码对不上。

重新构建二进制

go build -gcflags="all=-N -l" -o bin/manager main.go 

准备 Dockerfile

FROM openkruise/kruise-manager:test
COPY bin/manager .

构建镜像

docker build -t openkruise/kruise-manager:test -f Dockerfile .

替换 minikube 里的镜像

minikube loadimage openkruise/kruise-manager:test

执行前需要将这个镜像的容器删掉。

运行 kruise

delve attach 待调试的 golang 进程

首先找到 kruise manager 的 pid。

image-20240921160034883

然后使用 delve 容器进行 attach。

image-20240921160143117

goland 连接

最后使用 goland 的 remote debug 连接 delve 即可。

以上方法同样适用于调试 k8s 控制面,调试 containerd 等 golang 程序。

作者:Yuyy
博客:https://yuyy.info
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇