
容器技术发展史与 Docker 核心架构 目录一、容器技术发展史1. Jail 时代进程隔离的起源2. 云时代从隔离到资源控制3. 云原生时代Docker 与 K8s 的竞争与标准确立4. 编排与容器的技术演进之路二、什么是虚拟化、容器化三、为什么要虚拟化、容器化四、虚拟化的实现方式五、容器虚拟化的底层基础1. Namespace命名空间2. cgroups控制组3. LXC六、Docker 是什么1. Docker 的本质2. Docker 的引擎迭代3. Docker 与虚拟机的区别4. Docker 为什么比虚拟机资源利用率高、启动快5. Docker 与 JVM 虚拟化的区别6. Docker 的版本七、Docker 架构八、Docker 生态为什么要设计镜像和仓库一、容器技术发展史容器不是一个新概念或者新技术很早就有了只是近几年遇到了云计算整个技术被彻底引爆了。下面按时间线梳理它的演进脉络。1. Jail 时代进程隔离的起源时间事件核心贡献1979 年贝尔实验室发明chroot进程隔离的鼻祖将进程及其子进程的根目录更改为文件系统中的新位置隔离后该进程无法访问外面的文件被称为Chroot Jail监狱2000 年FreeBSD 4.0 发行FreeBSD Jail不仅有了 chroot 的文件系统隔离还扩充了独立的进程和网络空间能为每个系统分配 IP 地址2001 年Linux VServer 发行对文件系统、网络地址、内存等资源进行分区2004 年Solaris Containers 发行结合系统资源控制和区域进行隔离并添加了快照和克隆能力这个时期的进程隔离技术大多以 Jail 模式为核心基本实现了进程相关资源的隔离操作但没有更大的应用场景发展有限。2. 云时代从隔离到资源控制2006 年 Google 101 计划提出云的概念。云计算需要处理海量数据、超高并发、快速扩展等问题此时不仅仅需要隔离还需要能够对资源进行控制和调配。时间事件要点2006 年Google 推出Process Container限制、统计和隔离一组进程的资源使用CPU、内存、磁盘 I/O、网络一年后更名为Control Groupscgroups最终合并到 Linux 内核 2.6.242008 年LXC推出Linux 容器管理器的第一个、最完整的实现使用 cgroups 和 Linux 命名空间实现无需内核补丁。同年 Google 推出 GAE并在其中使用BorgKubernetes 的前身来对容器进行编排和调度2011 年CloudFoundry 推出Warden早期使用 LXC后来替换为自己的实现直接对 Cgroups 及 Linux Namespace 操作2013 年LMCTFY启动Google 容器堆栈的开源版本后因 Google 与 Docker 合作转向 libcontainer于 2015 年停止2013 年Docker 推出风靡全球最初是 dotCloud 公司的内部项目初期使用 LXC之后采用自研的 libcontainerDocker 与其他只做容器的项目不同它引入了一整套管理容器的生态系统高效、分层的容器镜像模型全局和本地的容器注册库清晰的 REST API、命令行等。Docker 不仅解决了容器化问题还解决了分发问题很快被各大厂商选择变成了云基础设施。3. 云原生时代Docker 与 K8s 的竞争与标准确立Docker 生态扩张后与 CoreOS 的布局产生直接竞争容器江湖逐渐分为 Google 派系和 Docker 派系行业标准的诉求越来越强烈。时间事件要点2014 年 6 月Google 发布开源容器编排引擎KubernetesK8SGoogle 内部调度系统 Borg 拥有 10 多年容器经验K8S 解决容器编排、网络、负载均衡、监控、部署、更新等问题2014 年 12 月CoreOS 发布开源容器引擎Rocketrkt与 Docker 正式分开发展2015 年Docker 推出容器集群编排组件Swarm在 Docker 1.12 及更高版本中与 Docker 引擎集成2015 年 6 月Docker 成立OCIDocker 将 Libcontainer 捐出并改名RunC交由中立基金会管理OCI 制定容器镜像格式和容器运行时规范Runtime Spec / Image Spec / Distribution Spec解决容器的构建、分发和运行问题2015 年 7 月Google 带头成立CNCF旨在构建云原生基础设施K8S 是第一个纳入的项目后续 Prometheus、ETCD 等也加入解决应用管理及容器编排问题此后 K8s 逐步成为云原生事实标准一系列标准相继确立2016 年发布 CRI 标准Container Runtime InterfaceK8s 定义的一组与容器运行时交互的接口只要实现这套接口就能对接 K8s。由于 Docker 仍是事实标准产生了dockershimK8s 对接 Docker 的 CRI 实现。2016 年 Docker 捐献 containerd从 Docker Engine 中剥离出来捐献给 CNCFGoogle 为将 containerd 加入 CRI 标准开发了 cri-containerd。2016 年 CRI-O 发布让 K8s 可以不依赖传统容器引擎如 Docker也能管理容器化工作负载。2017 年 containerd 确定作为标准 CRI各大厂商AWS、Microsoft Azure、VMware 等纷纷拥抱 K8sK8s 成为容器编排领域的绝对标准Docker 成为容器事实标准。结论Kubernetes 已成容器编排领域的绝对标准Docker 已成容器事实标准。4. 编排与容器的技术演进之路围绕容器运行时如何与 K8s 对接这一问题技术栈经历了如下演进DockerClient → RUNC Shim → CRI-Containerd → CRI-O → Containerd。其本质是不断剥离 Docker 一家独大的情况确保各厂商都能搭建自己的容器平台。以腾讯 TKE腾讯商用 K8S 产品为例生产集群支持选择 containerd 和 docker 两种运行时模式选择建议如下containerd调用链更短组件更少更稳定占用节点资源更少建议选择 containerd。以下情况仍需用 docker使用docker build/push/save/load等命令调用 docker API需要 docker compose 或 docker swarm。二、什么是虚拟化、容器化在理解 Docker 之前先弄清三个基础概念。物理机实际的服务器或计算机相对于虚拟机而言的实体计算机的称呼。它提供给虚拟机以硬件环境有时也称为宿主或寄主。虚拟化通过虚拟化技术将一台计算机虚拟为多台逻辑计算机每个逻辑计算机可运行不同的操作系统且应用程序可以在相互独立的空间内运行而互不影响从而显著提高计算机的工作效率。容器化一种虚拟化技术又称操作系统层虚拟化Operating system level virtualization将操作系统内核虚拟化允许用户空间软件实例被分割成几个独立的单元在内核中运行。这个软件实例也被称为一个容器containers。对每个实例的拥有者来说服务器程序看起来就像是自己专用的。生活类比物理机像一个庄园独立占用一块土地花园都是自己的其他人无法共享。虚拟机相当于开发商的一个楼盘一栋楼一套房子一户人家共享宅基地、小区花园和游乐设施。容器相当于在一间房子里开辟出一个又一个胶囊公寓共享卫生间、厨房、WiFi只有衣服、电脑等私人物品是自己的。三、为什么要虚拟化、容器化虚拟化和容器化的最主要目的就是资源隔离随着资源隔离的实现逐渐带来了更大的收益。收益说明资源利用率高将利用率较低的服务器资源进行整合用更少硬件资源运行更多业务降低 IT 支出和运维管理成本环境标准化一次构建随处执行。Docker 镜像提供除内核外完整的运行时环境确保应用运行环境一致性不再出现这段代码在我机器上没问题啊这类问题资源弹性伸缩根据业务情况动态调整计算、存储、网络等资源如双 11 扩容 100 个、过后收回差异化环境提供同时提供多套差异化执行环境如一个服务依赖 Ubuntu、另一个依赖 CentOS无需购买两台物理机沙箱安全在虚拟执行环境中运行不安全或不稳定软件不影响宿主系统如在容器里执行rm -rf /*不会搞死整个服务器更轻量、启动更快Docker 容器直接运行于宿主内核无需启动完整操作系统可做到秒级甚至毫秒级启动维护和扩展容易分层存储与镜像技术使重复部分复用更容易Docker Hub 提供大量官方基础镜像可直接使用或进一步定制四、虚拟化的实现方式应用程序的执行环境可分为三层硬件层提供硬件抽象包括指令集架构、硬件设备及访问接口、操作系统层提供系统调用接口管理硬件资源、程序库层提供数据结构定义及函数调用接口。基于这三分层常见虚拟化类别有类别定位原理虚拟机硬件层与操作系统层之间通过伪造硬件抽象接口将操作系统及以上的层嫁接到硬件上实现接近物理机的功能。如在一台 Windows 电脑上运行 Android 虚拟机容器操作系统层与函数库层之间通过伪造操作系统接口将函数库层以上的功能置于操作系统上。以 Docker 为例基于 Linux 的 Namespace 和 Cgroup 实现隔离容器。容器把一个个应用单独封装隔离体积比虚拟机小很多JVM 之类的虚拟机函数库层与应用程序之间在应用层与函数库层之间建立抽象层对下适配不同操作系统函数库对上提供统一运行环境主机虚拟化虚拟机根据虚拟化层是否直接位于硬件之上分为两种Type1Hypervisor 直接运行在硬件之上没有宿主操作系统直接控制硬件资源和客户机。典型如 Xen、VMware ESX。Type2Hypervisor 运行在宿主操作系统之上作为其中一个应用程序客户机是宿主机上的一个进程。如 VMware Workstation。五、容器虚拟化的底层基础容器虚拟化有别于主机虚拟化是操作系统层的虚拟化通过namespace 进行各程序的隔离加上cgroups 进行资源的控制以此来实现虚拟化。这两个能力都是 Linux 内核提供的而非 Docker 提供的。1. Namespace命名空间namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源而另外一些进程也只能看到与它们自己相关的资源两拨进程根本感觉不到对方的存在。改变一个 namespace 中的系统资源只会影响当前 namespace 里的进程对其他 namespace 中的进程没有影响。Linux 提供了三个 API 来操作 namespaceclone()、setns()和unshare()通过指定调用参数来确定隔离哪项 namespace。常用隔离参数及资源如下namespace系统调用参数被隔离的全局系统资源引入内核版本UTSCLONE_NEWUTS主机名和域名2.6.19IPCCLONE_NEWIPC信号量、消息队列和共享内存进程间通信2.6.19PIDCLONE_NEWPID进程编号2.6.24NetworkCLONE_NEWNET网络设备、网络栈、端口等2.6.29MountCLONE_NEWNS文件系统挂载点2.4.19UserCLONE_NEWUSER用户和用户组3.8这些 namespace 在容器环境下的隔离效果UTS 让每个容器拥有独立主机名IPC 使不同 IPC namespace 之间不能通信PID 让每个容器有其 PID 为 1 的 root 进程Network 让每个容器有独立的网络设备、IP、路由表、端口号Mount 让每个容器看到不同的文件系统层次结构User 让每个容器有不同的 user 和 group id。2. cgroups控制组cgroupsControl Groups是 Linux 内核提供的一种机制可以把一系列系统任务及其子任务整合到按资源划分等级的不同组内从而为系统资源管理提供一个统一框架。简单说cgroups 可以限制、记录任务组所使用的物理资源。本质上cgroups 是内核附加在程序上的一系列钩子hook通过程序运行时对资源的调度触发相应钩子达到资源追踪和限制的目的。Docker 及 K8s 中的 Pod 就使用了 cgroups 提供的资源限制能力。其主要用途包括Resource limitation限制资源使用、Prioritization优先级控制、Accounting审计统计、Control挂起/恢复进程。可控制的子系统有子系统作用blkio对块设备的 IO 进行限制cpu限制 CPU 时间片的分配cpuacct生成 cgroup 中任务占用 CPU 资源的报告cpuset分配独立的 CPU 和内存节点devices限制设备文件的创建和读写freezer暂停/恢复 cgroup 中的任务memory限制可用内存并生成资源占用报告perf_event允许 perf 观测 cgroup 中的 tasknet_cls对数据报文打类别标识符配合 tc 进行网络限制hugetlb限制内存页数量pids限制任务数量rdma限制 RDMA 资源3. LXCLXCLinuX Containers是一种操作系统层虚拟化技术为 Linux 内核容器功能提供用户空间接口将应用打包成软件容器内含应用代码以及所需操作系统核心和库。它是最早一批真正把完整容器技术用一组简易工具和模板来简化使用的方案。但 LXC 比起直接通过内核调用使用容器技术复杂程度并没有多大降低——必须学会一组 LXC 命令工具通过批量命令实现数据迁移并不容易隔离性也没有虚拟机那么强大。后来就出现了 Docker从一定程度上来说Docker 就是 LXC 的增强版。 Namespace、cgroups、LXC 的实战操作会在本系列第 7 篇详细演示此处先建立概念认知。六、Docker 是什么1. Docker 的本质Docker 本质其实是 LXC 之类的增强版它本身不是容器而是容器的易用工具。容器是 Linux 内核中的技术Docker 只是把这种技术在使用上简易普及了。Docker 早期版本的核心就是 LXC 的二次封装发行版。Docker 是基于 Go 语言实现的一个开源项目主要目标是“Build, Ship and Run Any APP, Anywhere”即通过对组件的封装、分发、部署、运行等生命周期的管理使用户的应用及其运行环境能够做到一次封装到处运行。早期 Docker 利用 LXC 做容器管理引擎但创建容器时不再使用模板安装而是通过镜像技术——把操作系统用户空间所需组件事先编排好并整体打包成一个镜像文件image集中放在仓库中。需要创建容器时Docker 调用 LXC 的lxc-create工具连接到镜像服务器下载匹配的镜像文件基于镜像启动容器。此后创建启动容器只需要docker run、docker stop即可。2. Docker 的引擎迭代阶段引擎说明早期LXC基于 LXC 容器管理引擎实现成熟期libcontainerDocker 自建的容器引擎从 0.9 版本开始替代 LXC1.10 版本彻底去除 LXC标准化runCCNCF 介入后研发的工业化标准容器引擎libcontainer 成为 runC 的核心功能模块目前新版 Docker 使用的就是 runC3. Docker 与虚拟机的区别对比项传统虚拟机Docker 容器磁盘占用几个 GB 到几十个 GB几十 MB 到几百 MBCPU/内存占用虚拟操作系统非常占用需通过虚拟层调用占用率高Docker 引擎占用资源极低直接作用于硬件资源启动速度几分钟几秒安装管理需要专门的运维技术安装、管理方便应用部署手动部署速度慢体系化部署可自动化速度快隔离性系统级别进程级别封装程度打包整个操作系统打包项目代码和依赖信息4. Docker 为什么比虚拟机资源利用率高、启动快资源利用率高Docker 有比虚拟机更少的抽象层不需要 Hypervisor 实现硬件资源虚拟化运行在 Docker 容器上的程序直接使用实际物理机的硬件资源Docker 利用的是宿主机的内核而不需要 Guest OS节省了 Guest OS 占用的资源。启动快Docker 不需要 Guest OS创建容器时不需要像虚拟机一样重新加载一个操作系统内核从而避免了寻址、加载操作系统内核返回时耗时耗资源的过程。新建虚拟机是分钟级别的而新建 Docker 容器只需要几秒钟。5. Docker 与 JVM 虚拟化的区别对比项JVMDocker 容器性能JVM 需要占用一定的 CPU 和内存基本没有损失虚拟层面基于 JVM 虚拟机更加上层基于操作系统更加通用代码无关性特定代码的执行平台运行时才存在只能支撑特定代码在 JVM 进程内执行模拟了整个操作系统静态存在可支撑任何相同平台的应用程序主机隔离性JVM 不隔离主机通过命名空间实现隔离6. Docker 的版本版本说明lxc最早的 Linux 容器技术早期 Docker 直接使用 LXC 实现底层功能libcontainerDocker 从 0.9 版本自研替代 LXC1.11 版本拆分出 runC 后成为其核心模块mobyDocker 公司发起的开源项目是 dockerd 目前使用的开源项目名称使用 containerd 作为运行时标准docker-ceDocker 开源版本Community Edition组件来自 moby、containerd 等项目。学习和使用通常指这个版本docker-eeDocker 收费版本Enterprise Edition基础组件与 ce 相同附加其他组件和功能 官网https://www.docker.com/ Docker 官方文档七、Docker 架构Docker 使用客户端-服务器C/S架构模式使用远程 API 来管理和创建 Docker 容器Docker 容器通过 Docker 镜像来创建。核心组件如下组件说明Docker 仓库Registry保存镜像可理解为代码控制中的代码仓库。Docker Hub 提供庞大的镜像集合Docker daemon服务器组件Docker 最核心的后台进程也称为守护进程Docker 客户端Client通过命令行或其他工具使用 Docker API 与守护进程通信Docker 主机Host一个物理或虚拟的机器用于执行 Docker 守护进程和容器Docker 镜像Images用于创建 Docker 容器的模板Docker 容器Container独立运行的一个或一组应用生活案例酒店入住一家人去旅游入住酒店我们就是Docker Client。酒店前台提供办理入住、退房、缴费等服务就是Docker Daemon核心服务端。酒店的宅基地和大楼是实际的服务器即Docker Host。酒店有 1000 多个房间有标间、大床房、家庭房等这就是Docker 镜像仓库。标准的豪华大床房和双人标间是Docker 镜像客户无法修改。办理入住后把个人物品带到具体房间如 9527这个可使用的房间就是Docker Container。朋友也开了同样的豪华大床房但携带物品、作息时间都不同——镜像相同容器实例各自独立。退房搬出后酒店把房间恢复成镜像原来的样子——容器销毁。八、Docker 生态为什么要设计镜像和仓库云时代对软件提出了新的诉求Docker 的镜像和仓库设计正是针对这些诉求的解决方案。1. 时代诉求数据量疯狂增长据 IDC 预测全球数据量将从 2018 年的 33ZB 增至 2025 年的 175ZB增长超过 5 倍。处理能力快速增加腾讯云全球服务器数量 100 万阿里云在全球部署了上百个数据中心服务器总规模接近 200 万台。软件需求爆发式增长研发模式从瀑布开发变为敏捷开发发布频繁且需要快速回滚软件需要方便地共享给他人环境搭建复杂、技术种类繁多每个项目组语言不同从 yum 开始一个个部署各种奇怪问题运维成本很高。2. Docker 的解决方案诉求Docker 方案处理海量数据购买大量服务器并研发对应软件代码快速分发到成百上千台服务器、共享软件搞一个中心仓库让各服务器去下载——Docker 设计了镜像仓库Docker Hub 是公共托管仓库快速安装启动、有问题回滚将 Docker 所需的所有信息设计一套软件格式把所有依赖搞进去并打上版本标签——Docker 设计了镜像不同开发环境搭建Java、C 等镜像里存放运行环境像 iPhone 内置 iOS、华为 mate 50 内置鸿蒙一样一条命令完成环境搭建