美文网首页Golang语言社区
如何在docker中进行gdb调试

如何在docker中进行gdb调试

作者: _张晓龙_ | 来源:发表于2017-02-18 23:13 被阅读2529次

    环境准备

    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 bash
    root@27b0644624a9:/# 
    

    查看ubuntu版本:

    root@27b0644624a9:/# cat /etc/issue
    Ubuntu 16.04.1 LTS \n \l
    

    因为容器里还没有vi等基础软件,所以在虚机上编辑sources.list:

    deb http://mirrors.zte.com.cn/ubuntu/ xenial main multiverse restricted universe
    deb http://mirrors.zte.com.cn/ubuntu/ xenial-backports main multiverse restricted universe
    deb http://mirrors.zte.com.cn/ubuntu/ xenial-proposed main multiverse restricted universe
    deb http://mirrors.zte.com.cn/ubuntu/ xenial-security main multiverse restricted universe
    deb http://mirrors.zte.com.cn/ubuntu/ xenial-updates main multiverse restricted universe
    deb-src http://mirrors.zte.com.cn/ubuntu/ xenial main multiverse restricted universe
    deb-src http://mirrors.zte.com.cn/ubuntu/ xenial-backports main multiverse restricted universe
    deb-src http://mirrors.zte.com.cn/ubuntu/ xenial-proposed main multiverse restricted universe
    deb-src http://mirrors.zte.com.cn/ubuntu/ xenial-security main multiverse restricted universe
    deb-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 --version
    Python 3.5.2
    

    安装gdb:

    root@27b0644624a9:/# apt-get install gdb
    

    验证gdb是否可以run:

    root@27b0644624a9:/# gdb
    GNU gdb (Ubuntu 7.11.1-0ubuntu1~16.04) 7.11.1
    Copyright (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:gdb
    
    COPY ./libdpdk.so /lib/
    COPY ./Benchmark /Benchmark
    
    ENTRYPOINT ["/Benchmark"]
    
    

    制作镜像:

    $ docker build -t ubuntu-gdb:test .
    $ docker images
    REPOSITORY          TAG                 IMAGE ID            CREATED              SIZE
    ubuntu-gdb          test                10f840213452        About a minute ago   294 MB
    

    run image

    $ docker run -it --rm ubuntu-gdb:test bash
    is dpdk 0
    self ip is 0
    self port is 10008
    socket fd is 3
    msgReceive: now begin receive msg!
    

    查看容器Id:

    $ docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED              STATUS              PORTS               NAMES
    fd97fcd35a67        ubuntu-gdb:test     "/Benchmark bash"   About a minute ago   Up About a minute                       priceless_bell
    

    进入容器:

    $ docker exec -it fd bash
    root@fd97fcd35a67:/#
    

    gdb debug

    查看进程号:

    root@fd97fcd35a67:/# ps aux
    USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root         1 46.7  0.0  33016  1964 ?        Ssl+ 10:00   7:17 /Benchmark bash
    root         7  0.0  0.0  18244  3340 ?        Ss   10:08   0:00 bash
    root        18  0.0  0.0  34424  2912 ?        R+   10:16   0:00 ps aux
    

    查看该容器对应的Pid:

    $ docker inspect -f {{.State.Pid}} fd
    15099
    
    

    先输入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.1
    Copyright (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调试方法是一个程序员的基本技能之一。

    相关文章

      网友评论

        本文标题: 如何在docker中进行gdb调试

        本文链接:https://www.haomeiwen.com/subject/ogedwttx.html