01-docker原理-03-namespace的六项隔离

1. 概述

Namespace系统调用参数隔离内容
UTSCLONE_NEWUTS主机名与域名
IPCCLONE_NEWIPC信号量、消息队列和共享内存
PIDCLONE_NEWPID进程编号
NetworkCLONE_NEWNET网络设备、网络栈、端口等等
MountCLONE_NEWNS挂载点(文件系统)
UserCLONE_NEWUSER用户和用户组

2. namespace的API

包括 clone()、setns() 以及 unshare(),还有 /proc 下的部分文件

  • clone()

作用:创建新进程的同时创建 namespace

  • setns()

作用:加入一个已经存在的 namespace

  • unshare()

作用:在原先进程上进行 namespace 隔离

image.jpeg

  • /proc/ 下的文件

在 /proc/[pid号]/ns 目录下看到指向不同 namespace 号的文件

如果两个进程指向的 namespace 编号相同,就说明他们在同一个 namespace 下,否则则在不同 namespace 里面。

3. 六项隔离

3.1 UTS(UNIX Time-sharing System)

提供主机名和域名的隔离,在网络上可以被视作一个独立的节点而非宿主机上的一个进程。

3.2 IPC(Interprocess Communication)进程间通信

容器中进程间通信采用的方法包括常见的信号量、消息队列和共享内存。然而与虚拟机不同的是,容器内部进程间通信对宿主机来说,实际上是具有相同 PID namespace 中的进程间通信,因此需要一个唯一的标识符来进行区别。申请 IPC 资源就申请了这样一个全局唯一的 32 位 ID,所以 IPC namespace 中实际上包含了系统 IPC 标识符以及实现 POSIX 消息队列的文件系统。在同一个 IPC namespace 下的进程彼此可见,而与其他的 IPC namespace 下的进程则互相不可见。

3.3 PID namespace

对进程 PID 重新标号
两个不同 namespace 下的进程可以有相同 PID号。

3.3.1 PID namespace 的树状结构

内核为所有的 PID namespace 维护了一个树状结构:

  • 最顶层的是系统初始时创建的 root namespace。
  • 父进程可以创建的新的 child namespace。
    所属的父节点可以看到子节点中的进程,并可以通过信号等方式对子节点中的进程产生影响。
  • 反过来,子节点不能看到父节点 PID namespace 中的任何内容。

3.3.2 PID namespace 中的 init 进程

dockerinit:Docker 启动时的第一个进程,实现了进程监控和资源回收。

当我们新建一个 PID namespace 时,默认启动的进程 PID 为 1。我们知道,在传统的 UNIX 系统中,PID 为 1 的进程是 init,地位非常特殊。他作为所有进程的父进程,维护一张进程表,不断检查进程的状态,一旦有某个子进程因为程序错误成为了“孤儿”进程,init 就会负责回收资源并结束这个子进程。所以在你要实现的容器中,启动的第一个进程也需要实现类似 init 的功能,维护所有后续启动进程的运行状态。

看到这里,可能读者已经明白了内核设计的良苦用心。PID namespace 维护这样一个树状结构,非常有利于系统的资源监控与回收。Docker 启动时,第一个进程也是这样,实现了进程监控和资源回收,它就是 dockerinit。

3.3.3 信号与 init 进程

  • 信号屏蔽
    无特出情况,发送给PID namespace 中的 init 进程的信号都会被屏蔽。这个功能的主要作用是防止 init 进程被误杀。
    父节点中的进程发送的信号, 除SIGKILLSIGSTOP会被子节点的 init 会强制执行,其他信号也将被忽略。

  • 不存在没有进程的docker

一旦 init 进程被销毁,同一 PID namespace 中的其他进程也会随之接收到 SIGKILL 信号而被销毁。理论上,该 PID namespace 自然也就不复存在了。

因此我们说:Docker 一旦启动就有进程在运行,不存在不包含任何进程的 Docker,也就是这个道理。

3.3.4 挂载 proc 文件系统

只看到两个进程,一个是ps的,一个是进入容器的bash,可见隔离是对的。

image.jpeg

3.4 Mount namespaces

通过隔离文件系统挂载点对隔离文件系统提供支持,它是历史上第一个 Linux namespace。

3.5 Network namespace

  • 作用
    提供了关于网络资源的隔离(包括网络设备、IPv4 和 IPv6 协议栈、IP 路由表、防火墙、/proc/net 目录、/sys/class/net 目录、端口等等)。

  • 机制
    一个物理的网络设备最多存在在一个 network namespace 中。
    可以通过创建 veth pair在不同的 network namespace 间创建通道,以此达到通信的目的。

veth pair:(虚拟网络设备对)有两端,类似管道,如果数据从一端传入另一端也能接收到。

image.jpeg

※ 注意:如果你有多块物理网卡,其中一块给某个network namespace ,而该network namespace被释放时(所有内部的进程都终止并且 namespace 文件没有被挂载或打开),其中的物理网卡会返回到 root namespace 而非创建该进程的父进程所在的 network namespace。

3.6 User namespaces

主要隔离了安全相关的标识符(identifiers)和属性(attributes),包括用户 ID、用户组 ID、root 目录、key(指密钥)以及特殊权限。

是目前的六个 namespace 中最后一个支持的

posted on 2021-09-14 19:43  运维开发玄德公  阅读(10)  评论(0编辑  收藏  举报  来源

导航