1.4.2 容器化的核心原理
无论LXC还是Docker,底层主要的核心技术是Cgroups、Namespace。Cgroups是Linux内核提供的一种用来限定进程资源使用的技术,可以限制和隔离进程所使用的物理资源,比如CPU、内存、磁盘和网络I/O。相对于物理资源隔离,Namespace则是用来隔离进程ID、网络等系统资源的,类似Java中的类加载器(classloader)。即使是同样的PID、同样的IP,不同的Namespace之间也是相互独立的,毫无影响。比如父容器通过调用clone()函数创建两个子进程,ID分别为100、101,这两个子进程拥有自己的Namespace,映射到子进程后,分别对应PID为1的init进程,虽然在两个Namespace里PID都为1,但是有了Namespace的隔离,两者互不影响,如图1-10所示。
图1-10 Namespace隔离图
有了隔离,子容器之间可以相对独立、互不打扰地工作。每个容器都是为了处理特定工作的,比如有的容器负责提供数据库服务,有的容器负责提供缓存服务,有的容器负责应用系统的运行。如何决定容器创建后做什么工作呢?答案是通过Dockerfile。
我把Dockerfile比作人体的DNA,它记录了容器运行的子进程,进而决定了容器的核心功能。通过Dockerfile我们可以构建镜像,随时拉起多个容器,实现应用的高速扩展。业务应用的镜像本质上都很相似,假设应用A的Dockerfile为DockerfileA,应用B的Dockerfile为DockerfileB,它们都依赖于操作系统、JDK、Tomcat、日志采集器等,只有应用的War包不一样。如果每个镜像都重复维护多个共性的部分,带来的资源损耗和维护成本都是巨大的。
Docker采用分层技术来解决这个问题,每个容器都有自己独立的容器层,不同的容器共享一个镜像层,这样容器之间就可以共享基础资源。我们保存一个基础镜像(通常称作base镜像)到磁盘后,它就可以被其他镜像共享了,如图1-11所示。
图1-11 镜像共享图
Dockerfile底层用的核心文件共享技术就是UFS。UFS是一种轻量级、高性能、分层的文件系统。UFS把文件系统的每次修改作为一个个层进行叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。如果一次同时加载多个文件系统,UFS会把各层文件叠加起来,最终文件系统会包含所有底层文件和目录,从外部视角来看,用户看到的是一个文件系统。镜像就是利用UFS的特性,通过分层来进行继承、叠加,通常我们会先制作一个基础镜像,通过基础镜像衍生出各种具体的应用镜像。UFS是Docker镜像的基础。