问答题
-
在进行容器的隔离时都用到了哪些 Namespace?
答:
cgroup:针对每个容器实现资源控制
ipc:进程间通信,容器间通信用tcp
mnt:隔离文件系统挂载点
net:隔离网络资源
pid:隔离进程
user:隔离用户和用户组
uts:隔离主机名和域名
-
请描述手工创建一个类容器对象的操作都有哪些?
答:
一、准备容器文件系统rootfs
导出基础镜像、解压文件系统、测试根文件系统
二、用namespace进行资源隔离
用unshare创建多个独立命名空间
三、配置容器内环境
挂载proc文件系统
四、配置容器网络
创建一对虚拟网卡、启用网卡、把容器端网卡移到容器网络命名空间
一、Namespace是什么?
Namespace是Linux内核提供的资源隔离机制,我们可以把它理解成系统资源的独立隔间。同一台宿主机上,不同Namespace内的进程,会看到完全独立的进程列表、文件系统、网络、主机名等资源,互相不可见,天然实现隔离,这是容器能"假装独立服务器"的根本。
二、容器使用的6大Namespace详细拆解
1. PID Namespace(进程隔离)
作用:隔离进程ID。宿主机和容器拥有两套完全独立的PID编号。
举个例子:宿主机中bash进程PID是20480,但进入新PID命名空间后,这个bash会变成PID=1。容器内部看不到宿主机的所有进程,宿主机也只能通过特殊接口查看容器内进程,避免容器进程误操作宿主机服务。
2. Mnt Namespace(文件挂载隔离)
作用:隔离文件系统挂载点,每个容器拥有独立根文件系统视图。
宿主机挂载的磁盘、目录,默认不会出现在容器内;容器内的文件、挂载目录,宿主机虽能底层访问,但容器进程只能看到专属rootfs,实现文件环境隔离,也是chroot底层依赖的能力。
3. Net Namespace(网络隔离)
作用:隔离网络栈,包含网卡、路由表、iptables、端口、socket连接。
每个容器拥有独立lo回环网卡,可单独创建veth虚拟网卡、配置独立IP。不同Net Namespace端口完全互不冲突,容器默认看不到宿主机网卡,实现网络环境隔离。
4. UTS Namespace(主机名/域名隔离)
作用:隔离主机名、域名配置。
宿主机主机名是cka-worker,容器内部可以单独修改为container-01,互不影响,解决多容器统一主机名冲突问题。
5. IPC Namespace(进程通信隔离)
作用:隔离进程间通信资源,包含消息队列、共享内存、信号量。
默认不同容器无法通过共享内存、消息队列互相通信,只有手动共享IPC命名空间才能互通,提升容器安全边界。
6. User Namespace(用户/用户组ID隔离)
作用:隔离UID、GID用户编号,实现权限映射。
容器内root(UID=0),映射到宿主机普通非root用户。就算容器被恶意入侵,攻击者拿到容器root权限,在宿主机上也只是普通用户,无法破坏宿主机系统,大幅提升容器安全性。
三、仅使用chroot:只能实现基础文件隔离(存在巨大缺陷)
很多初学者会误以为chroot就是容器,实际它仅仅只能切换进程的根目录,没有任何Namespace隔离能力,我们通过实操理解它的短板:
- 导出容器镜像的rootfs文件系统,解压到本地自定义目录;
- 使用
chroot rootfs ash切换程序根目录到解压后的容器文件系统。
核心缺陷:无任何资源隔离
-
网络:执行ip link,能直接看到宿主机所有物理网卡、docker网桥、veth设备;
-
进程:执行ps -ef,能看到宿主机全部系统进程、其他容器进程;
-
主机名、用户权限、进程通信完全和宿主机共享,安全隔离完全失效。
简单总结:chroot只是改了"文件夹起点",做不到真正环境隔离,必须搭配Namespace才能做成容器。
四、unshare命令:创建完整隔离的命名空间环境
Linux内置unshare工具,可以一键新建6类Namespace,在全新隔离环境中启动shell,模拟容器底层隔离逻辑,是手工造容器的核心命令。
完整隔离参数:unshare --mount --uts --ipc --net --pid --user --map-root-user --fork /bin/bash
- 每条
--xxx对应创建一类独立Namespace; --map-root-user:开启用户ID映射,容器内模拟root权限;--fork:新建子进程运行shell,保证PID命名空间生效。
执行命令进入新shell后,进程已经和宿主机完成隔离,但还有两步补充操作才能完善环境。
4.1 手动挂载proc虚拟文件系统,完善PID隔离
新PID Namespace默认不会自动挂载/proc目录,直接执行ps依旧读取宿主机进程列表。
执行挂载命令:mount -t proc proc /proc,挂载专属proc文件系统后,ps只能看到当前隔离空间内的进程,PID=1为当前bash,进程隔离才算完整。
4.2 手动创建veth虚拟网卡,完善网络隔离
全新Net Namespace默认只有lo回环网卡,无法和宿主机、其他隔离环境通信,需要手动创建veth pair虚拟网卡对:
- 在宿主机创建一对veth虚拟网卡;
- 将其中一端网卡移入新建的Namespace;
- 配置网卡IP、启用网卡,此时隔离环境拥有独立网卡,实现独立网络栈。
五、从零搭建简易类容器完整流程梳理
结合前面所有知识点,完整手工构建隔离容器分为5大步骤:
- 导出任意容器的rootfs文件系统,解压到宿主机自定义目录;
- 使用
unshare命令一次性创建全部6大Namespace,进入隔离shell; - 执行chroot切换程序根目录到解压好的rootfs;
- 手动挂载proc文件系统,完成进程视图隔离;
- 创建veth虚拟网卡并移入当前网络命名空间,配置独立IP。
搭建完成后,这个自制程序拥有独立进程、文件、网络、主机名环境,和Docker容器底层隔离逻辑完全一致,唯一区别是Docker做了上层封装。
六、手工容器 vs Docker容器 对比
我们手工搭建的简易容器,只实现了内核层面的隔离能力,操作繁琐、无生命周期管理;而Docker作为高层容器引擎,做了全套封装:
- 自动创建全部6种Namespace,无需手动输入unshare复杂参数;
- 自动管理overlay2分层文件系统,自动挂载rootfs;
- 自动创建veth网桥、配置端口映射、iptables转发规则;
- 集成CGroup资源限制、镜像拉取、容器启停/删除/持久化全套能力;
- 封装命令简化操作,一条
docker run替代几十条手工Linux底层命令。