容器很是适合封装软件,可是有时一味地改造容器镜像以使其尽量小时,您可能走得太远。咱们须要在“简洁”的镜像和没法调试的镜像之间找到很好的平衡。docker
看到人们调试正在运行的容器的正常方法是docker exec -it $ CONTAINER sh并根据须要在容器中安装调试工具。可是,若是您的容器没有/ bin / sh怎么办?若是没有包管理器怎么办?您可使用docker cp将实用程序复制到容器中,而后将exec复制到正在运行的容器中,但这也很麻烦。shell
所以,一个朋友最近没有询问如何从容器中进行调试,而是询问如何从其余容器中进行调试。我没有那么聪明,因此我在网上问了不少聪明的人,并获得了很好的答复。bash
咱们建立一个只有caddy的精简容器。网络
首先下载/提取caddy二进制文件curl
$: curl https://getcaddy.com | bash -s personal && mv /usr/local/bin/caddy .
而后建立一个Dockerfile将二进制文件复制到临时容器中。工具
FROM scratch ADD caddy /
构建容器并运行caddyui
$: docker build -t caddy . <output trimmed>
如今运行这个容器url
$: docker run -d --name caddy -p 2015:2015 caddy /caddy
如今caddy正在运行发布端口2015(目前提供404页面,由于没有内容,但没有关系)。您如何调试容器?caddy并无bug,这不是您所须要的。 :)但出于假设的缘由。调试
许多人建议使用--link,但这只会将容器放在同一网络上。不是相同的名称空间,而是在同一虚拟网络上彼此链接。code
$: docker run -it --rm --link caddy:caddy alpine sh / # ping caddy -c 1 PING caddy (172.30.238.2): 56 data bytes 64 bytes from 172.30.238.2: seq=0 ttl=64 time=0.075 ms / # ps aux PID USER TIME COMMAND 1 root 0:00 sh 8 root 0:00 ps aux
其余人建议使用--volumes-from,但这不能使您将工具安装到现有的运行容器中,除非该运行容器正在导出卷而且该卷已经在$ PATH中。
相反,咱们将使用所需的全部工具(在本例中为strace)构建一个单独的容器,并在与原始容器相同的pid和网络名称空间中运行它。
首先使用strace建立一个调试容器
FROM alpine RUN apk update && apk add strace CMD ["strace", "-p", "1"]
构建容器
$: docker build -t strace . <output trimmed>
如今,在相同的pid和网络名称空间中运行strace容器。
$: docker run -t --pid=container:caddy \ --net=container:caddy \ --cap-add sys_admin \ --cap-add sys_ptrace \ strace strace: Process 1 attached futex(0xd72e90, FUTEX_WAIT, 0, NULL
附加的strace到caddy进程,并在执行时跟随它。
很好,但咱们也可使用远程容器的根文件系统(不是不少)。此次,咱们将使用alpine 镜像并再次在相同的pid和网络名称空间中启动一个shell。
$: docker run -it --pid=container:caddy \ --net=container:caddy \ --cap-add sys_admin \ alpine sh
咱们如今能够看到caddy 运行以下:
/ # ps aux PID USER TIME COMMAND 1 root 0:00 /caddy 13 root 0:00 strace -p 1 34 root 0:00 sh 40 root 0:00 ps aux
caddy容器文件系统位于/ proc / 1 / root中
/ # ls -l /proc/1/root/caddy -rwxr-xr-x 1 root root 16099400 Jan 24 15:30 /proc/1/root/caddy
将此容器附加到原始容器后,咱们能够进行更多调试。您仍然能够调试网络,但请确保使用localhost,由于新的sh进程正在同一网络名称空间中运行
/ # apk update && apk add curl lsof / # curl localhost:2015 404 Not Found / # lsof -i TCP COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME caddy 1 root 4u IPv6 330044347 0t0 TCP *:2015 (LISTEN)
您全部的标准调试工具都应在第二个容器中运行,而不会污染原始容器。若是遇到错误,请确保检查内核权限(注意strace须要如何--cap-add sys_ptrace但sh容器仅须要sys_admin)
这显然对于go容器或您只须要在不更改容器自己的状况下将一些额外的调试工具引入的任何其余容器颇有用。