美文网首页
Docker容器调试应用程序

Docker容器调试应用程序

作者: 汤尼房 | 来源:发表于2018-07-14 10:53 被阅读403次
    引言

    因为Docker技术的火热,因此在工作中我们经常会以容器的方式来运行一个应用。每当容器无法成功运行或者想要对容器中的应用参数、应用配置以及应用启动进行深入研究时,当然希望能够像在宿主机上调试程序一样在容器中调试应用。容器的本质包括应用与应用运行所依赖的环境, 因此首先需要创建一个空壳容器(没有运行应用的应用容器),然后进入容器中调试应用。此处的空壳容器提供了应用运行所需的环境,进而可方便的在其中调试应用。实践环境:Centos7.2+Docker1.12.6。

    容器启动命令介绍

    比较规范的镜像的Dockerfile中通常会有ENTRYPOINT与CMD的定义(Docker官方推荐这样做)。因此容器的启动命令则为ENTRYPOINT所对应的脚本或可执行程序加上CMD中定义的内容。比如elasticsearch的Dockerfile定义的ENTRYPOINT与CMD分别为:ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["elasticsearch"],则创建的容器的启动命令为:/docker-entrypoint.sh elasticsearch;mysql的Dockerfile:ENTRYPOINT ["docker-entrypoint.sh"] CMD ["mysqld"],则创建的容器的启动命令为:/docker-entrypoint.sh mysqld。所以想要知道一个容器的启动命令需要首先了解其镜像的Dockerfile中ENTRYPOINT与CMD的定义。如何查看一个镜像的ENTRYPONT与CMD的值呢?一般采用如下两种方式:

    1. 查看镜像的Dockerfile

      比如查看zookeeper的Dockerfile,先在Docker仓库中找到zookeeper镜像,然后找到特定版本的Dockerfile
    ENTRYPOINT ["/docker-entrypoint.sh"]
    CMD ["zkServer.sh", "start-foreground"]
    
    1. 通过 docker history 或 docker inspect 命令查看
      比如查看prom/prometheus:v1.8.0镜像的ENTRYPOINT与CMD信息
      docker history --no-trunc prom/prometheus:v1.8.0 (--no-trunc表示完整输出)

      上图仅展示一部分内容,可知prom/prometheus:v1.8.0镜像的ENTRYPOINT为:/bin/prometheus,CMD为:
      "-config.file=/etc/prometheus/prometheus.yml"
      "-storage.local.path=/prometheus"
      "-web.console.libraries=/usr/share/prometheus/console_libraries"
      "-web.console.templates=/usr/share/prometheus/consoles"

      docker inspect prom/prometheus:v1.8.0

      上图仅展示一部分内容,也可知prom/prometheus:v1.8.0镜像的ENTRYPOINT为:/bin/prometheus,
      CMD为:"-config.file=/etc/prometheus/prometheus.yml",
      "-storage.local.path=/prometheus",
      "-web.console.libraries=/usr/share/prometheus/console_libraries",
      "-web.console.templates=/usr/share/prometheus/consoles"

    上述第一种方式适用于比较规范的镜像,这类镜像通常会提供清晰、具体的Dockerfile。第二种方式适用于各种镜像,尽管是不规范的镜像。通过history、inspect两个命令的任一个均可快速、方便的查看镜像的ENTRYPOINT与CMD的值。

    不同类型镜像的调试举例
    如果不作额外的设置,容器的启动命令则是镜像的ENTRYPOINT+CMD的方式。比如:

    若要调试容器中的应用程序,则需额外的设置实现。docker run命令提供的--entrypoint参数能够覆盖Dockerfile中默认定义的ENTRYPOINT;docker run [OPTIONS] IMAGE [COMMAND] [ARG...]的COMMAND能够替换Dockerfile中定义的CMD。通过上面的示例可以发现,有的镜像的Dockerfile中ENTRYPOINT值为:/docker-entrypoint.sh,CMD为应用的可执行程序;有的镜像的Dockerfile中ENTRYPOINT值为应用的可执行程序,CMD为可执行程序的参数。因此针对不同的镜像想要创建空壳容器其方式是不同的。

    1. Dockerfile的ENTRYPOINT为/docker-entrypoint.sh,CMD为应用的可执行程序
      通常比较正式的官方镜像均会提供docker-entrypoint.sh脚本作为ENTRYPOINT,docker-entrypoint.sh脚本一般能够接收类似bash、sh的参数,因此对于这类镜像可以指定容器的COMMAND覆盖应用的二进制程序创建空壳容器。这里以elasticsearch:5.0.2镜像为例

      创建空壳容器es:
      docker run -itd --name es --network host elasticsearch:5.0.2 bash (alpine系统指定sh,非alpine系统可以指定bash or sh)

      查看空壳容器es中运行的进程:

      可见,es容器中运行的进程变为bash,并不是elasticsearch应用;此时es就为空壳容器,进入es容器调试elasticsearch应用就像在宿主机上调试程序

      进入es容器: es容器中调试elasticsearch应用程序: 运行elasticsearch应用程序:
    2. Dockerfile的ENTRYPOINT为应用的可执行程序,CMD为可执行程序的参数
      这类镜像不能再简单的通过覆盖镜像的CMD来创建空壳容器了,因为docker run 的COMMAND是作为ENTRYPOINT指定的二进制程序的参数传入的,所以简单的指定COMMAND为bash或sh多数情况下是不行的,最好的方式是通过docker run的--entrypoint参数来覆盖镜像中指定的二进制可执行程序,使得创建的容器其内部的进程为entrypoint参数指定的bash or sh。这里以google/cadvisor:v0.27.2镜像(ENTRYPOINT: /usr/bin/cadvisor -logtostderr, CMD: null)为例

      创建空壳容器cadvisor:
      docker run -itd --name cadvisor --network host --entrypoint sh -v /var/lib/docker:/var/lib/docker:ro google/cadvisor:v0.27.2

      查看cadvisor容器的进程: 进入cadvisor容器内调试应用: 运行cadvisor应用程序: 通过指定docker run的COMMAND为sh看能否成功创建空壳容器:

      可见,这种方式不能成功创建空壳容器

      上面是对两种类型的ENTRYPOINT创建空壳容器的举例说明,其实也可以对ENTRYPOINT不加以区分,即均通过docker run 的--entrypoint参数覆盖镜像中的ENTRYPOINT创建空壳容器。比如示例1中的elasticsearch:5.0.2镜像,指定--entrypoint bash创建空壳容器:
    总结

    容器其实是应用与应用运行所依赖的环境,创建空壳容器即提供了应用所需要的环境,进入此环境中可以调试应用,可以验证应用的各个参数,同样更可以像在宿主机中运行程序一样在此环境中运行应用,区别仅是容器与宿主机的两个环境。上面是对如何在容器中调试应用程序做的一些记录,希望与大家一起讨论、交流,一起学习。

    相关文章

      网友评论

          本文标题:Docker容器调试应用程序

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