一、容器本质:被“限制”的特殊进程
-
核心观点
graph LR A[二进制程序] -->|加载执行| B[进程:内存+CPU+设备状态] B -->|隔离| C[容器] C --> D[Namespace:进程视图隔离] C --> E[Cgroups:资源限制]
- 静态实体 = 程序(磁盘上的二进制文件)
- 动态实体 = 进程(运行时的计算机执行环境总和)
- 容器本质 = 通过技术约束的进程
-
关键技术实现
技术 作用机制 类比解释 Namespace 修改进程视图(PID,Network等) 给进程带“VR眼镜”,只能看到虚拟环境 Cgroups 限制资源用量(CPU/内存/IO等) 给进程套“枷锁”
二、Namespace 深度解析
1. PID Namespace(进程隔离)
# 原始进程:宿主机视角
$ ps -ef | grep /bin/sh
ubuntu 100 0.0 0.0 2120 540 pts/0 S 10:00 0:00 /bin/sh
# 容器内进程:隔离后视角
/ # ps
PID USER TIME COMMAND
1 root 0:00 /bin/sh # 误以为自己是1号进程
- 实现原理:
clone()
系统调用 +CLONE_NEWPID
参数
2. 其他关键Namespace
Namespace类型 | 作用域 | Docker默认启用 |
---|---|---|
Mount | 文件系统挂载点 | ✅ |
UTS | 主机名和域名 | ✅ |
IPC | 进程间通信 | ✅ |
Network | 网络设备/IP/端口 | ✅ |
User | 用户和用户组映射 | ❌(需手动启用) |
Cgroup | Cgroup根目录 | ✅ |
三、Cgroups:容器的资源限制手段
1. 核心能力
graph TB
A[Cgroups子系统] --> B[cpu]
A --> C[memory]
A --> D[blkio]
A --> E[devices]
A --> F[net_cls]
G[容器进程] -->|写入限制值| H[/sys/fs/cgroup/.../]
- 通过虚拟文件系统实现(路径:
/sys/fs/cgroup/
) - 限制维度:CPU配额、内存上限、磁盘IO、设备访问
2. Docker实战示例
# 启动限制资源的容器
docker run -it --cpus=0.5 --memory=100M busybox /bin/sh
# 查看Cgroup配置
$ cat /sys/fs/cgroup/memory/docker/<容器ID>/memory.limit_in_bytes
104857600 # 100MB内存限制
四、容器 vs 虚拟机:架构本质差异
这幅图的左边,画出了虚拟机的工作原理。其中,名为 Hypervisor 的软件是虚拟机最主要的部分。它通过硬件虚拟化功能,模拟出了运行一个操作系统需要的各种硬件,比如 CPU、内存、I/O 设备等等。然后,它在这些虚拟的硬件上安装了一个新的操作系统,即 Guest OS。
这样,用户的应用进程就可以运行在这个虚拟的机器中,它能看到的自然也只有 Guest OS 的文件和目录,以及这个机器里的虚拟设备。这就是为什么虚拟机也能起到将不同的应用进程相互隔离的作用。
而这幅图的右边,则用一个名为 Docker Engine 的软件替换了 Hypervisor。这也是为什么,很多人会把 Docker 项目称为“轻量级”虚拟化技术的原因,实际上就是把虚拟机的概念套在了容器上。
可是这样的说法,却并不严谨。
在理解了 Namespace 的工作方式之后,你就会明白,跟真实存在的虚拟机不同,在使用 Docker 的时候,并没有一个真正的“Docker 容器”运行在宿主机里面。Docker 项目帮助用户启动的,还是原来的应用进程,只不过在创建这些进程时,Docker 为它们加上了各种各样的 Namespace 参数。
这时,这些进程就会觉得自己是各自 PID Namespace 里的第 1 号进程,只能看到各自 Mount Namespace 里挂载的目录和文件,只能访问到各自 Network Namespace 里的网络设备,就仿佛运行在一个个“容器”里面,与世隔绝。
不过,相信你此刻已经会心一笑:这些不过都是“障眼法”罢了。
graph TD
subgraph 虚拟机
A[Hypervisor] --> B[虚拟CPU]
A --> C[虚拟内存]
A --> D[虚拟设备]
B --> E[Guest OS]
C --> E
D --> E
E --> F[App]
end
subgraph 容器
G[Host OS] --> H[Docker Engine]
H --> I[Namespace+Cgroups]
I --> J[App进程]
end
- 核心区别:
- 虚拟机:硬件虚拟化 + 完整Guest OS(重量级)
- 容器:进程隔离 + 共享主机内核(轻量级)
五、Docker默认启用的Namespace
Namespace | 作用 | Docker默认启用 |
---|---|---|
PID | 进程ID隔离 | ✅ |
Net | 网络设备/IP隔离 | ✅ |
IPC | 信号量/共享内存隔离 | ✅ |
Mount | 文件系统挂载点隔离 | ✅ |
UTS | 主机名隔离 | ✅ |
Cgroup | Cgroup根目录隔离 | ✅(较新版本) |
User | 用户/用户组隔离 | ❌(需--userns 参数) |
关键结论提炼
- 容器不是迷你虚拟机:无虚拟化开销,本质是受限进程
- Namespace是根基:制造"隔离幻觉"(每个容器误以为自己独占系统)
- Cgroups是护栏:防止进程抢夺资源导致系统崩溃
- 二者协作关系:
Namespace:决定"能看到什么" → 环境隔离 Cgroups:决定"能用多少" → 资源限制
技术演进:现代容器(如Kubernetes)在此基础之上添加:
- 镜像分层(Union FS)
- 声明式API(K8s Resources)
- 服务治理(Service Mesh)
但底层隔离机制始终依赖Linux Namespace+Cgroups
参考:极客时间-张磊-白话容器基础