cdebug 容器调试界的瑞士军刀,5 个超能力让你成为调试大师

Posted by Mike on 2024-08-06

你是否曾经遇到过这样的情况:

  • 需要调试一个没有 Shell 的容器?
  • 或者想访问容器内部未公开的端口?
  • 也许你只是想方便地将容器文件系统导出到本地?

如果有,那么 cdebug 就是为你量身打造的工具!

什么是 cdebug?

cdebug 是一个功能强大的容器调试工具,它就像是容器世界的瑞士军刀。无论你是在处理 Docker 容器、Kubernetes Pod,还是其他类型的容器,cdebug 都能给你提供所需的工具和便利。

想象一下,你有一个神奇的工具箱,里面装满了各种调试工具。现在,你可以随时随地打开这个工具箱,解决容器中遇到的各种问题。这就是 cdebug!

cdebug 能做什么?

  1. 调试 “无 Shell” 容器: 即使容器内没有 Shell 或调试工具,你也能轻松进入并调试。
  2. 端口魔术师: 将未公开的端口或 localhost 端口转发到你的主机系统。
  3. 反向通道: 将主机系统的端点暴露给容器和 Kubernetes 网络。
  4. 文件系统导出专家: 轻松将镜像或容器的文件系统导出到本地文件夹。
  5. 更多惊喜等你发现…

安装 cdebug: 简单得不能再简单!

cdebug 是一个静态链接的 Go 二进制文件,安装起来就像变魔术一样简单:

1
2
3
4
5
6
7
# 对于Linux amd64系统
GOOS=linux
GOARCH=amd64

$ curl -Ls https://github.com/iximiuz/cdebug/releases/latest/download/cdebug_${GOOS}_${GOARCH}.tar.gz | tar xvz

$ sudo mv cdebug /usr/local/bin

如果你是 Homebrew 用户,那就更简单了:

1
$ brew install cdebug

目前支持的系统:

  • linux/amd64
  • darwin/amd64
  • darwin/arm64

cdebug 使用指南: 让调试变得有趣!

1. cdebug exec: 你的容器,你做主

想在一个 “瘦身” 容器中启动一个交互式 Shell? 没问题!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 在 Docker 容器中启动一个 busybox:musl 的 shell
$ cdebug exec -it mycontainer
$ cdebug exec -it docker://mycontainer

# 在容器中执行命令
$ cdebug exec mycontainer cat /etc/os-release

# 使用不同的调试工具包镜像
$ cdebug exec -it --image=alpine mycontainer

# 使用 nixery.dev 镜像,按需定制你的工具
$ cdebug exec -it --image=nixery.dev/shell/vim/ps/tshark mycontainer

# 在 containerd 容器中执行
$ cdebug exec -it containerd://mycontainer ...
$ cdebug exec --namespace myns -it containerd://mycontainer ...

# 使用 nerdctl 在容器中执行
$ cdebug exec -it nerdctl://mycontainer ...

# 在 Kubernetes pod 中启动 shell
$ cdebug exec -it pod/mypod
$ cdebug exec -it k8s://mypod
$ cdebug exec --namespace=myns -it pod/mypod

# 在 Kubernetes pod 的容器中启动 shell
$ cdebug exec -it pod/mypod/mycontainer

cdebug exec 就像是 docker execkubectl debug 的完美结合。它能让你在目标容器中启动一个调试用的 “伴侣” 容器,感觉就像是在使用 docker exec,但功能更强大:

  • 调试器的根文件系统就是目标容器的根文件系统。
  • 目标容器不会被重新创建或重启。
  • 无需额外的卷或复制调试工具。
  • 调试工具在目标容器中随时可用。

2. cdebug port-forward: 端口转发从未如此简单

想要访问容器内部的 “隐藏” 端口? 或者将本地端口暴露给容器? cdebug port-forward 助你轻松搞定!

1
2
3
4
5
6
7
8
9
10
11
# 将容器的 80 端口发布到主机的随机端口
$ cdebug port-forward <target> -L 80

# 将容器的 localhost:5432 暴露到主机系统
$ cdebug port-forward <target> -L 127.0.0.1:5432

# 通过目标容器将本地流量代理到远程主机
$ cdebug port-forward <target> -L <LOCAL_HOST>:<LOCAL_PORT>:<REMOTE_HOST>:<REMOTE_PORT>

# 将 Kubernetes 服务暴露到主机系统
$ cdebug port-forward <target> -L 8888:my.svc.cluster.local:443

3. 实战示例

示例 1: 给 “无 Shell” 容器一个温暖的家

想象你有一个基于 DistrolessNode.js 容器,没有 Shell,没有调试工具,简直就是一个 “光秃秃” 的容器。别担心,cdebug 来救场!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 首先,启动一个目标容器
$ $ docker run -d --rm \
--name my-distroless gcr.io/distroless/nodejs \
-e 'setTimeout(() => console.log("Done"), 99999999)'

# 然后,使用 cdebug 进入容器
$ cdebug exec -it my-distroless

# 瞧!你现在有了一个交互式 shell
/ $# ls -lah
total 60K
drwxr-xr-x 1 root root 4.0K Oct 17 23:49 .
drwxr-xr-x 1 root root 4.0K Oct 17 23:49 ..
👉 lrwxrwxrwx 1 root root 18 Oct 17 23:49 .cdebug-c153d669 -> /proc/55/root/bin/
-rwxr-xr-x 1 root root 0 Oct 17 19:49 .dockerenv
drwxr-xr-x 2 root root 4.0K Jan 1 1970 bin
drwxr-xr-x 2 root root 4.0K Jan 1 1970 boot
drwxr-xr-x 5 root root 340 Oct 17 19:49 dev
drwxr-xr-x 1 root root 4.0K Oct 17 19:49 etc
drwxr-xr-x 3 nonroot nonroot 4.0K Jan 1 1970 home
drwxr-xr-x 1 root root 4.0K Jan 1 1970 lib
drwxr-xr-x 2 root root 4.0K Jan 1 1970 lib64
drwxr-xr-x 5 root root 4.0K Jan 1 1970 nodejs
...

示例 2: 给你的容器加上超能力

有时候,busybox 提供的工具可能不够用。没关系,我们可以借助 nixery 项目的力量,给容器加上任何你想要的工具!

1
2
3
4
5
# 想要一个带有 vim 的 shell? 没问题!
$ cdebug exec -it --image nixery.dev/shell/vim my-distroless

# 需要更多高级工具?来吧!
$ cdebug exec -it --image nixery.dev/shell/ps/findutils/tshark my-distroless

示例 3: 调试 containerd 容器(无需 Docker)

首先,启动目标容器:

1
2
$ sudo ctr image pull docker.io/library/nginx:latest
$ sudo ctr run -d docker.io/library/nginx:latest nginx-1

使用简单的 cdebug exec 在目标容器中运行交互式 Shell

1
2
$ sudo cdebug exec -it containerd://nginx-1
/ $# wget -O- 127.0.0.1

使用 cdebug exec --image nixery.dev/shell/vim 在目标容器中运行 VIM

1
$ sudo cdebug exec -it --rm --image nixery.dev/shell/vim containerd://nginx-1

示例 4: 调试 nerdctl 容器(无需 Docker)

使用 nerdctl 启动容器:

1
2
$ sudo $(which nerdctl) run -d --name nginx-1 nginx
9f8763d82259a6e3e747df83d0ce8b7ee3d33d94269a72cd04e0e3862a3abc5f

使用 nerdctl:// 模式和目标名称运行调试器:

1
$ sudo cdebug exec -it --rm nerdctl://nginx-1

或者使用 containerd:// 模式在上述容器中运行调试会话:

1
$ sudo cdebug exec -it --rm containerd://9f876

示例 5: Kubernetes Pod 调试大师

在 Kubernetes 中调试 Pod 不再是噩梦:

首先,创建一个 Pod:

1
2
3
4
5
6
7
8
$ kubectl run --image nginx:alpine nginx-1
$ kubectl run --image=nginx:alpine nginx-1 \
--overrides='{ "apiVersion": "v1", "spec": { "containers": [{ "name": "app", "image": "nginx:alpine" }] } }'
pod/nginx-1 created

$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-1 1/1 Running 0 5s

然后,使用 cdebug 进入Pod:

1
2
3
4
5
6
7
8
9
10
11
12
$ cdebug exec -it pod/nginx-1

Debugger container name: cdebug-3023d11d
Starting debugger container...
Waiting for debugger container...
Attaching to debugger container...
If you don't see a command prompt, try pressing enter.
/ # ps auxf
PID USER TIME COMMAND
1 root 0:00 sh /.cdebug-entrypoint.sh
10 root 0:00 /bin/sh -i
11 root 0:00 ps auxf

想要直接进入特定的容器? 也是没问题的!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cdebug exec -it pod/nginx-1/app

cdebug exec -it pod/nginx-1/app
Debugger container name: cdebug-b44ca485
Starting debugger container...
Waiting for debugger container...
Attaching to debugger container...
If you don't see a command prompt, try pressing enter.
/ # ps auxf
PID USER TIME COMMAND
1 root 0:00 nginx: master process nginx -g daemon off;
30 nginx 0:00 nginx: worker process
...
41 nginx 0:00 nginx: worker process
42 root 0:00 sh /.cdebug-entrypoint.sh
51 root 0:00 /bin/ash -i
52 root 0:00 ps auxf

示例 6: 端口转发魔术

6.1 忘记发布容器端口了? cdebug 来帮忙:
1
2
3
4
5
6
7
8
# 启动一个nginx容器,不暴露任何端口
$ docker run -d --name nginx-1 nginx:1.23

# 使用 cdebug 将本地 8080 端口转发到容器的 80 端口
$ cdebug port-forward nginx-1 -L 8080:80

# 现在你可以访问 nginx了
$ curl localhost:8080
6.2 将本地端口暴露给容器:

启动仅监听本地主机的容器化服务:

1
$ docker run -d --name svc-1 python:3-alpine python3 -m 'http.server' -b 127.0.0.1 8888

利用上述服务:

1
2
3
4
5
6
7
8
9
10
11
12
$ cdebug port-forward svc-1 -L 127.0.0.1:8888
Pulling forwarder image...
latest: Pulling from shell/socat
Digest: sha256:b43b6cf8d22615616b13c744b8ff525f5f6c0ca6c11b37fa3832a951ebb3c20c
Status: Image is up to date for nixery.dev/shell/socat:latest
Forwarding 127.0.0.1:49176 to 127.0.0.1:8888 through 172.17.0.4:34128

$ curl localhost:49176
<!DOCTYPE HTML>
<html lang="en">
<head>
...

总结: 你的容器调试新伙伴

cdebug 不仅仅是一个工具,它是你在容器世界冒险时的得力助手。无论你是在调试一个顽固的容器,还是需要快速访问一个隐藏的服务,cdebug 都能帮你搞定。

记住,在容器的海洋中,cdebug 就是你的瑞士军刀。所以,下次当你面对一个看似不可能的容器调试任务时,别忘了问问自己:“我的 cdebug 在哪里?”

祝你调试愉快,容器世界的冒险家!