1. Docker背后的内核知识

用一句话来概括docker的实现原理即:docker通过namespace实现了资源隔离,通过cgroup实现了资源限制,通过写时复制机制(copy-on-wirite)实现了高效的文件操作。

接下来我们更加细致的来看看原理细节。

2. namespace资源隔离

做资源隔离主要涉及6项隔离。linux内核中6种namespace隔离的系统调用如下:

Namespace 系统调用参数 隔离内容
UTS CLONE_NEWUTS 主机名与域名
IPC CLONE_NEWIPC 信号量、消息队列和共享内存
PID CLONE_NEWPID 进程编号
Network CLONE_NEWNET 网络设备、网络栈、端口等等
Mount CLONE_NEWNS 挂载点(文件系统)
User CLONE_NEWUSER 用户和用户组

namespace会提供相关API来操作系统调用(clone()、setns()、unshare()方法等等)。

3 cgroups资源隔离

cgroups(control group)也是LINUX内核提供的机制。其功能主要为:

  1. 资源限制:可以对任务使用的资源总额进行限制。比如内存上限。
  2. 优先级分配: 分配CPU时间片数量和磁盘IO带宽大小
  3. 资源统计: 云服务计费用这个就很好
  4. 任务控制:对任务执行挂起、恢复等操作。

cgroup的相关术语:

  1. task(任务):cgroups的术语中,task就表示系统的一个进程。
  2. cgroup(控制组):cgroups 中的资源控制都以cgroup为单位实现。cgroup表示按某种资源控制标准划分而成的任务组,包含一个或多个子系统。一个任务可以加入某个cgroup,也可以从某个cgroup迁移到另外一个cgroup。
  3. subsystem(子系统):cgroups中的subsystem就是一个资源调度控制器(Resource Controller)。比如CPU子系统可以控制CPU时间分配,内存子系统可以限制cgroup内存使用量。
  4. hierarchy(层级树):hierarchy由一系列cgroup以一个树状结构排列而成,每个hierarchy通过绑定对应的subsystem进行资源调度。hierarchy中的cgroup节点可以包含零或多个子节点,子节点继承父节点的属性。整个系统可以有多个hierarchy。

3.1 子系统简介

子系统就是cgroups的资源控制系统,每种子系统独立地控制一种资源。目前内核有以下9种子系统,docker用前8种:
blkio: 这个subsystem可以为块设备设定输入/输出限制,比如物理驱动设备(包括磁盘、固态硬盘、USB等)。
cpu: 这个subsystem使用调度程序控制task对CPU的使用。
cpuacct: 这个subsystem自动生成cgroup中task对CPU资源使用情况的报告。
cpuset: 这个subsystem可以为cgroup中的task分配独立的CPU(此处针对多处理器系统)和内存。
devices 这个subsystem可以开启或关闭cgroup中task对设备的访问。
freezer 这个subsystem可以挂起或恢复cgroup中的task。
memory 这个subsystem可以设定cgroup中task对内存使用量的限定,并且自动生成这些task对内存资源使用情况的报告。
perfevent 这个subsystem使用后使得cgroup中的task可以进行统一的性能测试。{![perf: Linux CPU性能探测器,详见https://perf.wiki.kernel.org/index.php/MainPage]}
*net_cls 这个subsystem Docker没有直接使用,它通过使用等级识别符(classid)标记网络数据包,从而允许 Linux 流量控制程序(TC:Traffic Controller)识别从具体cgroup中生成的数据包。

3.2 cgroups实现本质

cgroups的实现本质上是给系统进程挂上钩子(hooks),当task运行的过程中涉及到某个资源时就会触发钩子上所附带的subsystem进行检测,最终根据资源类别的不同使用对应的技术进行资源限制和优先级分配。

4 docker架构概览

PS: libcontainer和libnetwork已经成为单独的项目

docker采用传统的CS架构模式,用户通过docker client和docker daemon建立通信。上图是docker server部分,是一个松耦合的结构。上图中docker daemon提供了主要的docker用户API。

4.1 driver

docker架构图中各个driver主要负责对系统调用做一些抽象,方便docker client调用。

4.2 client和daemon

docker命令后面可以接参数daemon或者其他参数。只有daemon参数会启动daemon模式,创建一个daemon进程。

  1. client模式:
  2. daemon模式: 会创建一个运行在宿主机的daemon进程

P56到P76讲解了两种模式如何初始化的过程。

5. docker镜像

docker镜像有很多特点,其中写时复制这个特点很重要。多个容器之间是共享镜像的。镜像层上面抽象了一层可读写的容器层。只有发生写的时候,才会把变化的文件内容反映到可读写的容器层。

5.1 docker镜像的存储组织方式

5.2 docker镜像关键概念

  1. registry: 容器需要依靠docker镜像来生成。docker镜像的仓库服务。类似docker hub 就是一个registry服务
  2. repository: 这个注意区分registry。指的是具有指定功能的一组镜像。例如ubuntu repository下面有很多ubuntu相关的镜像。
  3. manifest: 描述文件,是docker镜像的元数据
  4. image和layer
  5. Dockerfile: docker镜像的定义文件,给docker build用的。

5.3 docker镜像构建操作

  1. commit:将容器提交为镜像
  2. build构建镜像