Namespace是Linux内核的一项功能,该功能对内核资源进行分区,以使一组进程看到一组资源,而另一组进程看到另一组资源。 Namespace的工作方式通过为一组资源和进程设置相同的Namespace而起作用,但是这些Namespace引用了不同的资源。 资源可能存在于多个Namespace中。这些资源可以是进程ID、主机名、用户ID、文件名、与网络访问相关的名称和进程间通信。
隔离不同的进程或进程组看到的挂载点,实现容器内只能看到自己的挂载信息,在容器内的挂载操作不会影响主机的挂载目录。
1.2 PID NamespacePID Namespace 的作用是用来隔离进程的,例如一个进程在主机上的PID为122,使用PID Namespace可以实现该进程在容器内看到的PID为1
1.3 UTS NamespaceUTS Namespace主要是用来隔离主机名的,它允许每个UTS Namespace拥有一个独立主机名。
1.4 IPC NamespaceIPC Namespace 主要是用来隔离进程间通信的,PID Namespace和IPC Namespace 一起使用可以实现同一IPC Namespace 内的进程彼此可以通信, 不同IPC Namespace 的进程却不能通信
1.5 User NamespaceUser Namespace 主要是用来隔离用户和用户组的,使用 User Namespace 可以实现进程在容器内拥有 root 权限,而在主机上却只是普通用户
1.6 Net NamespaceNet Namespace 用来隔离网络设备、IP 地址和端口等信息,Net Namespace 可以让每个进程拥有自己独立的 IP 地址,端口和网卡信息 例如主机 IP 地址为 172.16.4.1,容器内可以是指独立的 IP 地址为192.168.1.1
为什么Docker需要Namespace
Linux内核从 2002 年 2.4.19 版本开始加入了 Mount Namespace 内核 3.8 版本加入了 User Namespace 为容器提供了足够的支持功能 当一个Docker 新建一个容器时会创建这六种 Namespace,然后将容器中的进程加入这些 Namespace之中。 Namespace 是Linux内核的一个特性,可以实现在同一主机系统中对进程 ID、主机名、用户 ID、文件名、网络和进程间通信等资源的隔离。
二、Docker 的cgroups原理我们可以知道使用不同的Namespace,可以实现容器中的进程看不到别的容器的资源,但是容器内的进程仍然可以任意地使用主机的CPU、内存等资源, 如果某一个容器使用的主机资源过多,可能导致主机的资源竞争,进而影响业务。这里就需要使用到Linux内核的另一个核心技术 cgroups。
cgroups(全称:control groups)是 Linux 内核的一个功能,它可以实现限制进程或者进程组的资源(如 CPU、内存、磁盘 IO 等)。
2.1 cgroups 功能及核心概念cgroups 主要提供了如下功能:
- 资源限制:限制资源的使用量,例如可以通过限制某个业务的内存上限,从而保护主机其他业务的安全运行。
- 优先级控制:不同的组可以有不同的资源(CPU、磁盘 IO 等)使用优先级
- 审计:计算控制组的资源使用情况
- 控制:控制进程的挂起或恢复
cgroup功能的实现依赖与三个核心概念:子系统、控制组、层级树。
- 子系统(subsystem):是一个内核组件,一个子系统代表一类资源调度控制器。例如内存子系统可以限制内存的使用量, CPU 子系统可以限制 CPU 的使用时间。
- 控制组(cgroup):标志一组进程和一组带有参数的子系统的关联关系。例如,一个进程使用了CPU子系统来限制CPU的使用时间, 则这个进程和CPU子系统的关联关系称为控制组。
- 层级树(hierarchy):是由一系列的控制组按照树状结构排列组成的。这种排列方式可以使得控制组拥有父子关系, 子控制组默认拥有父控制组的属性,也就是子控制组会继承于父控制组。比如,系统中定义了一个控制组 c1,限制了 CPU 可以使用 1 核, 然后另外一个控制组 c2 想实现既限制 CPU 使用 1 核,同时限制内存使用 2G,那么 c2 就可以直接继承 c1,无须重复定义 CPU 限制。
cgroups 的这三个核心概念中,子系统是最核心的概念,因为子系统是真正实现某类资源限制的基础。
2.2 Docker是如何使用cgroups# 首先,我们使用以下命令创建一个 nginx 容器:
docker run -it -m=1g nginx
# 上述命令创建并启动了一个 nginx 容器,并且限制内存为 1G。然后我们进入 cgroups 内存子系统的目录,
# 使用 ls 命令查看一下该目录下的内容:
ls -l /sys/fs/cgroup/memory
# 通过上面输出可以看到,该目录下有一个 docker 目录,该目录正是 Docker 在内存子系统下创建的。
# 我们进入到 docker 目录下查看一下相关内容:
# 可以看到 docker 的目录下有一个一串随机 ID 的目录,该目录即为我们上面创建的 nginx 容器的 ID。
# 然后我们进入该目录,查看一下该容器的 memory.limit_in_bytes 文件的内容。
docker cd 956ad357c45498d219a4d9bd0feae62b7cde5469790aa3afe764b948945237fa
956a...fa cat memory.limit_in_bytes
可以看到内存限制值正好为 1G。 事实上,Docker 创建容器时,Docker 会根据启动容器的参数, 在对应的 cgroups 子系统下创建以容器 ID 为名称的目录, 然后根据容器启动时设置的资源限制参数, 修改对应的 cgroups 子系统资源限制文件, 从而达到资源限制的效果。
cgroups不仅可以实现资源的限制,还可以为我们统计资源的使用情况,容器监控系统的数据来源也是cgroups提供的。 另外,cgroups虽然可以实现资源的限制,但是不能保证资源的使用。例如cgroups限制容器最多使用1核CPU,但不保证总是能使用1核CPU, 当CPU资源发生竞争时,可能会导致实际上使用的CPU资源产生竞争。
博文参考Docker高级网络实践之 玩转Linux network namespace & pipework【附源码】_甘兵_51CTO博客
2021年最新版本docker容器云详细讲解_含底层原理部分_哔哩哔哩_bilibili