Docker 简明教程

Docker - Containers & Shells

在 Docker 容器中,Shell 必不可少;它们充当界面,通过它们可以在容器中执行命令。通常,当一个容器启动时,它必须运行一个 shell 来解释和执行 Dockerfile 中描述的命令或在运行容器时传递的命令。

Shell 执行以下几项至关重要的功能 −

  1. Command Execution − Shell 解释和执行用户在脚本中编写的或交互式输入的命令。这包括软件安装、环境配置和应用程序执行。

  2. Script Automation − Shell 脚本在 Dockerfile 中扮演的最大角色之一就是自动化容器环境设置。它确保所有必要的步骤会自动并一致地执行。

  3. Interactive Access − Shell 使能与容器的交互访问,从而允许开发者和管理员调试、管理和检查容器的环境。这可以通过交互式运行命令(例如,docker exec)对正在运行的容器进行操作,在其中打开一个 shell 会话来实现。

Types of Shells Commonly Used in Docker

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

Bash (Bourne Again Shell)

  1. Default Shell − Bash 是大多数 Linux 发行版的默认 shell,并且是 Docker 容器中使用最广泛的 shell。

  2. Scripting − 它具有广泛的脚本编写功能,从变量和循环到条件语句和函数。

  3. Rich Functionality − Bash 提供了诸如命令历史、作业控制和 Tab 补全等功能,可增强交互式使用。

Sh (Bourne Shell)

  1. Simplicity − 与 Bash 相比,Sh 是一个非常简单的 shell。它是最初的 Unix shell,几乎可在所有类 Unix 系统上使用。

  2. Portability − Sh 脚本高度可移植,几乎可以在任何类 Unix 操作系统上运行。

  3. Fewer Features − 它不如 bash 功能丰富,但这使得脚本通常更易于可移植编写。

Zsh (Z Shell)

  1. Advanced Features − 它具有 Bash 中没有的大多数高级功能,如更好的 Tab 补全、广泛的脚本编写功能和高度可自定义的提示。

  2. Customization − 它高度可自定义,允许用户根据自己的偏好定制 shell 环境。

  3. Popularity − 凭借其强大的功能和可自定义性,Zsh 在开发者群体中变得特别流行。

Accessing Shells with in Docker Containers

让我们了解在 Docker 容器中访问 shell 的不同方法。

Docker exec Command (Interactive and Detached Modes)

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

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

在已经运行的容器内运行 Bash shell 的示例命令 -

$ docker exec -it <container_id> /bin/bash
interactive mode

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

除此之外,docker exec 还可以接受以分离方式做事 - 执行命令,但不会将用户连接到进程。这对于容器内的所有后台处理或非交互式命令非常有用。

示例分离进程命令 -

$ docker exec -d <container_id> <command>
detached mode

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

docker run -it (Interactive Terminal at Container Start)

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

使用 Bash 在新容器中启动交互式 shell 的示例命令 -

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

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

nsenter and Other Low-Level Tools

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,并可以完全访问容器的环境。

Using Docker Desktop with Shell Access(GUI)

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

使用 Docker Desktop 访问 shell -

  1. Open Docker Desktop - 从应用程序菜单中启动 Docker Desktop 应用程序。

  2. View Containers - 点击“容器/应用程序”选项卡可查看正在运行的容器列表。

  3. Open Terminal - 只需点击要连接的容器,然后点击“CLI”或“终端”按钮。这会打开一个新的终端窗口,该窗口依附于容器,通常在其中有 bash 外壳。

Running Containers as Non-Root Users

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

Best Practices

Create Non-Root Users - 使用 USER 指令在 Dockerfile 中定义非 root 用户。例如 -

FROM ubuntu:latest
RUN useradd -m nonrootuser
USER nonrootuser

Restrict Capabilities - 通过使用 Docker 的 --cap-drop 和 --cap-add 选项来删除特权,从而限制容器的能力。

File System Permissions - 确保正确设置文件系统权限,以防止对敏感文件和目录进行未经授权的访问。

Conclusion

在本章中,我们讨论了如何访问容器外壳。我们研究了不同类型的容器外壳以及用于访问每一个容器外壳的命令。如果你想检查 docker 容器内部发生的事情,或者你想要在容器中运行命令,这些命令会很有用。

FAQs on Docker Containers & Shells

1. What should I do if the docker container doesn’t have a shell?

有时,为了保持小镜像大小,容器镜像特意没有外壳。在这种情况下,你可以执行下列操作:使用安装了外壳的新层提交正在运行的容器,然后基于此修改后的镜像启动新的容器。

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

2. Are there any Alternatives to Accessing Docker Container Shells?

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

具有连接的调试器的 docker exec 等专用工具启用了此类调试可能性,或者当需要深入分析正在运行的进程时通过 strace 和 gdb 启用。最终,最佳方法将基于你的需求以及你的任务需要多少访问权限。