Docker Container Isolation

Linux内核实现namespace的主要目的之一就是实现轻量级虚拟化(容器)服务。在同一个namespace下的进程可以感知彼此的变化,而对外界的进程一无所知。这样就可以让容器中的进程产生错觉,仿佛自己置身于一个独立的系统环境中,以达到独立和隔离的目的。

一般,Docker容器需要并且Linux内核也提供了这6种资源的namespace的隔离:

  1. UTS : 主机与域名

  2. IPC : 信号量、消息队列和共享内存

  3. PID : 进程编号

  4. NETWORK : 网络设备、网络栈、端口等

  5. Mount : 挂载点(文件系统)

  6. User : 用户和用户组

namespace理解

进入一个容器内部:

docker exec -it ad9342449b86 /bin/bash

通过ps命令查看容器内部的进程,容器内部只有两个进程在运行,看不到操作系统的其他进程,一个进程执行的/bin/bash,另外一个执行的ps,说明此刻容器被 Docker 隔离在了一个跟宿主机在不同的环境中

对于宿主机来说相当于我们在宿主机上执行一个/bin/bash的进程,宿主机给这个进程起一个独一无二名字,比如叫PID=800,用来区分与其他进程的不同,Docker在运行/bin/bash的时候,会与宿主机上的其他进程进行隔离,让他看不到其他进程运行状况,并且重新计算进程号,也就是我们看到202,但是这个进程实际上是宿主机的进程,这种技术,其实就是对被隔离应用的进程空间做了手脚,使得这些进程只能看到重新计算过的进程编号,这就是Linux里面的Namespace机制,也就是Docker采用的隔离技术。

总结一下,Namespace是Linux内核用来隔离内核资源的方式。通过Namespace可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个Namespace中。Linux Namespace是对全局系统资源的一种封装隔离,使得处于不同Namespace的进程拥有独立的全局系统资源,改变一个Namespace中的系统资源只会影响当前Namespace里的进程,对其他Namespace中的进程没有影响。

Pid namespace

用户进程是lxc-start进程的子进程,不同用户的进程就是通过pid namespace隔离开的,且不同namespace中可以有相同PID,具有以下特征:

  1. 每个namespace中的pid是有自己的pid=1的进程(类似/sbin/init进程)

  2. 每个namespace中的进程只能影响自己的同一个namespace或子namespace中的进程

  3. 因为/proc包含正在运行的进程,因此而container中的pseudo-filesystem的/proc目录只能看到自己namespace中的进程

  4. 因为namespace允许嵌套,父进程可以影响子namespace进程,所以子namespace的进程可以在父namespace中看到,但是具有不同的pid

Net namespace

有了pid namespace ,每个namespace中的pid能够相互隔离,但是网络端口还是共享host的端口。网络隔离是通过netnamespace实现的, 每个net namespace有独立的network devices, IP address, IP routing tables, /proc/net目录,这样每个container的网络就能隔离开来, LXC在此基础上有5种网络类型,docker默认采用veth的方式将container中的虚拟网卡同host上的一个docker bridge连接在一起

IPC namespace Container

进程交互还是采用linux常见的进程间交互方法(interprocess communication-IPC)包括常见的信号量、消息队列、内存共享。然而同VM不同, container的进程交互实际是host具有相同pid namespace中的进程间交互,因此需要在IPC资源申请时加入namespace信息,每个IPC资源有一个唯一的32bit ID

mnt namespace

类似chroot ,将一个进程放到一个特定的目录执行,mnt namespace允许不同namespace的进程看到的文件结构不同,这样每个namespace中的进程所看到的文件目录被隔离开了,同chroot不同,每个namespace中的container在/proc/mounts的信息只包含所在namespace 的mount point

UTS namespace

UTS(UNIX Time sharing System)namespace允许每个container拥有独立地hostname和domain name,使其在网络上被视作一个独立的节点而非Host上的一个进程

User namespace

每个container可以有不同的user和group id ,也就是说可以container内部的用户在container内部执行程序而非Host上的用户