背景
当一个Python程序运行停住或陷入死循环,遇到这种情况可以使用GDB命令attach到进程上,查看Python堆栈信息然后进行分析。但是当在Docker容器中运行Python程序时,因为Docker的seccomp禁用了系统ptrace,所以不能直接使用GDB调试,这时我们要借助nsenter工具进入容器命令空间再运行GDB调试。
什么是nsenter
nsenter的一个最典型的用途就是进入容器的网络命令空间。相当多的容器为了轻量级,不包含较为基础的命令,比如说 ip address,ping,telnet,ss,tcpdump等等命令,这时可以使用nsenter命令进入该容器的网络命名空间,使用宿主机的命令调试容器网络。
在宿主机上安装nsenter
yum install util-linux
nsenter用法
nsenter [options] [program [arguments]]
options:
-t, --target pid:指定被进入命名空间的目标进程的pid
-m, --mount[=file]:进入mount命令空间。如果指定了file,则进入file的命令空间
-u, --uts[=file]:进入uts命令空间。如果指定了file,则进入file的命令空间
-i, --ipc[=file]:进入ipc命令空间。如果指定了file,则进入file的命令空间
-n, --net[=file]:进入net命令空间。如果指定了file,则进入file的命令空间
-p, --pid[=file]:进入pid命令空间。如果指定了file,则进入file的命令空间
-U, --user[=file]:进入user命令空间。如果指定了file,则进入file的命令空间
-G, --setgid gid:设置运行程序的gid
-S, --setuid uid:设置运行程序的uid
-r, --root[=directory]:设置根目录
-w, --wd[=directory]:设置工作目录
在容器中安装gdb
yum install gdb
查找容器的PID
docker inspect -f '{{.State.Pid}}' <容器id>
进入namespace使用gdb调试
sudo nsenter -t 14734 -m -p gdb
(gdb) set auto-load safe-path /
(gdb) file /home/okp/.pyenv/versions/3.6.5/bin/python3.6
Reading symbols from /home/okp/.pyenv/versions/3.6.5/bin/python3.6...done.
(gdb) attach 3866
gdb调试常用命令
bt # 当前C调用栈
py-bt # 当前Python调用栈
py-bt-full # 输出Python调用栈
py-up # 上一帧(py级别的帧)
py-down # 下一帧(py级别的帧)
py-list # 当前py代码位置
py-locals # 输出locals变量
py-print <var> # 输出指定变量
info thread # 线程信息
thread <id> # 切换到某个线程
thread apply all py-list # 查看所有线程的python代码位置
ctrl-c # 中断