Docker - 容器与Shell



Shell 在 Docker 容器中至关重要;它们充当接口,通过它们在容器中执行命令。通常,当容器启动时,它必须运行一个 Shell 来解释和执行在 Dockerfile 中描述或在运行容器时传递的命令。

Shell 执行几个重要的功能 -

  • 命令执行 - Shell 解释和执行在脚本中编写的或用户交互式输入的命令。这包括软件安装、环境配置和应用程序执行。
  • 脚本自动化 - Shell 脚本在 Dockerfile 中扮演的最大角色之一是容器环境设置的自动化。它确保所有必要步骤都自动且一致地执行。
  • 交互访问 - Shell 允许交互访问容器,允许开发人员和管理员调试、管理和检查容器的环境。这是通过运行命令(例如,docker exec)来针对正在运行的容器交互地完成的,以在其中打开 Shell 会话。

Docker 中常用的 Shell 类型

Docker 容器中使用了相当多的 Shell 类型,它们具有不同的特性和优势 -

Bash(Bourne Again Shell)

  • 默认 Shell - Bash 是大多数 Linux 发行版的默认 Shell,并且在 Docker 容器中使用最为广泛。
  • 脚本 - 它具有广泛的脚本功能,从变量和循环到条件和函数。
  • 丰富的功能 - Bash 提供了命令历史记录、作业控制和制表符完成等功能,增强了交互式使用。

Sh(Bourne Shell)

  • 简单性 - 与 Bash 相比,Sh 是一个非常简单的 Shell。它是原始的 Unix Shell,几乎所有类 Unix 系统上都可用。
  • 可移植性 - Sh 脚本具有很强的可移植性,几乎可以在任何类 Unix 操作系统上运行。
  • 功能较少 - 它不像 bash 那样功能丰富,但这使得脚本通常更容易编写成可移植的。

Zsh(Z Shell)

  • 高级功能 - 它拥有 Bash 中不存在的大多数高级功能,例如更好的制表符补全、广泛的脚本功能和高度可定制的提示。
  • 自定义 - 它高度可定制,允许用户根据自己的喜好定制 Shell 环境。
  • 流行度 - 凭借其强大的功能和自定义功能,Zsh 在开发人员中尤其受欢迎。

访问 Docker 容器中的 Shell

让我们了解访问 Docker 容器内 Shell 的不同方法。

Docker exec 命令(交互式和分离模式)

访问和交互正在运行的 Docker 容器的最佳方法之一是通过 docker exec 命令。它允许在现有容器内启动一个新进程,从而允许执行命令甚至打开交互式 Shell 会话。

交互模式

docker exec 命令与 -it 标志一起使用,以交互方式访问正在运行的容器中可用的 Shell。在这种情况下,-i 表示交互式,-t 分配伪终端。通过这种方式,用户可以与 Shell 交互,就像他们真的登录了一样。

运行正在运行的容器内的 Bash Shell 的示例命令 -

$ docker exec -it <container_id> /bin/bash
Interactive Mode

在上面的示例中,用实际的运行容器 ID 或名称替换 <container_id>。这会将用户放入容器内的实时 Bash Shell 中,以进行交互和命令执行。

分离模式

除此之外,docker exec 还可以接受以分离方式执行操作的选项 - 执行命令但不将用户附加到进程。这非常适合容器内的所有后台处理或非交互式命令。

分离进程命令示例 -

$ docker exec -d <container_id> <command>
Detached Mode

在此示例中,<command> 是您希望在容器内运行的命令,并且由于我们使用了 -d,因此该命令将在后台运行,并且您的命令行与该进程分离。

docker run -it(在容器启动时交互式终端)

当您想要启动一个新容器并以交互方式打开其中的终端会话时,可以使用docker run -it 命令。这在调试、测试或交互式配置新容器时非常实用。

使用 Bash 启动带有交互式 Shell 的新容器的示例命令 -

$ docker run -it <image_name> /bin/bash
Docker run -it

在上面的示例中,在 <image_name> 中,您必须包含您想要从中创建容器的 Docker 镜像的名称。然后,选项 -it 使交互式和伪终端分配模式,允许用户直接与容器交互。

nsenter 和其他低级工具

nsenter 是一个低级 Linux 实用程序,用于访问正在运行的进程的命名空间。Docker 容器使用 Linux 命名空间作为隔离;nsenter 用于进入这些命名空间,从而访问容器内部的环境。

使用 nsenter 进入容器命名空间的示例命令 -

1. 首先,获取容器中正在运行的主进程的 PID -

$ docker inspect --format "{{.State.Pid}}" <container_id>
nsenter and Other Low-Level Tools 1

2. 使用 nsenter 访问容器的命名空间 -

$ nsenter --target <pid> --mount --uts --ipc --net --pid /bin/bash
nsenter and Other Low-Level Tools 2

在此示例中,用您在第一步中获得的 PID 替换 <pid>。这将在容器的命名空间内打开一个 bash,并完全访问容器的环境。

使用 Docker Desktop 访问 Shell(GUI)

Docker Desktop 对于 macOS 和 Windows 操作系统来说是一种便利,因为它提供了一个图形用户界面来处理 Docker 容器。因此,Docker CLI 中许多可能很复杂的工作,例如打开容器中的 Shell,都通过其 GUI 简化了。

要使用 Docker Desktop 访问 Shell -

  • 打开 Docker Desktop - 从您的应用程序菜单启动 Docker Desktop 应用程序。
  • 查看容器 - 点击“容器/应用”选项卡以查看正在运行的容器列表。
  • 打开终端 - 只需点击您要连接到的容器,然后点击“CLI”或“终端”按钮。这将打开一个连接到容器的新终端窗口,通常在其中包含一个 Bash Shell。

以非 root 用户身份运行容器

以非 root 用户身份运行容器是一种必要的安全实践。默认情况下,Docker 容器以 root 用户身份运行。这样做会导致如果攻击者进入容器,则会产生高度风险。在容器内运行最低必要的权限有助于减少潜在的损害。

最佳实践

创建非 root 用户 - 使用 USER 指令在您的 Dockerfile 中定义非 root 用户。例如 -

FROM ubuntu:latest
RUN useradd -m nonrootuser
USER nonrootuser

限制功能 - 通过使用 Docker 的 --cap-drop 和 --cap-add 选项来删除不必要的权限,从而限制容器的功能。

文件系统权限 - 确保文件系统权限设置正确,以防止未经授权访问敏感文件和目录。

结论

在本章中,我们讨论了如何访问容器 Shell。我们查看了不同类型的 Shell 以及访问每个 Shell 的命令。如果您想检查 Docker 容器内部发生了什么,或者如果您想在容器中运行命令,这些命令将非常有用。

关于 Docker 容器与 Shell 的常见问题

1. 如果 Docker 容器没有 Shell,我该怎么办?

有时容器镜像会故意不带 Shell 以保持镜像大小较小。在这种情况下,您可以执行以下操作:使用安装了 Shell 的新层提交正在运行的容器,然后基于此修改后的镜像启动一个新容器。

您可以使用Docker cp 命令或以其他方式将 Shell 二进制文件复制到容器中。更高级的是使用nsenter 相对直接地访问现有容器的命名空间。

2. 访问 Docker 容器 Shell 是否有任何替代方法?

是的,除了直接访问之外,还有其他方法可以与容器交互。例如,可以使用 docker logs 查看容器输出,使用 docker inspect 检查容器详细信息,或使用 docker stats 检查资源使用情况。

专用的工具(例如带有调试器附加的 docker exec)可以实现这种调试可能性,或者当需要深入分析正在运行的进程时,可以通过 strace 和 gdb 实现。最终,最佳方法将取决于您的需求以及您的任务需要多少访问权限。

广告