喜迎周三
让我们在一个舒缓的 BGM 中开始今日话题 Docker Namespaces
前情提要
随着现在云原生蓬勃发展,Docker 成为每个技术伙伴必须要掌握的一项技能,当然小白手套也不例外,有天小白手套想,为什么每次容器运行起来,不管我在当前容器内怎么修改,对于同样运行在宿主机的其他容器毫无影响,同时,我也看不到其他容器中的内容,它究竟是怎么做到的,本章让我们跟随小白手套走进 NameSpace 的世界。
主角介绍
- 小李-某司技术一把手,年纪轻轻,财务自由,开小米 SU7
- 小白手套-某司技术 家财万贯,只为体验生活,上级小李,开法拉利
什么是 Namespaces
参考维基百科对 Namespaces 的定义
大致意思是:
- 命名空间是 Linux 的一个功能,它对内核资源进行分区,便于一组进程看到一组资源,另一组进程看到另一组资源。
- 它的工作原理是一组资源和进程使用相同的命名空间,但这些命名空间引用不同的资源。
用大白话翻译过可以这样理解:
- 我有一台 Windows 电脑,电脑上我可以有多个用户,比如 玩游戏的用户 Game 、打工的用户 Work、看电影的用户 Video
- 切换到不同的用户,他们都有共同的文件夹 Document,但 Document 内相同的文件名彼此不会冲突,互不干扰。
Linux 命名空间是 2002 年 2.4.19 内核开始,主要针对挂载命名空间的类型,从 2006 年开始持续至今。
Linux 内核 5.6 开始 支持 8 种命名空间
命名空间 | 隔离资源 |
---|---|
Mount (mnt) | 隔离挂载点 |
Process ID (pid) | 隔离进程 |
Network (net) | 隔离网络 |
Inter-process Communication (ipc) | 隔离进程与商业版 Unix System V |
UTS | 隔离主机名和域名 |
User ID (user) | 隔离用户 |
Control group (cgroup) Namespace | 隔离CPU、内存等 |
Time Namespace | 隔离系统时间 |
华为工程师瑞翔提出 syslog namespace,并没有合并到 linux 内核
实战 Namespaces
unshare
命令是 Linux 中的一个命令行工具,用于在新的命名空间中执行命令。它允许你将进程从当前的命名空间中分离出来,使得它在一个新的、隔离的环境中运行。
unshare
命令的基本用法:
css
cssCopy code
unshare [options] [command [args...]]
options
: 是一些控制命名空间的选项。command
: 是在新的命名空间中执行的命令。args...
: 是命令的参数。
一些常见的选项包括:
-m
或--mount[=mount_options]
:创建新的挂载命名空间。-u
或--uts[=utsname]
:创建新的 UTS 命名空间,用于修改系统主机名。-n
或--net[=hostname]
:创建新的网络命名空间。-i
或--ipc
:创建新的 IPC 命名空间。
Mnt
Mount Namespace
创建后,当前挂载命名空间中的挂载将复制到新命名空间,但随后创建的挂载点不会在命名空间之间传播(使用共享子树,可以在命名空间之间传播挂载点)。
我们的操作
- 首先,在宿主机创建一个
mount namespace
,并且访问创建好的 mount namespace
bash
unshare --mount --fork /bin/bash
- 然后,在 mount namespace 中创建挂载目录,并查看 namespace 信息
bash
mkdir -p /maomao/mount
bash
mount -t tmpfs -o size=10m tmpfs /maomao/mount
bash
df -h
bash
ls -l /proc/self/ns/
可以看到已经成功挂载,关注 namespace mount id
- 最后,在主机上检查是否存在挂载目录
bash
df -h
bash
ls -l /proc/self/ns/
可以看到,宿主机是不存在 maomao/mount 这个挂载目录的,并且 mnt id 也是不一致的
Pid
Process ID Namespace
不同 Process ID Namespace 中 PID 号是可以相同的
在 PID 命名空间中创建的第一个进程被分配进程 ID 号 1,并接受与正常init进程相同的大部分特殊处理,最值得注意的是命名空间内的孤立进程附加到它。这也意味着终止此 PID 1 进程将立即终止其 PID 命名空间中的所有进程及其任何后代.
- 首先在宿主机上创建一个 Porcess ID Namespace
bash
unshare --pid --fork --mount-proc /bin/bash
- 查看宿主机进程
Net
Network Namespace
- 网络命名空间虚拟化网络堆栈。创建时,网络命名空间仅包含一个环回接口。
- 每个命名空间都有一组私有IP 地址、自己的路由表、套接字列表、连接跟踪表、防火墙和其他网络相关资源。
- 首先,创建一个 Net Namesapce,并查看网络信息
bash
unshare --net --fork /bin/bash
- 然后查看宿主机网络
Ipc
Inter-process Communication Namespace
PC 命名空间将进程与 SysV 样式的进程间通信隔离。这可以防止不同 IPC 命名空间中的进程使用 SHM 系列函数等在两个进程之间建立一系列共享内存。相反,每个进程将能够对共享内存区域使用相同的标识符,并生成两个这样的不同区域。
- 首先创建一个 IPC Namespace
bash
unshare --ipc --fork /bin/bash
- 然后查看 Namespace 中当前系统通信队列列表,如果没有队列就给它创建一个,
- 最后到宿主机查看通信队列,可以看到已经实现隔离
UTS
UTS Namespace
允许单个系统对于不同的进程看起来具有不同的主机名
- 首先,创建一个 UTS Namespace 命名空间,并设置主机名
bash
unshare --uts --fork /bin/bash
- 然后查看宿主机主机名
User
User ID Namespace
为了促进管理操作的权限隔离,每个命名空间类型都被视为由基于创建时活动用户命名空间的用户命名空间拥有。在适当的用户命名空间中具有管理权限的用户将被允许在其他命名空间类型中执行管理操作。
如果进程具有更改网络接口的 IP 地址的管理权限,则只要其自己的用户命名空间与拥有该网络命名空间的用户命名空间相同(或其祖先),它就可以这样做。因此,初始用户命名空间对系统中的所有命名空间类型具有管理控制权。
非 root 权限就可以创建 user namespace
- 首先,创建一个 User ID Namespace
bash
unshare --user -r /bin/bash
- 然后,在宿主机用普通用户执行高权限命令
小白手套靓照
结语
尽情享受技术带来的乐趣吧,祝你好运。
参考文献: