docker容器下对运行中python进程调试踩坑记录(mgaic亲踩)

背景

线上的项目是使用python3.6.15写的, 跑在docker下

问题

某个进程执行巨慢,通过日志定位到了 if else, 但是if下的代码有日志, else 处并没有打日志, 所以想看看else 处到底发生了什么.

问题解决

尝试方案一. gdb 调试.

安装 gdb

1
2
3
4
5
6
# 没权限记录加sudo
apt upgrade
apt update
apt install gdb
apt install python3-dbg
gdb python pid

gdb 无法附加, 可能是安全策略导致的.

尝试 echo 0 /proc/sys/kernel/yama/ptrace_scope
但报错 只读文件系统.
一番搜索后, 发现可以在进入容器命令中加个参数即可解决.

1
docker exec --privileged -ti ebbed4cb3xxxx bash

解决后再次附加进程, 结果如下

img_1.png

一番搜索后猜测是原因可能是 原进程是root用户启动的,或者该进程是root启动的. 暂时先忽略这个报错.

看看 bt 命令 打印一下堆栈

img_1.png

解释型语言, 这个堆栈,并不是我理想的样子.

随即尝试方案二, 真香.

同样需要安装 gdb、python3-dbg, 上面我们已经安装过了.

安装主次主角 pyrasite

1
pip install pyrasite

同样需要 echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope, 如果是容器下, 只需要 docker exec 时候, 加上 –privileged 命令就好.

然后执行 pyrasite-shell pid 附加到你要调试的进程中

1
$ pyrasite-shell your_need_attach_process_id

img_1.png

可以看到已经成功附加到了原进程中, 并且打印Pid, 已经是原进程的pid.

img_1.png
查看一下本地变量还有全局变量,打印一下本地变量 i的值,发现是变化的. 如果你的程序中有 redis_conn 这些,也应该可以执行 redis_conn.exist() 等复杂操作.

调试完成后, Use quit() or Ctrl-D (i.e. EOF) to exit, 这种退出方式不会影响原进程, 原进程健壮地活着. 手动狗头.jpg

done!!!