【Docker】知识五
目录
一、Namespace 基础定义与核心价值
1. 本质
Linux内核通过Namespace机制对系统资源进行抽象化处理与隔离划分:将各类资源(进程ID、网络设备、挂载点等)分别封装到不同的命名空间中,构建出多个相互独立的资源运行环境。运行在不同命名空间的程序,仅能访问所属空间内的资源,彼此间不存在资源可见性与干扰,最终达成高效、轻量的资源隔离目标。
举个直观的例子:
宿主机有100个进程,但容器里的进程只能看到自己组里的2个进程;
宿主机有eth0网卡,但容器里只有自己的虚拟网卡;
容器里的“/”根目录,和宿主机的“/”完全是两个独立的文件夹。
2.与容器的关系
容器的本质是 “被 Namespace 隔离、CGroup 限制资源、搭载独立 Rootfs 的应用运行单元”,其中 Namespace 是容器实现 “独立环境” 的核心底层支撑,相当于容器的 “隔离骨架”—— 没有 Namespace,容器就无法摆脱宿主机资源的束缚,与普通进程无本质区别。
二、Namespace 能隔离哪些资源?
Linux 给 8 类系统资源都配了 “隔离结界”,每类对应一种 Namespace 类型。我们结合实际场景拆解它们的作用:
|
Namespace 类型 |
隔离的资源 |
效果 |
|
Network Namespace |
网卡、IP、端口、路由表 |
PID Namespace 进程 ID(PID) 容器里的进程 PID 从 1 开始(比如容器里的 Nginx 进程是 PID=1),看不到宿主机的 systemd 进程。 |
|
PID Namespace |
进程 ID(PID) |
容器里的进程 PID 从 1 开始(比如容器里的 Nginx 进程是 PID=1),看不到宿主机的 systemd 进程。 |
|
Mount Namespace |
文件系统挂载点 |
容器里挂载 /proc 不会影响宿主机,容器的 “/” 根目录是自己的镜像文件系统(比如 Alpine 镜像的 /)。 |
|
UTS Namespace |
主机名、域名 |
可以给容器单独起个主机名(docker run --hostname my-app),不会和宿主机重名。 |
|
IPC Namespace |
消息队列、共享内存 |
容器里的进程用消息队列通信,其他容器或宿主机的进程 “听不见”。 |
|
User Namespace |
用户 / 用户组 ID(UID/GID) |
容器里的 “root 用户”,在宿主机其实是普通用户(比如 UID=1000),就算容器被攻破也不会拿到宿主机的 root 权限。 |
|
CGroup Namespace |
CGroup 控制组视图 |
容器只能看到自己的资源限制配置,改不了宿主机的 CGroup 规则。 |
|
PID for Children |
子进程的 PID 视图 |
可以单独给子进程设置 PID 隔离范围,比如让某个脚本的子进程只看到自己的 PID。 |
可以通过/proc/[进程PID]/ns查看进程所属的 Namespace:
ls -l /proc/$$/ns # $$是当前Shell的PID
输出里的pid:[1234]、net:[5678]就是 Namespace 的唯一标识 —— 标识相同的进程,共享同一份资源。
三、手动造容器:Namespace
我们用unshare命令从零搭一个 “简易容器”,亲身体验 Namespace 的隔离效果。
步骤 1:准备一个独立的根文件系统
容器的基础是 “独立的文件系统”,我们从 Docker 容器导出一个精简的根文件(以 Alpine 为例):
# 1. 启动一个Alpine容器,导出它的文件系统
docker run --name conns --rm -id alpine ash
docker export conns -o dockercontainer.tar
# 2. 解压到本地目录,作为“模拟容器”的根文件系统
mkdir -p mancontainer/rootsfs
tar -xf dockercontainer.tar -C mancontainer/rootsfs
步骤 2:用 unshare 创建完整隔离环境
unshare命令可以一次性创建多个新的 Namespace,我们直接隔离pid、net、uts、ipc、mnt:
# 在mancontainer目录下执行
unshare --mount --uts --ipc --net --pid --fork --user --map-root-user /bin/bash
参数解释:
--mount/--uts/--ipc/--net/--pid:创建新的 mnt/uts/ipc/net/pid Namespace
--fork:在新 Namespace 中启动子进程
--user --map-root-user:让容器内的 root 映射到宿主机普通用户(安全隔离)
验证:
执行id:显示是 root 用户,但实际在宿主机是普通用户(user Namespace);
执行ip link:只有 lo 网卡,没有宿主机的 eth0(net Namespace);
执行ps -ef:只能看到当前 Shell 进程(pid Namespace,PID 从 1 开始)。
步骤 3:完善 PID 隔离(挂载 proc 文件系统)
进程信息是通过/proc文件系统展示的,我们需要在新 Namespace 中重新挂载 proc:
mount -t proc proc /proc
再执行ps -ef,就只能看到隔离环境内的进程了 —— 这才是pid Namespace的完整效果。
步骤 4:给 “容器” 加网卡(net 隔离实战)
net Namespace 默认只有 lo 网卡,我们给它加一个能和外部通信的网卡:
# 1. 在宿主机创建一对veth虚拟网卡(vethLocal和vethContainer)
sudo ip link add vethLocal type veth peer name vethContainer
# 2. 找到unshare进程的PID(假设是3591)
ps -ef | grep unshare
# 3. 将vethContainer网卡加入“模拟容器”的net Namespace
sudo ip link set vethContainer netns 3591
回到 “隔离环境”,执行ip link,就能看到vethContainer网卡了 —— 这就是net Namespace的作用:容器有独立的网络设备。
四、Docker 对 Namespace 的应用
Docker 为每个容器默认创建6 组独立 Namespace(PID、Network、Mount、UTS、IPC、User),具体策略如下:
1. 默认隔离策略
PID Namespace:容器内进程 PID 从 1 开始(如 Nginx 容器内 nginx 进程 PID=1);
Network Namespace:容器拥有独立 IP(如 172.17.0.2),需通过 -p 映射端口到宿主机;
Mount Namespace:容器内挂载独立的 /(Rootfs)、/proc 等,与宿主机隔离;
UTS Namespace:通过 --hostname 设置独立主机名;
User Namespace:默认关闭,开启后容器内 root 映射为宿主机普通用户。
2.特殊模式下的 Namespace 共享
Docker 通过 --network 控制 Network Namespace 共享:
Host 模式:容器共享宿主机 Network Namespace,直接使用宿主机 IP / 端口;
Container 模式:新容器共享指定容器的 Network Namespace(如 docker run --network container:nginx);
None 模式:容器仅保留 lo 网卡,完全隔离网络。
五、Namespace 与其他容器技术的协同
Namespace 需与 CGroup、Rootfs 协同,才能实现完整的容器功能:
|
技术组件 |
核心作用 |
与 Namespace 的协同关系 |
|
Namespace |
资源隔离 |
实现容器 “独立资源视野”,是容器的基础 |
|
CGroup |
资源限制 |
限制容器资源占用,防止容器耗尽宿主机资源 |
|
Rootfs |
文件系统隔离 |
为容器提供独立根目录,配合 Mount Namespace 隔离文件系统 |
六、Namespace 的局限性
Namespace 解决了 “隔离”,但没解决 “资源限制”—— 比如容器内的进程可能把宿主机的 CPU、内存占满。
这就需要 Docker 的第二个核心技术:Cgroups(Control Groups)—— 用来限制容器能使用的资源上限。
总结
Namespace 是 Docker 实现 “轻量隔离” 的核心:它用内核级的技术,让容器拥有独立的进程、网络、文件系统等资源,却不需要像虚拟机一样运行完整的操作系统。
简单说:Namespace 是容器的 “隔离围墙”,Cgroups 是容器的 “资源天花板”,UnionFS 是容器的 “文件系统底座”—— 三者结合,才构成了 Docker 的基础。
更多推荐



所有评论(0)