前戏

为了更好地理解容器的特性,可以刨析容器的底层实现技术。​​cgroup​​​和​​namespace​​是最重要的两种技术。cgroup实现资源限额,namespace实现资源隔离。

 cgroup

cgroup全称Control Group。Linux操作系统通过cgroup可以设置进程使用CPU、内存和IO资源的限额,例如: --cpu-shares、-m、--device-write-bps实际上就是在配置cgroup

cgroup是什么样的?我们可以在 /sys/fs/cgroup中找到它。还是用例子来说明,启动一个容器,设置 --cpu-shares=512

Docker容器底层技术_docker

查看容器的ID

Docker容器底层技术_linux_02

在 /sys/fs/cgroup/cpu/docker目录中,Linux会为每个容器创建一个cgroup目录,以容器长ID命名

Docker容器底层技术_docker_03

注:

​目录中包含所有与cpu相关的cgroup配置,文件cpu.shares保存的就是 --cpu-shares的配置,值为512。同样的,/sys/fs/cgroup/memory/docker和 /sys/fs/cgroup/blkio/docker中保存的是内存以及Block IO的cgroup配置。

namespace

简介:

在每个容器中,我们都可以看到文件系统、网卡等资源,这些资源看上去是容器自己的。拿网卡来说,每个容器都会认为自己有一块独立的网卡,即使宿主机上只有一块物理网卡。这种方式非常好,它使得容器更像一个独立的计算机。

Linux实现这种方式的技术是namespace。namespace管理着host中全局唯一的资源,并可以让每个容器都觉得只有自己在使用它。换句话说,namespace实现了容器间资源的隔离。

inux使用了6种namespace,分别对应6种资源:Mount、UTS、IPC、PID、Network和User

Mount namespace

Mount namespace让容器看上去拥有整个文件系统(用来隔离文件系统的挂载点)。容器有自己的/目录,可以执行mount和umount命令。当然我们知道这些操作只在当前容器中生效,不会影响到host和其他容器。

UTS namespace

UTS namespace让容器有自己的hostname(主机名)。默认情况下,容器的hostname是它的短ID,可以通过 -h或 --hostname参数设置

IPC namespace

IPC namespace让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而不会与host和其他容器的IPC混在一起。

PID namespace

容器在宿主机中以进程的形式运行

Docker容器底层技术_docker_04

Docker容器底层技术_linux_05

注:所有容器的进程都挂在dockerd进程下,同时也可以看到容器自己的子进程。

进程的PID不同于host中对应进程的PID,容器中PID=1的进程当然也不是host的init进程。也就是说:容器拥有自己独立的一套PID,这就是PID namespace提供的功能。

Network namespace

Network namespace让容器拥有自己独立的网卡、IP、路由等资

User namespace

User namespace让容器能够管理自己的用户,宿主机不能看到容器中创建的用户

注:在容器中创建了用户cjk,但宿主机t中并不会创建相应的用户

Docker容器底层技术_docker_06