如何从单独的容器调试运行中的Docker容器

42次阅读

共计 2074 个字符,预计需要花费 6 分钟才能阅读完成。

容器非常适合封装软件,但是有时一味地改造容器镜像以使其尽可能小时,您可能走得太远。我们需要在“简洁”的镜像和无法调试的镜像之间找到很好的平衡。

看到人们调试正在运行的容器的正常方法是 docker exec -it $ CONTAINER sh 并根据需要在容器中安装调试工具。但是,如果您的容器没有 / bin / sh 怎么办?如果没有包管理器怎么办?您可以使用 docker cp 将实用程序复制到容器中,然后将 exec 复制到正在运行的容器中,但这也很麻烦。

因此,一个朋友最近没有询问如何从容器中进行调试,而是询问如何从其他容器中进行调试。我没有那么聪明,所以我在网上问了很多聪明的人,并得到了很好的答复。

我们创建一个只有 caddy 的精简容器。

首先下载 / 提取 caddy 二进制文件

$: curl https://getcaddy.com | bash -s personal && mv /usr/local/bin/caddy .

然后创建一个 Dockerfile 将二进制文件复制到临时容器中。

FROM scratch
ADD caddy /

构建容器并运行 caddy

$: docker build -t caddy .
<output trimmed>

现在运行这个容器

$: docker run -d --name caddy -p 2015:2015 caddy /caddy

现在 caddy 正在运行发布端口 2015(目前提供 404 页面,因为没有内容,但没有关系)。您如何调试容器?caddy 并没有 bug,这不是您所需要的。:) 但出于假设的原因。

许多人建议使用 –link,但这只会将容器放在同一网络上。不是相同的名称空间,而是在同一虚拟网络上彼此连接。

$: 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 容器或您只需要在不更改容器本身的情况下将一些额外的调试工具引入的任何其他容器很有用。

正文完
 0