如何使用 docker debug 命令调试容器和镜像

DockerDockerBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,我们将探索如何高效地使用 docker debug 命令及相关技术调试 Docker 容器和镜像。首先,我们将解决调试无 shell 的 slim 容器的挑战,演示如何直接在其环境中执行命令。

随后,我们将学习如何在镜像尚未作为容器运行前直接调试 slim 镜像。我们还将介绍如何修改运行中容器内的文件以进行调试,以及如何使用 installuninstall 命令管理调试工具箱。最后,通过 entrypoint 命令,我们将更深入地理解容器的入口点机制。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL docker(("Docker")) -.-> docker/ContainerOperationsGroup(["Container Operations"]) docker(("Docker")) -.-> docker/VolumeOperationsGroup(["Volume Operations"]) docker(("Docker")) -.-> docker/DockerfileGroup(["Dockerfile"]) docker/ContainerOperationsGroup -.-> docker/run("Run a Container") docker/ContainerOperationsGroup -.-> docker/rm("Remove Container") docker/ContainerOperationsGroup -.-> docker/exec("Execute Command in Container") docker/VolumeOperationsGroup -.-> docker/cp("Copy Data Between Host and Container") docker/DockerfileGroup -.-> docker/build("Build Image from Dockerfile") subgraph Lab Skills docker/run -.-> lab-555138{{"如何使用 docker debug 命令调试容器和镜像"}} docker/rm -.-> lab-555138{{"如何使用 docker debug 命令调试容器和镜像"}} docker/exec -.-> lab-555138{{"如何使用 docker debug 命令调试容器和镜像"}} docker/cp -.-> lab-555138{{"如何使用 docker debug 命令调试容器和镜像"}} docker/build -.-> lab-555138{{"如何使用 docker debug 命令调试容器和镜像"}} end

调试无 shell 的 slim 容器

在本步骤中,我们将学习如何调试未安装 shell 的 slim 容器。Slim 容器通常用于减小镜像体积和攻击面,但当出现问题时调试会变得具有挑战性。

首先,让我们运行一个简单的 slim 容器,它会打印一条消息然后退出。我们将使用非常小巧的 Linux 发行版 alpine 镜像。

docker run alpine echo "Hello from Alpine!"

你应该会在终端看到输出 Hello from Alpine!,这确认容器已成功运行。

现在,让我们尝试使用 docker exec 在这个容器内运行命令。我们将尝试运行常见的 shell /bin/sh

docker run -d --name slim-container alpine sleep 3600
docker exec -it slim-container /bin/sh

你很可能会看到错误信息,提示找不到 /bin/sh。这是因为默认配置的 alpine 镜像不包含 bashsh 等 shell,这是 slim 容器的常见特性。

要调试没有 shell 的容器,我们可以使用 docker exec 命令在容器环境中直接运行特定命令。由于没有 shell,我们需要直接执行命令。

让我们尝试列出容器根目录的文件。我们知道即使在最小化环境中通常也提供 ls 命令。

docker exec -it slim-container ls /

你应该会看到容器文件系统根目录下的目录和文件列表,例如 binetclib 等。这证明即使没有 shell,我们仍然可以直接在容器内执行命令。

最后,让我们清理创建的容器。

docker stop slim-container
docker rm slim-container

本步骤展示了如何通过直接使用 docker exec 执行命令来与没有 shell 的 slim 容器交互。在接下来的步骤中,我们将探索其他调试技术。

直接调试 slim 镜像

在上一步中,我们学习了如何与运行中的 slim 容器交互。但有时你可能需要在镜像 尚未 作为容器运行前检查其内容,或者当容器启动失败时进行调试。本步骤将探索如何直接调试 slim 镜像。

Docker 的 docker run 命令提供了覆盖镜像默认入口点和命令的能力。这让我们可以在镜像创建的临时容器中运行不同命令,从而检查其内容。

让我们再次使用 alpine 镜像。我们知道这是一个默认不包含 shell 的 slim 镜像。可以直接使用 docker run 在镜像上执行 ls / 等命令。

docker run --rm alpine ls /

--rm 标志确保临时容器在命令执行后自动删除。你应该会看到与上一步在运行容器中执行 ls / 相同的输出,这证实我们可以直接检查镜像的文件系统。

现在,让我们检查镜像中是否存在特定命令。例如检查 ping 命令是否存在。

docker run --rm alpine which ping

你可能会看到 which: not found 的错误信息,这表明默认的 alpine 镜像不包含 ping 命令。这是 slim 镜像的另一个特点——它们通常只包含绝对必要的最小工具集。

让我们尝试一个已知存在的命令,比如 cat

docker run --rm alpine which cat

这次你应该会看到输出 /bin/cat,确认镜像中确实存在 cat 命令。

这种使用 docker run --rm <image> <command> 的技术非常有用,可以快速检查镜像内容、验证特定文件或命令是否存在,以及理解镜像结构,而无需运行长期容器或构建新镜像。

修改运行中容器内的文件

在本步骤中,我们将学习如何修改运行中容器内的文件。这在调试时非常有用,例如更改配置文件或向已运行的容器添加临时脚本。

我们将首先基于 ubuntu 镜像运行一个简单容器,它比 alpine 功能更丰富,包含 shell 和常用工具。

docker run -d --name my-ubuntu ubuntu sleep 3600

该命令以分离模式 (-d) 运行 Ubuntu 容器,并使用 sleep 3600 命令使其运行一小时。我们将容器命名为 my-ubuntu 以便引用。

现在,使用 docker exec 获取运行中容器内的 shell。

docker exec -it my-ubuntu /bin/bash

你现在应该已进入 my-ubuntu 容器的 bash shell。提示符会变化以反映你正在容器内。

在容器内,让我们在 /tmp 目录创建一个新文件。

echo "This is a test file." > /tmp/test_file.txt

现在验证文件是否已创建并包含正确内容。

cat /tmp/test_file.txt

你应该会看到输出 This is a test file.。这确认我们能够在运行中的容器内创建并写入文件。

要退出容器 shell,只需输入 exit

exit

现在你已回到 LabEx VM 终端。

我们还可以使用 docker cp 命令在运行中容器内外复制文件。让我们在 LabEx VM 上创建一个文件并复制到容器中。

首先,在 ~/project 目录创建名为 local_file.txt 的文件。

echo "This file is from the host." > ~/project/local_file.txt

现在将该文件复制到 my-ubuntu 容器的 /tmp 目录。

docker cp ~/project/local_file.txt my-ubuntu:/tmp/

docker cp 的格式是 docker cp <源路径> <容器名>:<目标路径>docker cp <容器名>:<源路径> <目标路径>

让我们验证文件是否已复制到容器中。重新进入容器 shell。

docker exec -it my-ubuntu /bin/bash

在容器内,检查 /tmp 中是否存在 local_file.txt

ls /tmp/

你应该会看到 local_file.txttest_file.txt 一起列出。

现在查看容器内 local_file.txt 的内容。

cat /tmp/local_file.txt

你应该会看到输出 This file is from the host.

再次退出容器 shell。

exit

最后,清理容器。

docker stop my-ubuntu
docker rm my-ubuntu

本步骤演示了如何使用 docker exec 获取 shell 和标准 Linux 命令来修改运行中容器内的文件,以及如何使用 docker cp 在主机和容器之间复制文件。

使用安装与卸载管理调试工具集

在本步骤中,我们将探索如何在运行中的容器内添加和移除调试工具。虽然通常建议保持生产环境容器镜像最小化,但有时你需要安装临时工具进行调试。

我们将再次使用 ubuntu 镜像,因为它带有 apt 包管理器,可以方便地安装软件。

首先,以分离模式运行一个新的 Ubuntu 容器。

docker run -d --name debug-ubuntu ubuntu sleep 3600

现在,进入容器内的 shell。

docker exec -it debug-ubuntu /bin/bash

在容器内,尝试使用默认未安装的命令,如 ping

ping google.com

你可能会看到"command not found"错误。

要安装 ping 和其他网络工具,我们可以使用 apt 包管理器。首先更新软件包列表是个好习惯。

apt update

该命令从软件源获取最新的可用软件包信息。

现在安装提供 ping 命令的 iputils-ping 包。

apt install -y iputils-ping

-y 标志会自动确认安装而无需提示。

安装完成后,你应该可以使用 ping 命令了。

ping -c 4 google.com

你将看到 ping 命令的输出,表明该命令现在在容器内可用且正常工作。

调试完成后,建议移除已安装的工具以保持容器清洁,如果要将其提交为新镜像也能减小体积(尽管通常不建议为生产环境修改运行中的容器)。

使用 apt remove 移除 iputils-ping 包。

apt remove -y iputils-ping

你可以验证 ping 是否已不可用。

ping google.com

你应该会再次看到"command not found"错误。

退出容器 shell。

exit

最后清理容器。

docker stop debug-ubuntu
docker rm debug-ubuntu

本步骤演示了如何使用容器自带的包管理器在运行中的容器内临时安装和卸载调试工具。对于排查基础镜像未包含必要工具的容器问题,这是一种强大的技术手段。

通过 entrypoint 命令理解容器入口点

在本步骤中,我们将学习 Dockerfile 中的 ENTRYPOINT 指令及其对容器运行方式的影响。ENTRYPOINT 定义了容器启动时将执行的命令,通常用于设置容器的主执行程序。

让我们创建一个使用 ENTRYPOINT 的简单 Dockerfile。在 ~/project 目录下创建名为 Dockerfile 的文件,内容如下:

FROM alpine
ENTRYPOINT ["echo", "Hello from the entrypoint!"]
CMD ["default", "command"]

这个 Dockerfile 使用 alpine 镜像作为基础。ENTRYPOINT 设置为 ["echo", "Hello from the entrypoint!"]CMD 设置为 ["default", "command"]。当同时指定 ENTRYPOINTCMD 时,CMD 的参数会作为 ENTRYPOINT 命令的参数传递。

现在,我们基于这个 Dockerfile 构建镜像。

docker build -t my-entrypoint-image ~/project

该命令从 ~/project 目录的 Dockerfile 构建名为 my-entrypoint-image 的镜像。

现在,我们运行这个镜像的容器而不提供额外命令。

docker run my-entrypoint-image

你应该会看到输出 Hello from the entrypoint! default command。这表明 ENTRYPOINT 命令 (echo) 被执行,且 CMD 参数 (default command) 被传递给它。

现在,我们在 docker run 命令行提供不同的命令。当你在 docker run 命令行提供命令时,它会覆盖 Dockerfile 中的 CMD 指令,但 ENTRYPOINT 仍会以提供的命令作为参数执行。

docker run my-entrypoint-image "override command"

你应该会看到输出 Hello from the entrypoint! override command。这演示了 ENTRYPOINT 仍被执行,但 docker run 命令的参数 (override command) 替换了 CMD 参数。

如果你想完全忽略 ENTRYPOINT 并运行不同的命令怎么办?你可以使用 docker run--entrypoint 标志。

docker run --entrypoint /bin/echo my-entrypoint-image "Running a different command"

你应该会看到输出 Running a different command。这种情况下,--entrypoint 标志覆盖了 Dockerfile 中指定的 ENTRYPOINT,提供的命令 (/bin/echo) 以参数 (Running a different command) 执行。

理解 ENTRYPOINTCMD 对于构建和调试 Docker 镜像至关重要。ENTRYPOINT 定义了核心可执行程序,而 CMD 为该可执行程序提供默认参数,或者在没有设置 ENTRYPOINT 时提供默认命令。

总结

在本实验中,我们学习了如何使用 docker debug 命令及相关技术来调试 Docker 容器和镜像。我们首先探索了如何调试缺少 shell 的精简容器,证明了即使没有传统的 bashsh 等 shell,我们仍然可以使用 docker exec 直接在容器环境中执行命令。这是排查最小化容器镜像问题的关键技术。

虽然提供的内容仅涵盖第一步,但实验的整体结构表明后续步骤将深入探讨直接调试精简镜像、修改运行中容器内的文件、使用安装与卸载命令管理调试工具集,以及通过 entrypoint 命令理解容器入口点。这些步骤将进一步提升我们诊断和解决 Docker 化应用及镜像问题的能力。