本节我们一起来了解一下容器资源隔离性技术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的资源抽象上是隔离的。

参考