一、 核心概念对齐:什么是 Namespace?
1. 什么是 Namespace(命名空间),它跟容器是什么关系?
- 通俗解释:如果把 Linux 宿主机比作一间大办公室,所有的进程原本都在大开间里一起办公,大家共享同一个地址、同一个前台、同一套工位编号。Namespace 技术就是给大开间里造了一间间隔音且不透明的“独立玻璃房”。
- 与容器的关系:Docker 容器本质上根本不是什么新东西,它就是跑在这些“玻璃房”里的普通 Linux 进程。Namespace 提供了玻璃房的墙壁(隔离),而 Docker 只是那个负责帮你搭墙、搬家具的装修工。
2. Namespace 隔离的到底是什么?
它隔离的是全局系统资源。比如进程编号(PID)、网络设备(网卡/IP)、文件系统挂载点等。通过隔离,玻璃房里的进程会产生一种幻觉:“我是这台机器上唯一的程序,我独占了所有资源。”
3. 为什么需要 Namespace,解决了什么问题?
- 解决冲突:如果没有隔离,两个 Web 容器同时想监听 80 端口就会报错。有了隔离,它们各自拥有独立的网络空间,都可以绑定自己空间内的 80 端口。
- 安全与权限:防止恶意进程随便杀死其他进程,或者偷窥其他进程的数据。
二、 7 种 Linux Namespace 技术详解
接下来,我们逐一拆解 Linux 内核提供的 7 种“玻璃房”材料。我们将使用 unshare 命令来演示,这个命令的作用是脱离父进程的某个 Namespace,在一个全新的 Namespace 中运行程序。
1. UTS Namespace (主机名与域名隔离)
- 一句话概括:让进程拥有自己独立的 Hostname(主机名)和 Domain Name(域名)。
- 作用:在宿主机上,主机名只有一个。UTS 隔离让每个容器可以拥有自己独特的名字,仿佛是一台独立的机器。
- 简单演示:
- 实际应用:在微服务架构中,容器通过自己独立的 Hostname 在内部网络中互相识别和通信。
2. PID Namespace (进程编号隔离)
- 一句话概括:让进程在自己的空间里编号重新从 1 开始。
- 作用:Linux 系统开机第一个进程是 init(PID=1),它是所有进程的祖宗。PID 隔离让容器内的程序误以为自己是 PID 1,从而方便容器管理自己的生命周期。
- 简单演示:
- 实际应用:Docker 容器内部启动的应用主进程,你在容器里
ps看它总是 PID 1。如果这个 PID 1 挂了,容器也就自动退出了。
3. Mount Namespace (文件系统挂载点隔离)
- 一句话概括:让进程看到一个完全独立的文件目录视图(你挂载或卸载磁盘,不影响宿主机)。
- 作用:这是历史上第一个 Namespace。它允许容器内部拥有独立的
/tmp、独立的根目录/。容器里怎么折腾文件,都不会弄坏外面的宿主机。 - 简单演示:
- 实际应用:结合
chroot技术,Docker 才能把镜像里的各种文件(比如 Ubuntu 或 CentOS 的系统目录)挂载为容器的根目录。
4. Network Namespace (网络资源隔离)
- 一句话概括:给进程分配独立的虚拟网卡、IP 地址、路由表和防火墙规则。
- 作用:这是容器网络的基础。它让容器与宿主机的网络完全隔离开来,避免端口冲突。
- 简单演示:
- 实际应用:Docker 的
bridge网络模式。Docker 会给每个容器分配一个 Network Namespace,然后用一对虚拟网线(veth pair)把容器连到宿主机的虚拟交换机(docker0)上。
5. IPC Namespace (进程间通信隔离)
- 一句话概括:防止不同容器的进程通过共享内存或消息队列互相偷窥数据。
- 作用:Linux 进程间可以通过一块共享的内存(IPC)来光速传数据。如果不隔离,容器 A 的进程就能读写容器 B 进程的内存数据,极不安全。
- 简单演示:
- 实际应用:保障容器的底层内存通信安全,是多租户环境(如 Kubernetes)必备的隔离屏障。
6. User Namespace (用户和用户组隔离)
- 一句话概括:让进程在容器内拥有 root 权限,但在宿主机上只是个普通平民。
- 作用:极大地提升了安全性。很多应用在容器里需要 root 权限来运行(比如安装软件),但这存在“容器逃逸”的风险。User 隔离利用了 ID 映射技术:让容器里的 UID 0 (root) 映射到宿主机上的 UID 1000 (普通用户)。
- 简单演示:
- 实际应用:Rootless Docker(非 root 模式运行的 Docker)底层完全依赖这个技术,用来防御黑客攻击。
7. Cgroup Namespace (控制组视图隔离)
- (注:Cgroup 本身是用来限制 CPU/内存大小的,而 Cgroup Namespace 隔离的是对 Cgroup 目录的查看视图)
- 一句话概括:让进程只能看到自己所属的资源限制配置,看不到宿主机全局的资源配置。
- 作用:隐藏宿主机的实际物理资源信息,防止容器内的进程通过读取
/sys/fs/cgroup目录获取到整台物理机的信息。 - 实际应用:让容器化管理工具更安全。在较新的 Linux 和 Docker 版本中,这个功能默认开启,使得容器环境更加“沙盒化”。
💡 总结与下一步探索
我们今天通过 unshare 命令,手动模拟了 Docker 在底层调用 Linux 内核 API 的过程。Docker Run 命令本质上就是把上面这 7 种 unshare 参数打包组合,一键执行而已。
既然我们已经掌握了这些底层隔离的积木,你想不想尝试一个极客挑战:我们完全不安装、不使用 Docker,仅凭 Linux 自带的基础命令,手动用 Namespace 拼装出一个能跑 Web 服务的“纯手工容器”? 如果感兴趣,我可以带你一步步敲出来!