Docker工作原理详解 | AI生成和翻译
让我们深入探讨 Docker 的工作原理,重点关注它如何利用 Linux 文件系统以及如何实现应用程序间的相互隔离。
Docker 的核心是什么?
Docker 是一个平台,允许你在称为容器的轻量级隔离环境中打包、分发和运行应用程序。与包含完整操作系统的虚拟机不同,Docker 容器共享主机操作系统内核,并利用其特性提供隔离和效率。
Docker 的工作原理
Docker 利用 Linux 内核的几项特性来创建和管理容器:
- 命名空间 - 用于隔离。
- 控制组 - 用于资源管理。
- 联合文件系统 - 用于高效存储和分层。
以下是这些组件如何协同工作:
1. Linux 命名空间:隔离机制
命名空间为系统资源创建隔离的”视图”,确保一个容器中的进程不会干扰其他容器中的进程。Docker 使用的关键命名空间包括:
- PID 命名空间:每个容器拥有独立的进程 ID 空间。容器内的进程 ID 1 与主机的 PID 1(通常是
init或systemd)是隔离的。 - 网络命名空间:容器拥有独立的网络栈(IP 地址、端口、路由表)。这就是为什么两个容器可以同时监听 8080 端口而不会冲突。
- 挂载命名空间:每个容器对文件系统有独立的视图,与主机和其他容器隔离。
- UTS 命名空间:容器可以拥有自己的主机名和域名。
- IPC 命名空间:隔离进程间通信(例如共享内存、消息队列)。
- 用户命名空间(可选):将容器用户映射到主机用户,增强安全性。
示例:如果在容器内运行 ps 命令,你只能看到该容器 PID 命名空间内的进程,而看不到主机的进程。
2. 控制组:资源限制
Cgroups 限制和监控每个容器的资源使用(CPU、内存、磁盘 I/O 等)。这可以防止某个容器占用所有系统资源而导致其他容器资源匮乏。
- 工作原理:Docker 为每个容器分配一个 cgroup。你可以设置如下限制:
docker run --memory="512m" --cpus="0.5" myapp这将容器限制为 512 MB 内存和半个 CPU 核心。
- 隔离:命名空间隔离了可见性,而 cgroups 隔离了资源消耗。
3. 联合文件系统:分层存储
Docker 使用联合文件系统(例如 OverlayFS、AUFS)来高效管理容器镜像及其文件系统。以下是它与 Linux 文件系统的关联方式:
- 镜像层:Docker 镜像由堆叠的只读层构成。每个层代表一组在
Dockerfile中定义的更改(例如安装软件包、复制文件)。- 示例:
FROM openjdk:17是一个层,COPY app.jar添加另一个层。 - 层会被缓存和重用,从而节省磁盘空间并加快构建速度。
- 示例:
- 容器文件系统:当你运行容器时,Docker 在只读镜像层之上添加一个薄的可写层。这称为写时复制机制:
- 读取操作来自镜像层。
- 写入操作(例如日志文件、临时数据)进入可写层。
- 如果修改了较低层中的文件,该文件会首先被复制到可写层(因此称为”写时复制”)。
-
隔离:每个容器都有自己的可写层,因此一个容器中的更改不会影响其他容器,即使它们共享相同的基础镜像。
- 磁盘存储:在主机上,这些层存储在
/var/lib/docker中(例如,OverlayFS 使用/var/lib/docker/overlay2)。你无需直接与此交互——Docker 会管理它。
应用程序如何相互隔离
以下是上述组件如何协同工作以实现应用程序隔离:
- 进程隔离:
- 每个容器运行其应用程序作为一个独立的进程树,不知道其他容器或主机的存在。
- 网络隔离:
- 容器拥有独立的网络接口。Docker 的默认”桥接”网络为每个容器分配唯一的 IP,并通过 NAT 处理外部通信。
- 示例:两个 Spring Boot 应用程序可以同时在各自的容器内绑定到 8080 端口而不会冲突。
- 文件系统隔离:
- 每个容器只能看到自己的文件系统,该文件系统由镜像层加上其可写层构建而成。
- 如果容器 A 写入
/tmp,容器 B 不会看到它。
- 资源隔离:
- 一个应用程序无法耗尽主机的 CPU 或内存而导致另一个应用程序崩溃。
- 共享内核:
- 容器共享主机的 Linux 内核,但命名空间确保它们不会相互干扰。系统调用会根据需要进行过滤或重定向。
简化工作流程
- 构建:使用
Dockerfile创建镜像,定义应用程序及其依赖项。Docker 使用联合文件系统将这些内容堆叠成层。 - 运行:Docker 通过以下方式创建容器:
- 设置命名空间以实现隔离。
- 分配 cgroups 以限制资源。
- 挂载镜像层加上一个可写层。
- 启动你的应用程序作为入口点(例如
java -jar app.jar)。
- 清理:当容器停止时,可写层会被丢弃(除非使用
docker commit保存为新镜像)。
为什么选择 Linux?
Docker 依赖于深度集成到其操作中的 Linux 内核特性(命名空间、cgroups、联合文件系统)。在 macOS 或 Windows 上,Docker 通过 HyperKit 或 WSL2 运行一个轻量级 Linux 虚拟机来提供这些功能,然后将它们映射到主机操作系统。
视觉类比
将 Docker 容器想象成建筑物中的公寓:
- 命名空间:墙壁和门将租户隔开。
- Cgroups:房东限制每个单元的水或电用量。
- UnionFS:所有公寓共享一个共同的蓝图(镜像层),但每个租户可以装饰自己的空间(可写层)。
这是否澄清了 Docker 的工作原理以及应用程序的隔离机制?如果你希望深入了解任何部分,请告诉我!