本节我们一起来了解一下容器资源隔离性技术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:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
lsns
        NS TYPE  NPROCS   PID USER    COMMAND
4026531836 pid      138     1 root    /usr/lib/systemd/systemd --switched-root --system --deserialize 21
4026531837 user     139     1 root    /usr/lib/systemd/systemd --switched-root --system --deserialize 21
4026531838 uts      138     1 root    /usr/lib/systemd/systemd --switched-root --system --deserialize 21
4026531839 ipc      138     1 root    /usr/lib/systemd/systemd --switched-root --system --deserialize 21
4026531840 mnt      128     1 root    /usr/lib/systemd/systemd --switched-root --system --deserialize 21
4026531856 mnt        1    27 root    kdevtmpfs
4026531956 net      138     1 root    /usr/lib/systemd/systemd --switched-root --system --deserialize 21
4026532109 mnt        1   513 root    /usr/lib/systemd/systemd-udevd
4026532133 mnt        1   670 root    /usr/sbin/NetworkManager --no-daemon

要查看一个进程所属的namespace信息,可以到/proc/<pid>/ns目录下查看:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
ps -ef | grep mysqld
mysql     5662 ......

ll /proc/5662/ns
ipc -> ipc:[4026531839]
mnt -> mnt:[4026531840]
net -> net:[4026531956]
pid -> pid:[4026531836]
user -> user:[4026531837]
uts -> uts:[4026531838]

这些namespace都是链接文件, 格式为namespaceType:[inode number]。inode number则用来标识一个namespace,可以理解为namespace id。 如果两个进程的某个namespace链接文件指向同一个,则其相关资源在同一个namespace中。例如,上面的msyqld进程是直接部署在测试服务器的,现在查看该服务器上sshd进程的namespace:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
ps -ef | grep sshd
root     17114 ......

ll /proc/17114/ns
lrwxrwxrwx 1 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 net -> net:[4026531956]
lrwxrwxrwx 1 pid -> pid:[4026531836]
lrwxrwxrwx 1 user -> user:[4026531837]
lrwxrwxrwx 1 uts -> uts:[4026531838]

可以看到sshd进程和mysqld进程的各种namespace都相同。

下面还是启动一个redis的containerd容器:

1
nerdctl run -d --name redis redis:alpine3.13

查看容器进程的namespace:

1
2
3
4
5
6
lsns | grep redis
4026532170 mnt        1 16117 polkitd redis-server *:637
4026532171 uts        1 16117 polkitd redis-server *:637
4026532172 ipc        1 16117 polkitd redis-server *:637
4026532173 pid        1 16117 polkitd redis-server *:637
4026532175 net        1 16117 polkitd redis-server *:637

可以看出,启动容器后,为redis容器进程创建了单独的mtn, uts, ipc, pid, net namespace,说明容器在这些namespace的资源抽象上是隔离的。

参考