容器本质是宿主机上的特殊进程,其生命周期由PID 1进程决定;底层依赖Namespace实现隔离视图、Cgroups实施资源限制、联合文件系统提供分层存储。
容器生命周期不是抽象概念,它直接对应宿主机上一个或多个进程的启停过程;底层原理也不神秘,本质是 linux 内核提供的 namespace、cgroups 和联合文件系统协同作用的结果。
容器生命周期由 PID 1 进程决定
容器没有独立操作系统,它的“存活”完全依赖内部运行的第一个进程(即 PID 1)。Docker 守护进程持续监控该进程状态,一旦退出,整个容器立即终止。
- 运行
docker run -d nginx:alpine后,宿主机上实际启动的是nginx -g 'daemon off;'进程,它成为容器内 PID 1 - 若误用
docker run -d ubuntu:22.04 sleep 10,10 秒后 sleep 结束,PID 1 退出,容器立刻停止 - 想让容器长期运行,必须确保 PID 1 是一个不退出的前台进程(如 Nginx、Redis、自定义守护程序)
创建与启动背后的关键系统调用
从执行 docker run 到容器真正运行,底层经过一系列标准 Linux 系统调用,核心是 clone()、unshare() 和 execve()。
-
clone()创建新进程,并通过参数指定启用哪些 Namespace(如 CLONE_NEWPID、CLONE_NEWNET),实现资源视图隔离 -
unshare()让已有进程进入新的命名空间,常用于运行时调整隔离边界 -
execve()在隔离环境中加载并执行用户指定的二进制程序(比如 /bin/sh 或 /usr/sbin/nginx) - cgroups 的配置则通过写入
/sys/fs/cgroup/...下的虚拟文件完成,例如设置内存上限或 CPU 配额
镜像层与容器层的运行时协作
容器启动时,Docker 不复制整个镜像,而是利用联合文件系统(如 overlay2)将只读镜像层与可写容器层动态叠加。
- 镜像层按顺序堆叠,每一层记录文件系统变更(ADD、COPY、RUN 指令生成)
- 容器层位于最上方,所有写操作(touch、apt install、日志写入)都发生在此层
- 读文件时,系统从上至下查找,命中即返回;修改文件时先复制到底层内容(Copy-on-Write),再在容器层编辑
- 删除文件则在容器层生成 whiteout 文件,屏蔽镜像中同名项,保持镜像原始完整性
Docker 架构中的各组件分工
Docker 并非单体程序,而是一套分层协作的系统:CLI 发起请求,daemon 协调调度,containerd 负责生命周期管理,runc 执行最终的容器创建。
-
docker CLI:用户命令入口,将
docker run转为 HTTP 请求发给 daemon - dockerd:主守护进程,处理镜像拉取、网络配置、存储驱动初始化等高层逻辑
- containerd:专注容器生命周期(start/stop/kill),对接多种运行时
- runc:符合 OCI 规范的轻量运行时,调用内核接口真正创建隔离进程











