重学容器07: 容器隔离性背后的技术namespace
2021-05-10
本节我们一起来了解一下容器资源隔离性技术namespace。 namespace即命名空间,主要用来做访问隔离,针对一类资源进行抽象封装给一个容器使用,对于这类资源,每个容器都有自己的抽象,它们之间彼此不可见实现了访问隔离,例如PID namespace用来隔离进程号,User namespace用来隔离用户和用户组。
1.linux namespace的种类 #
linux共有6种命名空间:
- IPC: IPC(信号量、消息队列、共享内存等)隔离
- Network: 网络设备、网络栈、端口等隔离
- Mount: 文件系统挂载点隔离
- PID: 进程编号隔离
- User: 用户和用户组隔离
- UTS: 主机和域名隔离
另外从linux内核4.6开始提供了第7种namespace: CGroup namespace主要用于cgroup根目录隔离。
2.查看进程所属的namespaces #
使用lsns
命令可以查看当前系统已经创建的namesapce,第一列可以理解为namespace id:
1lsns
2 NS TYPE NPROCS PID USER COMMAND
34026531836 pid 138 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 21
44026531837 user 139 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 21
54026531838 uts 138 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 21
64026531839 ipc 138 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 21
74026531840 mnt 128 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 21
84026531856 mnt 1 27 root kdevtmpfs
94026531956 net 138 1 root /usr/lib/systemd/systemd --switched-root --system --deserialize 21
104026532109 mnt 1 513 root /usr/lib/systemd/systemd-udevd
114026532133 mnt 1 670 root /usr/sbin/NetworkManager --no-daemon
要查看一个进程所属的namespace信息,可以到/proc/<pid>/ns
目录下查看:
1ps -ef | grep mysqld
2mysql 5662 ......
3
4ll /proc/5662/ns
5ipc -> ipc:[4026531839]
6mnt -> mnt:[4026531840]
7net -> net:[4026531956]
8pid -> pid:[4026531836]
9user -> user:[4026531837]
10uts -> uts:[4026531838]
这些namespace都是链接文件, 格式为namespaceType:[inode number]。inode number则用来标识一个namespace,可以理解为namespace id。 如果两个进程的某个namespace链接文件指向同一个,则其相关资源在同一个namespace中。例如,上面的msyqld进程是直接部署在测试服务器的,现在查看该服务器上sshd进程的namespace:
1ps -ef | grep sshd
2root 17114 ......
3
4ll /proc/17114/ns
5lrwxrwxrwx 1 ipc -> ipc:[4026531839]
6lrwxrwxrwx 1 mnt -> mnt:[4026531840]
7lrwxrwxrwx 1 net -> net:[4026531956]
8lrwxrwxrwx 1 pid -> pid:[4026531836]
9lrwxrwxrwx 1 user -> user:[4026531837]
10lrwxrwxrwx 1 uts -> uts:[4026531838]
可以看到sshd进程和mysqld进程的各种namespace都相同。
下面还是启动一个redis的containerd容器:
1nerdctl run -d --name redis redis:alpine3.13
查看容器进程的namespace:
1lsns | grep redis
24026532170 mnt 1 16117 polkitd redis-server *:637
34026532171 uts 1 16117 polkitd redis-server *:637
44026532172 ipc 1 16117 polkitd redis-server *:637
54026532173 pid 1 16117 polkitd redis-server *:637
64026532175 net 1 16117 polkitd redis-server *:637
可以看出,启动容器后,为redis容器进程创建了单独的mtn, uts, ipc, pid, net namespace,说明容器在这些namespace的资源抽象上是隔离的。