1.Linux Namespace
namespace是Linux系统的底层概念,在内核层实现,即有一些不同类型的命名空间被部署在核内,各个docker容器运行在同一个docker主进程并且共 用同一个宿主机系统内核,各docker容器运行在宿主机的用户空间,每个容器都要有类似于虚拟机一样的相互隔离的运行空间,但是容器技术是在一个 进程内实现运行指定服务的运行环境,并且还可以保护宿主机内核不受其他进程的干扰和影响,如文件系统空间、网络空间、进程空间等,目前主要通过 以下8种技术实现容器运行空间的相互隔离.
目前,Linux已经支持8种全局资源的虚拟化(每种资源都是随着Linux内核版本的迭代而逐渐加入的,因此有些内核版本可能不具备某种namespace):
-
cgroup namespace:该namespace可单独管理自己的cgroup
-
ipc namespace:该namespace有自己的IPC,比如共享内存、信号量等
-
network namespace:该namespace有自己的网络资源,包括网络协议栈、网络设备、路由表、防火墙、端口等
-
mount namespace:该namespace有自己的挂载信息,即拥有独立的目录层次
-
pid namespace:该namespace有自己的进程号,使得namespace中的进程PID单独编号,比如可以PID=1
-
time namespace:该namespace有自己的启动时间点信息和单调时间,比如可设置某个namespace的开机时间点为1年前启动,再比如不同的namespace创建后可能流逝的时间不一样
-
user namespace:该namespace有自己的用户权限管理机制(比如独立的UID/GID),使得namespace更安全
-
uts namespace:该namepsace有自己的主机信息,包括主机名(hostname)、NIS domain name
-
2.1mount namespace
提供磁盘挂载点和文件系统的隔 离: a.每个容器都要有独立的根文件 系统有独立的用户空间,以实 现在容器里面启动服务并且使 用容器的运行环境,即一个宿 主机是ubuntu的服务器,可以 在里面启动一个centos运行环 境的容器并且在容器里面启动 一个Nginx服务,此Nginx运行 时使用的运行环境就是centos 系统目录的运行环境,即在容 器里面是不能直接访问宿主机 的文件系统。 b. 宿主机是使用了chroot技术把 容器锁定到一个指定的运行目录里面并作为容器的根运行环境。
2.2ipc namespace
clone()
系统调用 clone() 创建一个新的进程,它会根据参数中的 CLONE_NEW* 设置,逐个实现对应的配置功能。当然这个系统调用也实现了一些与 namespace 无关的功能。对低于 Linux 3.8 版本内核的系统而言,大多数情况下, 需要具备 CAP_SYS_ADMIN 的 capability。
unshare()
系统调用 unshare() 将进程分配至新的 namespace ,同样,它也会根据参数中的 CLONE_NEW* 设置来调整实现对应的配置功能。对低于 Linux 3.8 的系统而言,大多数情况,需要具备 CAP_SYS_ADMIN 的 capability。
setns()
系统调用 setns() 将进程移动到某一已存在的 namespace,这会导致 /proc/[pid]/ns 对应的目录中内容的变更。进程创建的子进程可以通过调用 unshare() 和 setns() 来调整所属的 namespace。这通常是需要具备 CAP_SYS_ADMIN 的 capability 的。
4.部分重点目录
4.1./proc/[pid]/ns/ 目录
每个进程都有一个 /proc/[pid]/ns/ 子目录,目录中的内容会受到 setns() 系统调用的影响。只要目录中的文件被打开,对应的 namespace 就不能被销毁。系统可以通过调用 setns() 来变更这些文件内容。
-
Linux 3.7 及更早期的版本 - 文件是以硬链接方式存在的;
-
Linux 3.8 开始 - 文件以软连接的方式存在;
如果两个进程的 namespace 相同,那么它们这个目录内的内容应该是一样的。
以下是该目录下文件的详细说明:
文件名称 | 起始版本 | 描述 |
---|---|---|
/proc/[pid]/ns/cgroup | Linux 4.6 | 进程的 cgroup namespace |
/proc/[pid]/ns/ipc | Linux 3.0 | 进程的 IPC namespace |
/proc/[pid]/ns/mnt | Linux 3.8 | 进程的 mount namespace |
/proc/[pid]/ns/net | Linux 3.0 | 进程的 network namespace |
/proc/[pid]/ns/pid | Linux 3.8 | 进程的 PID namespace在进程的整个生命周期里是不变的 |
/proc/[pid]/ns/pid_for_children | Linux 4.12 | 进程创建子进程的 PID namespace这个文件与 /proc/[pid]/ns/pid 不一定一致。 |
/proc/[pid]/ns/time | Linux 5.6 | 进程的 time namespace |
/proc/[pid]/ns/time_for_children | Linux 5.6 | 进程创建子进程的 time namespace |
/proc/[pid]/ns/user | Linux 3.8 | 进程的 user namespace |
/proc/[pid]/ns/uts | Linux 3.0 | 进程的 UTS namespace |
4.2./pro/sys/user 目录
/proc/sys/user 目录下的文件记录了各 namespace 的相关限制。当达到限制,相关调用会报错 error ENOSPC 。
文件名称 | 限制内容说明 |
---|---|
max_cgroup_namespaces | 在 user namespace 中的每个用户可以创建的最大 cgroup namespaces 数 |
max_ipc_namespaces | 在 user namespace 中的每个用户可以创建的最大 ipc namespaces 数 |
max_mnt_namespaces | 在 user namespace 中的每个用户可以创建的最大 mount namespaces 数 |
max_net_namespaces | 在 user namespace 中的每个用户可以创建的最大 network namespaces 数 |
max_pid_namespaces | 在 user namespace 中的每个用户可以创建的最大 PID namespaces 数 |
max_time_namespaces | Linux 5.7在 user namespace 中的每个用户可以创建的最大 time namespaces 数 |
max_user_namespaces | 在 user namespace 中的每个用户可以创建的最大 user namespaces 数 |
max_uts_namespaces | 在 user namespace 中的每个用户可以创建的最大 uts namespaces 数 |
5.namespace 的生命周期
正常的 namespace 的生命周期与最后一个进程的终止和离开相关。
但有一些情况,即使最后一个进程已经退出了,namespace 仍不能被销毁。这里来稍微聊下这些特殊的情况:
-
/proc/[pid]/ns/*
中的文件被打开或者 mount ,即使最后一个进程退出,也不能被销毁; -
namespace 存在分层,子 namespace 仍存在 ,即使最后一个进程退出,也不能被销毁;
-
一个 user namespace 拥有一些非 user namespace (比如拥有 PID namespace 等其他的 namespace 存在),即使最后一个进程退出,也不能被销毁;
-
对于 PID namespace 而言,如果与
/proc/[pid]/ns/pid_for_children
存在关联关系时,即使最后一个进程退出,也不能被销毁;
当然除此之外还有一些其他的情况,基本都是存在被占用或未被释放。