docker 调试

描述获取任何容器或镜像的 shell。这是使用 `docker exec` 进行调试的替代方案。
用法debug [OPTIONS] {CONTAINER|IMAGE}

描述

注意

Docker Debug 需要一个 Pro、Team 或 Business 订阅。 您必须 登录 才能使用此命令。

Docker Debug 是一个 CLI 命令,可帮助您遵循最佳实践,保持镜像小巧且安全。 借助 Docker Debug,即使镜像中仅包含运行应用程序所需的极简内容,您也可以对其进行调试。 它通过允许您创建和使用精简镜像或容器来实现这一点,这些镜像或容器通常因为所有工具都被移除而难以调试。 例如,虽然典型的调试方法(如 docker exec -it my-app bash)可能无法在精简容器上运行,但 docker debug 可以正常运行。

使用 docker debug,您可以进入任何容器或镜像的调试 shell,即使它们不包含 shell。 您不需要为了使用 Docker Debug 而修改镜像。 但是,使用 Docker Debug 仍然不会修改您的镜像。 Docker Debug 自带工具箱,您可以轻松自定义。 该工具箱预装了许多标准 Linux 工具,例如 vimnanohtopcurl。 使用内置的 install 命令添加 https://search.nixos.org/packages 上可用的其他工具。 Docker Debug 支持 bashfishzsh。 默认情况下,它会尝试自动检测您的 shell。

自定义内置工具:

  • install [tool1] [tool2]: 从以下地址添加 Nix 包: https://search.nixos.org/packages,参见 示例
  • uninstall [tool1] [tool2]: 卸载 Nix 软件包。
  • entrypoint: 打印、检查或运行入口点,参见 示例
  • builtins: 显示自定义内置工具。

注意

对于镜像和已停止的容器,退出 Shell 时所有更改都会被丢弃。 更改绝不会影响实际的镜像或容器。 当访问运行中或已暂停的容器时,所有文件系统更改对容器直接可见。 /nix 目录对实际的镜像或容器永远不可见。

选项

选项默认描述
--shellauto选择一个 shell。支持的: bash, fish, zsh, auto.
-c, --command计算指定的命令而不是启动交互式会话,请参见 示例
--host要连接的 Docker 守护进程套接字。例如:ssh://root@example.org, unix:///some/path/docker.sock,参见 示例

示例

调试没有 shell 的容器(精简容器)

hello-world 镜像非常简单,仅包含 /hello Binaries。 这是一个精简镜像的好例子。 没有其他工具,也没有 shell。

hello-world 镜像运行一个容器:

$ docker run --name my-app hello-world

容器立即退出。要在内部获取调试 shell,请运行:

$ docker debug my-app

调试 Shell 允许您检查文件系统:

docker > ls
dev  etc  hello  nix  proc  sys

文件 /hello 是运行容器时执行的Binaries。 您可以通过直接运行它来确认这一点:

docker > /hello

运行Binaries后,它会产生相同的输出。

调试 (slim) 镜像

您可以通过运行直接调试镜像:

$ docker debug hello-world
...
docker > ls
dev  etc  hello  nix  proc  sys

您甚至不需要拉取镜像,因为 docker debug 会像 docker run 命令一样自动完成此操作。

修改运行中容器的文件

Docker debug 让你可以在任何运行中的容器里修改文件。 The toolbox comes with vim and nano pre-installed.

运行一个 nginx 容器并更改默认值 index.html:

$ docker run -d --name web-app -p 8080:80 nginx
d3d6074d0ea901c96cac8e49e6dad21359616bef3dc0623b3c2dfa536c31dfdb

要确认 nginx 正在运行,请打开浏览器并访问 http://localhost:8080。 你应该能看到 nginx 的默认页面。 现在,使用 vim 进行修改:

vim /usr/share/nginx/html/index.html

将标题更改为 "Welcome to my app!" 并保存文件。 现在,在浏览器中重新加载页面,您应该会看到更新后的页面。

使用 install 命令管理您的工具箱

内置的 install 命令允许您从 https://search.nixos.org/packages 添加任何工具到工具箱中。 请记住,添加工具不会修改实际的镜像或容器。 工具只会添加到您的工具箱中。 运行 docker debug 然后安装 nmap

$ docker debug nginx
...
docker > install nmap
Tip: You can install any package available at: https://search.nixos.org/packages.
installing 'nmap-7.93'
these 2 paths will be fetched (5.58 MiB download, 26.27 MiB unpacked):
/nix/store/brqjf4i23fagizaq2gn4d6z0f406d0kg-lua-5.3.6
/nix/store/xqd17rhgmn6pg85a3g18yqxpcya6d06r-nmap-7.93
copying path '/nix/store/brqjf4i23fagizaq2gn4d6z0f406d0kg-lua-5.3.6' from 'https://cache.nixos.org'...
copying path '/nix/store/xqd17rhgmn6pg85a3g18yqxpcya6d06r-nmap-7.93' from 'https://cache.nixos.org'...
building '/nix/store/k8xw5wwarh8dc1dvh5zx8rlwamxfsk3d-user-environment.drv'...

docker > nmap --version
Nmap version 7.93 ( https://nmap.org )
Platform: x86_64-unknown-linux-gnu
Compiled with: liblua-5.3.6 openssl-3.0.11 libssh2-1.11.0 nmap-libz-1.2.12 libpcre-8.45 libpcap-1.10.4 nmap-libdnet-1.12 ipv6
Compiled without:
Available nsock engines: epoll poll select

您可以通过进入另一个镜像的调试 shell 来确认 nmap 现在已是您工具箱的一部分:

$ docker debug hello-world
...
docker > nmap --version

Nmap version 7.93 ( https://nmap.org )
Platform: x86_64-unknown-linux-gnu
Compiled with: liblua-5.3.6 openssl-3.0.11 libssh2-1.11.0 nmap-libz-1.2.12 libpcre-8.45 libpcap-1.10.4 nmap-libdnet-1.12 ipv6
Compiled without:
Available nsock engines: epoll poll select

docker > exit

nmap 仍然存在。

了解容器的默认启动命令(入口点)

Docker Debug 附带一个内置工具,entrypoint。 进入 hello-world 镜像并确认入口点为 /hello

$ docker debug hello-world
...
docker > entrypoint --print
/hello

entrypoint 命令会评估基础镜像的 ENTRYPOINTCMD 语句,并允许您打印、检查或运行生成的入口点。 然而,从 了解 CMD 和 ENTRYPOINT 如何交互 中理解所有边界情况可能比较困难。 在这些情况下,entrypoint 可以提供帮助。

使用 entrypoint 调查从 Nginx 镜像运行容器时实际发生的情况:

$ docker debug nginx
...
docker > entrypoint
Understand how ENTRYPOINT/CMD work and if they are set correctly.
From CMD in Dockerfile:
 ['nginx', '-g', 'daemon off;']

From ENTRYPOINT in Dockerfile:
 ['/docker-entrypoint.sh']

By default, any container from this image will be started with following   command:

/docker-entrypoint.sh nginx -g daemon off;

path: /docker-entrypoint.sh
args: nginx -g daemon off;
cwd:
PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

Lint results:
 PASS: '/docker-entrypoint.sh' found
 PASS: no mixing of shell and exec form
 PASS: no double use of shell form

Docs:
- https://docs.docker.com/reference/dockerfile/#cmd
- https://docs.docker.com/reference/dockerfile/#entrypoint
- https://docs.docker.com/reference/dockerfile/#understand-how-cmd-and-entrypoint-interact

输出表明在 nginx 镜像启动时,会执行一个脚本 /docker-entrypoint.sh,并带有参数 nginx -g daemon off;。 你可以使用 --run 选项来测试入口点:

$ docker debug nginx
...
docker > entrypoint --run
/docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
/docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
/docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf
10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
/docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
/docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh
/docker-entrypoint.sh: Configuration complete; ready for start up
2024/01/19 17:34:39 [notice] 50#50: using the "epoll" event method
2024/01/19 17:34:39 [notice] 50#50: nginx/1.25.3
2024/01/19 17:34:39 [notice] 50#50: built by gcc 12.2.0 (Debian 12.2.0-14)
2024/01/19 17:34:39 [notice] 50#50: OS: Linux 5.15.133.1-microsoft-standard-WSL2
2024/01/19 17:34:39 [notice] 50#50: getrlimit(RLIMIT_NOFILE): 1048576:1048576
2024/01/19 17:34:39 [notice] 50#50: start worker processes
2024/01/19 17:34:39 [notice] 50#50: start worker process 77
...

这将在您的调试 shell 中启动 nginx,而无需实际运行容器。 您可以通过按 Ctrl+C 来关闭 nginx。

直接运行命令(例如,用于脚本编写)

使用 --command 选项可以直接执行命令,而不是启动交互式会话。 例如,这与 bash -c "arg1 arg2 ..." 类似。 以下示例在 nginx 镜像中运行 cat 命令,而不启动交互式会话。

$ docker debug --command "cat /usr/share/nginx/html/index.html" nginx

<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>

<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>

<p><em>Thank you for using nginx.</em></p>
</body>
</html>

使用 --host 选项进行远程调试

以下示例展示了如何使用 --host 选项。第一个示例使用 SSH 连接到位于 example.org 的远程 Docker 实例,以 root 用户身份,并进入 my-container 容器的 shell。

$ docker debug --host ssh://root@example.org my-container

下面的示例连接到不同的本地 Docker 引擎,并进入 my-container 容器的 shell。

$ docker debug --host=unix:///some/path/docker.sock my-container