這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
環境準備
install nsenter
nsenter 工具在 util-linux 包2.23版本後包含。 nsenter 可以訪問另一個進程的名字空間。nsenter 要正常工作需要有 root 許可權。 很不幸,Ubuntu 14.04 仍然使用的是 util-linux 2.20。
$ cd /tmp; curl https://www.kernel.org/pub/linux/utils/util-linux/v2.24/util-linux-2.24.tar.gz | tar -zxf-; cd util-linux-2.24;$ ./configure --without-ncurses$ make nsenter && sudo cp nsenter /usr/local/bin
pull ubuntu image
$ docker pull ubuntu
ubuntu:gdb鏡像製作
sources.list
啟動ubuntu鏡像的容器
$ docker run -it --rm ubuntu bashroot@27b0644624a9:/#
查看ubuntu版本:
root@27b0644624a9:/# cat /etc/issueUbuntu 16.04.1 LTS \n \l
因為容器裡還沒有vi等基礎軟體,所以在虛機上編輯sources.list:
deb http://mirrors.zte.com.cn/ubuntu/ xenial main multiverse restricted universedeb http://mirrors.zte.com.cn/ubuntu/ xenial-backports main multiverse restricted universedeb http://mirrors.zte.com.cn/ubuntu/ xenial-proposed main multiverse restricted universedeb http://mirrors.zte.com.cn/ubuntu/ xenial-security main multiverse restricted universedeb http://mirrors.zte.com.cn/ubuntu/ xenial-updates main multiverse restricted universedeb-src http://mirrors.zte.com.cn/ubuntu/ xenial main multiverse restricted universedeb-src http://mirrors.zte.com.cn/ubuntu/ xenial-backports main multiverse restricted universedeb-src http://mirrors.zte.com.cn/ubuntu/ xenial-proposed main multiverse restricted universedeb-src http://mirrors.zte.com.cn/ubuntu/ xenial-security main multiverse restricted universedeb-src http://mirrors.zte.com.cn/ubuntu/ xenial-updates main multiverse restricted universe
拷貝sources.list到容器的/etc/apt/目錄下:
$ docker cp ./sources.list 27:/etc/apt/
install some software for gdb
更新源的索引:
root@27b0644624a9:/# apt-get update
gdb依賴python的3.x版本。在ubuntu14.04中,gdb依賴的python版本是3.4,那麼在ubuntu16.04中,gdb依賴的python版本應該不低於3.4。
搜尋一下python3.x版本的程式名:
root@27b0644624a9:/# apt-cache search python
安裝python:
root@27b0644624a9:/# apt-get install python3
查詢python版本號碼,符合預期:
root@27b0644624a9:/# python3 --versionPython 3.5.2
安裝gdb:
root@27b0644624a9:/# apt-get install gdb
驗證gdb是否可以run:
root@27b0644624a9:/# gdbGNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1Copyright (C) 2016 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word".(gdb)
vi是很基礎的編輯工具,也建議安裝:
root@27b0644624a9:/# apt-get install vim
save ubuntu:gdb image
$ docker commit 27 ubuntu:gdb$ docker save -o ubuntu-gdb.tar ubuntu:gdb
ubuntu:gdb鏡像驗證
Dockerfile
Benchmark是筆者用C++開發的一個關於網路效能的測試載入器,它同時支援linux socket和dpdk socket,所以對dpdk的動態庫有依賴。
Dockerfile檔案描述:
FROM ubuntu:gdbCOPY ./libdpdk.so /lib/COPY ./Benchmark /BenchmarkENTRYPOINT ["/Benchmark"]
製作鏡像:
$ docker build -t ubuntu-gdb:test .$ docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEubuntu-gdb test 10f840213452 About a minute ago 294 MB
run image
$ docker run -it --rm ubuntu-gdb:test bashis dpdk 0self ip is 0self port is 10008socket fd is 3msgReceive: now begin receive msg!
查看容器Id:
$ docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESfd97fcd35a67 ubuntu-gdb:test "/Benchmark bash" About a minute ago Up About a minute priceless_bell
進入容器:
$ docker exec -it fd bashroot@fd97fcd35a67:/#
gdb debug
查看進程號:
root@fd97fcd35a67:/# ps auxUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMANDroot 1 46.7 0.0 33016 1964 ? Ssl+ 10:00 7:17 /Benchmark bashroot 7 0.0 0.0 18244 3340 ? Ss 10:08 0:00 bashroot 18 0.0 0.0 34424 2912 ? R+ 10:16 0:00 ps aux
查看該容器對應的Pid:
$ docker inspect -f {{.State.Pid}} fd15099
先輸入nsenter命令使gdb attach成功,然後再分別輸入info threads和bt命令確認響應沒毛病:
$ sudo nsenter -t 15099 -m -p gdb -p 1[sudo] password for zte: GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1Copyright (C) 2016 Free Software Foundation, Inc.License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>This is free software: you are free to change and redistribute it.There is NO WARRANTY, to the extent permitted by law. Type "show copying"and "show warranty" for details.This GDB was configured as "x86_64-linux-gnu".Type "show configuration" for configuration details.For bug reporting instructions, please see:<http://www.gnu.org/software/gdb/bugs/>.Find the GDB manual and other documentation resources online at:<http://www.gnu.org/software/gdb/documentation/>.For help, type "help".Type "apropos word" to search for commands related to "word".Attaching to process 1[New LWP 6][Thread debugging using libthread_db enabled]Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".0x00007fc7f369298d in pthread_join () from /lib/x86_64-linux-gnu/libpthread.so.0(gdb) info threads Id Target Id Frame* 1 Thread 0x7fc7f41b1940 (LWP 1) "Benchmark" 0x00007fc7f369298d in pthread_join () from /lib/x86_64-linux-gnu/libpthread.so.0 2 Thread 0x7fc7f281b700 (LWP 6) "Benchmark" 0x00007fc7f369a8f3 in recvfrom () from /lib/x86_64-linux-gnu/libpthread.so.0(gdb) bt#0 0x00007fc7f369298d in pthread_join () from /lib/x86_64-linux-gnu/libpthread.so.0#1 0x0000000000407e57 in main (argc=2, argv=0x7fffe3029a08) at /home/zte/gitlab/benchmark/src/Main.cpp:135(gdb)
應用情境
gdb調試一般是不得已的選擇。我們一般先是通過代碼走查和測試來找bug,其次是通過日誌分析找bug,最後的最後才是通過gdb找bug。話雖如此,但gdb調試仍然很重要,比如程式“卡死”等情境。
每個應用程式容器都依賴gdb並不是能在容器中進行gdb調試的唯一選擇。在有kubernetes叢集的系統中,gdb所在的容器可以在一個pod中掛一個,當出現“頑疾”時通過共用檔案系統來偵錯工具。
小結
本文以ubuntu系統為例,先介紹了環境準備,然後帶著讀者一起製作了ubuntu:gdb鏡像,最後以C++程式為例驗證了ubuntu:gdb鏡像的可用性。本文所講的對於docker的gdb調試方法具有一定的通用性,大家可以在其他的linux系統上如法炮製,同時支援gdb調試的語言都可以通過本文介紹的方法在docker中調試,比如Golang,它和C/C++的gdb調試稍有不同,具體請參考官方文檔《Debugging Go Code with GDB》。在虛擬化時代,掌握docker中的gdb調試方法是一個程式員的基本技能之一。