从 CPU 指令到容器隔离:Docker 就是一个打了标签的普通进程

CodeStats |资深底层技术爱好者与实战派架构师,WWAIC(全周 AI 编程)范式创始人

专注计算机体系结构、操作系统内核、Java 虚拟机实现原理与自研框架落地。

本文手撕容器底层:不讲空话,只从 CPU 指令 → 操作系统 → 进程 → Namespace → Cgroups 这条铁链,彻底讲透 Docker 是什么、凭什么能隔离、和普通进程到底有什么区别


📖 本文你能得到什么?

读完本文,你将彻底搞懂:

  • Docker 隔离的本质:不是虚拟机,而是依赖 Linux 内核的 Namespace 和 Cgroups 技术,把普通进程"包装"成容器。
  • CPU 特权级与系统调用:为什么用户程序不能随便访问硬件,必须通过内核。
  • 普通进程的隔离缺陷:为什么端口会冲突、环境变量会打架。
  • 6 大 Namespace 的作用:PID、Network、Mount、UTS、IPC、User 各自隔离什么。
  • 容器网络如何工作:veth pair、网桥、NAT 转发,外界如何访问容器服务。
  • 资源限制的原理:Cgroups 如何像"资源锁"一样防止容器拖垮宿主机。
  • Docker 与虚拟机的本质区别:共享内核 vs 独立内核,轻量 vs 重量级。

一句话记住:Docker 容器 = 打了隔离标签 + 上了资源枷锁的普通进程

📚 参考原文(CSDN)


📑 目录

  • [💡 核心观点一句话](#💡 核心观点一句话)
  • [一、CPU 指令集为什么要分权限?内核态 vs 用户态](#一、CPU 指令集为什么要分权限?内核态 vs 用户态)
  • 二、操作系统如何让每个进程"以为自己独占机器"
  • 三、普通进程之间到底缺什么隔离?(痛点场景)
  • [四、Docker 容器的本质:不是虚拟机,是带 Namespace 标签的普通进程](#四、Docker 容器的本质:不是虚拟机,是带 Namespace 标签的普通进程)
  • [五、Linux 内核给了 Docker 哪 6 把隔离"手术刀"](#五、Linux 内核给了 Docker 哪 6 把隔离“手术刀”)
  • [六、两个容器怎么做到端口不冲突?Network Namespace 的独立端口空间](#六、两个容器怎么做到端口不冲突?Network Namespace 的独立端口空间)
  • [七、外界如何访问容器里的服务?veth pair + 网桥 + NAT 隧道](#七、外界如何访问容器里的服务?veth pair + 网桥 + NAT 隧道)
  • [八、容器不会把宿主机搞垮的秘密:Cgroups 资源锁](#八、容器不会把宿主机搞垮的秘密:Cgroups 资源锁)
  • [九、终极总结:Docker 的本质公式 + 与虚拟机的本质区别](#九、终极总结:Docker 的本质公式 + 与虚拟机的本质区别)
  • [🔚 最后:点赞・收藏・评论](#🔚 最后:点赞・收藏・评论)

💡 核心观点一句话

Docker 容器 = 内核的 Namespace(隔离视图) + Cgroups(限制资源) + UnionFS(分层镜像)

它没有自己的操作系统内核,它就是宿主机上一个被打了"隔离标签"的普通进程


一、CPU 指令集为什么要分权限?内核态 vs 用户态

CPU 只认机器指令。有一类叫特权指令 (读写硬盘、改内存映射表),一旦用错,整个操作系统会直接宕机。Intel CPU 用 ring 0(内核态)和 ring 3(用户态)划分权限。普通程序要访问硬件,必须通过系统调用陷入内核,让内核代劳。

这一层奠定了"权限核级控制"的基础。


二、操作系统如何让每个进程"以为自己独占机器"

每个进程被分配一个虚拟地址空间 (32 位 Linux 为 4GB),通过 MMU 映射到真实物理内存。进程以为自己在独占整台电脑,实际上只隔离了内存视图。其他资源(端口、文件、PID)默认完全不隔离。


三、普通进程之间到底缺什么隔离?(痛点场景)

默认共享端口、文件系统、PID、主机名、环境变量等。例如:两个 Java 程序分别需要 Java 8 和 Java 11,全局 JAVA_HOME 只能设一个,另一个必然不兼容。我们需要按"组"隔离进程。


四、Docker 容器的本质:不是虚拟机,是带 Namespace 标签的普通进程

在宿主机上执行 ps aux | grep nginx 能看到容器进程的真实 PID。它和你手动启动的 nginx 进程毫无区别,只是 task_struct 里多了 Namespace 指针,内核会返回"包装后"的结果。容器没有自己的内核,没有硬件虚拟化,是纯进程级隔离。


五、Linux 内核给了 Docker 哪 6 把隔离"手术刀"

Namespace 隔离内容
PID 进程 ID 空间(容器内 PID=1,外面看 12345)
Network 网络设备、IP、端口表
Mount 文件系统挂载点
UTS 主机名和域名
IPC 信号量、消息队列
User 用户/组 ID 映射

Docker 调用 clone() 并传入 CLONE_NEW* 标志创建带 Namespace 的进程。


六、两个容器怎么做到端口不冲突?Network Namespace 的独立端口空间

每个 Network Namespace 拥有独立的 TCP/UDP 端口空间(0~65535)。容器 A 和 B 都可监听 80 端口,互不影响。端口冲突只在同一个 Network Namespace 内发生。


七、外界如何访问容器里的服务?veth pair + 网桥 + NAT 隧道

  1. 创建 veth pair,一头在容器(eth0),一头在宿主机(vethXXXX)。
  2. 将 vethXXXX 插到 docker0 网桥。
  3. 容器分配私有 IP(如 172.17.0.2/24)。
  4. docker run -p 8080:80 添加 iptables DNAT 规则。

流量路径:外部 → 宿主机:8080 → DNAT → 容器私有IP:80 → 容器内进程。


八、容器不会把宿主机搞垮的秘密:Cgroups 资源锁

Cgroups 限制 CPU、内存、磁盘 I/O、网络带宽。例如 docker run --cpus=1.5 --memory=512m,内核据此限制容器最多用 1.5 个 CPU 核,内存超限触发 OOM Kill。

Namespace 管"视野",Cgroups 管"食量"。


九、终极总结:Docker 的本质公式 + 与虚拟机的本质区别

Docker = Namespace(视图隔离) + Cgroups(资源限制) + UnionFS(镜像分层),Docker 只是一个友好的 CLI。

维度 虚拟机(KVM) 容器(Docker)
边界 硬件 内核(系统调用接口)
独立内核 每个虚拟机一个 Guest OS 内核 无,共享宿主机内核
启动时间 分钟级 毫秒级
资源开销 GB 级别 MB/KB 级别
隔离级别 强(硬件辅助虚拟化) 中(内核 Namespace)

一句话:虚拟机模拟硬件,跑操作系统;容器隔离进程,跑应用。


🔚 最后:点赞・收藏・评论

如果这篇文章帮你彻底搞懂了 Docker 的底层原理

  • 👍 点赞 让更多同学看到这篇硬核推演
  • ⭐ 收藏 方便随时复习完整逻辑链
  • 💬 评论 留下疑问或补充

从 CPU 指令到容器隔离,你已掌握本质。


© 2026 CodeStats|原创不易,转载注明出处