1. 为什么是 Docker ?
在虚拟化发展的历程中,虚拟化技术也曾经百花齐放。但是由于种种原因,最终 Docker 成为了当前时代的容器标准。那么究竟是哪些原因让时代选择了 Docker ?本文从时代背景、技术创新、运营理念等方面进行分析,希望说明白为什么选择 Docker。
1.1. 前篇,时代需要的虚拟化
随着科技的进步与发展,硬件制作工艺的提高,计算机性能也越来也高。单台计算机性能提高后,单个业务无法使用过剩的资源导致大量的浪费,这时资源共享就成为了必然的发展趋势。
从早期的物理机到虚拟机,然后再到容器技术;以及 CPU 从单任务到多任务,然后到多核处理器,主要就是在解决资源共享问题,以及资源共享后衍生出来的安全问题、性能损耗问题以及资源隔离问题。
在20世纪60年年代,虚拟化的概念就已经产生。1961年 IBM709 机实现了分时系统,将 CPU 占用切分为多个极短(1/100sec)时间片,每一个时间片都执行着不同的任务。通过对这些时间片的轮询,这样就可以将一个 CPU 虚拟化或者伪装成为多个 CPU,并且让每一颗虚拟 CPU 看起来都是在同时运行,这就是虚拟机的雏形。
使虚拟机广泛使用是在虚拟化软件出现后,软件虚拟化的目的是使用逻辑来表示资源,从而摆脱物理限制的约束,提高物理资源的利用率。主流的虚拟化技术及软件,常见有:MWare workstation(VMWare)、VirtualBox(Oracle)、Hyper-V(Microsoft)、KVM(Redhat)、Xen、OpenStack等。其中 OpenStack 的开源与逐渐成熟,使其成为自建私有云的首选方案。
在进行虚拟化的同时引入一个比较严重的问题是,在虚拟化过程中虚拟机本身会消耗较多的资源,这部分资源消耗是无法生产业务价值的。
为了解决资源虚拟化时自身的损耗,各大厂商都想方设法来降低这部分的损耗,Xen 走半虚拟化的路,部分设备直接访问,减小性能损耗。Intel、AMD 等硬件厂商对指令集进行优化,专门给虚拟化提升性能或降低虚拟化的损耗。但效果都不太理想。
虚拟机目的都是在一台强性能的物理机上虚拟出多个互相之间完全独立的虚拟机。主要优势就是能大大提升物理资源利用率的同时,又能将不同的应用完全独立开来,能够进行资源的隔离,资源的共享。但缺点也比较明显,就是在进行虚拟化的同时会消耗大量的资源,这部分资源的消耗并没有产生任何业务价值。而容器技术刚好能够解决虚拟机的这个问题。
1.2. 中篇,Docker 的创新
容器是操作系统(一般是指 Linux)使用 Cgroup 和 Namespace 等技术进行资源隔离和限制资源,使用同一个操作系统内核又能提供一个独立进程运行环境的一种虚拟化技术。
1.2.1. 容器相比传统虚拟化的优势有哪些呢?
容器使您能够将应用程序与基础架构分开,从而可以快速交付软件。借助容器技术,您可以与管理应用程序相同的方式来管理基础架构。通过利用容器的方法来快速交付,测试和部署代码,您可以大大减少编写代码和在生产环境中运行代码之间的延迟。
- 快速,一致地交付您的应用程序
容器允许开发人员使用您提供的应用程序或服务的本地容器在标准化环境中工作,从而简化了开发的生命周期。
容器非常适合持续集成和持续交付(CI / CD)工作流程,请考虑以下示例方案:
您的开发人员在本地编写代码,并使用容器与同事共享他们的工作。 他们使用容器将其应用程序推送到测试环境中,并执行自动或手动测试。 当开发人员发现错误时,他们可以在开发环境中对其进行修复,然后将其重新部署到测试环境中,以进行测试和验证。 测试完成后,将修补程序推送给生产环境,就像将更新的镜像推送到生产环境一样简单。
- 响应式部署和扩展
容器可以在开发人员的本机上,数据中心的物理或虚拟机上,云服务上或混合环境中运行。
容器的可移植性和轻量级的特性,还可以使您轻松地完成动态管理的工作负担,并根据业务需求指示,实时扩展或拆除应用程序和服务。
- 在同一硬件上运行更多工作负载
容器轻巧快速。它为基于虚拟机管理程序的虚拟机提供了可行、经济、高效的替代方案,因此您可以利用更多的计算能力来实现业务目标。容器非常适合于高密度环境以及中小型部署,而您可以用更少的资源做更多的事情。
1.2.2. 容器技术核心
支持容器技术的底层技术主要有 Cgroup、Namespace、UnionFS,正是因为有了这些技术才能让容器虚拟化成为了可能。
- Cgroup
Linux CGroup 全称 Linux Control Group, 是 Linux 内核的一个功能,用来限制,控制与分离一个进程组群的资源(如 CPU、内存、磁盘输入输出等)。这个项目最早是由 Google 的工程师在2006年发起(主要是 Paul Menage 和 Rohit Seth),最早的名称为进程容器(process containers)。在2007年时,因为在 Linux 内核中,容器(container)这个名词太过广泛,为避免混乱,被重命名为 cgroup,并且被合并到2.6.24版的内核中去。
Linux CGroup 为系统中所运行任务(进程)的用户定义组群分配资源 — 比如 CPU 时间、系统内存、网络带宽或者这些资源的组合。您可以监控您配置的 cgroup,拒绝 cgroup 访问某些资源,甚至在运行的系统中动态配置您的 cgroup。
主要提供了如下功能:
- Resource limitation: 限制资源使用,比如内存使用上限以及文件系统的缓存限制。
- Prioritization: 优先级控制,比如:CPU 利用和磁盘 IO 吞吐。
- Accounting: 一些审计或一些统计,主要目的是为了计费。
- Control: 挂起进程,恢复执行进程。
使用 cgroup,系统管理员可更具体地控制对系统资源的分配、优先顺序、拒绝、管理和监控。可更好地根据任务和用户分配硬件资源,提高总体效率。
Linux 的 Cgroup 具有不同功能的子系统:
- cpu 子系统,主要限制进程的 cpu 使用率。
- cpuacct 子系统,可以统计 cgroups 中的进程的 cpu 使用报告。
- cpuset 子系统,可以为 cgroups 中的进程分配单独的 cpu 节点或者内存节点。
- memory 子系统,可以限制进程的 memory 使用量。
- blkio 子系统,可以限制进程的块设备 io。
- devices 子系统,可以控制进程能够访问某些设备。
- net_cls 子系统,可以标记 cgroups 中进程的网络数据包,然后可以使用 tc 模块(traffic control)对数据包进行控制。
- freezer 子系统,可以挂起或者恢复 cgroups 中的进程。
ns 子系统,可以使不同 cgroups 下面的进程使用不同的 namespace。
Namespace
Linux Namespaces机制提供一种资源隔离方案。PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace。每个Namespace里面的资源对其他Namespace都是透明的。要创建新的Namespace,只需要在调用clone时指定相应的flag。Linux Namespaces机制为实现基于容器的虚拟化技术提供了很好的基础,LXC(Linux containers)就是利用这一特性实现了资源的隔离。不同container内的进程属于不同的Namespace,彼此透明,互不干扰。
Linux 中使用多种 Namespace 进行系统资源的管理,目前支持:
分类 | 系统调用参数 | 相关内核版本 | 描述 |
---|---|---|---|
Mount namespaces | CLONE_NEWNS | Linux 2.4.19 | 隔离文件系统挂载点 |
UTS namespaces | CLONE_NEWUTS | Linux 2.6.19 | 隔离主机名和域名信息 |
IPC namespaces | CLONE_NEWIPC | Linux 2.6.19 | 隔离进程间通信 |
PID namespaces | CLONE_NEWPID | Linux 2.6.24 | 隔离进程的ID |
Network namespaces | CLONE_NEWNET | 始于Linux 2.6.24 完成于 Linux 2.6.29 | 隔离网络资源 |
User namespaces | CLONE_NEWUSER | 始于 Linux 2.6.23 完成于 Linux 3.8) | 隔离用户和用户组的ID |
- UnionFS
UnionFS 是一种为 Linux,FreeBSD 和 NetBSD 操作系统设计的把其他文件系统联合到一个联合挂载点的文件系统服务。它使用 branch 把不同文件系统的文件和目录“透明地”覆盖,形成一个单一一致的文件系统。这些 branches 或者是 read-only 或者是 read-write 的,所以当对这个虚拟后的联合文件系统进行写操作的时候,系统是真正写到了一个新的文件中。看起来这个虚拟后的联合文件系统是可以对任何文件进行操作的,但是其实它并没有改变原来的文件,这是因为 unionfs 用到了一个重要的资管管理技术叫写时复制。
写时复制(copy-on-write,简称 CoW ),也叫隐式共享,是一种对可修改资源实现高效复制的资源管理技术。它的思想是,如果一个资源是重复的,但没有任何修改,这时候并不需要立即创建一个新的资源;这个资源可以被新旧实例共享。创建新资源发生在第一次写操作,也就是对资源进行修改的时候。通过这种资源共享的方式,可以显著地减少未修改资源复制带来的消耗,但是也会在进行资源修改的时候增减小部分的开销。
1.2.3. Docker 的创新
容器技术虽然解决了虚拟化本身的损耗问题,但是有很长一段时间没有成为主流。主要原因是不好用,学习和使用成本比较高,直到 Docker 的出现。
Docker 并不是新技术,而是使用了一种创新的方式来时整合使用已有的技术。Linux 命名空间、控制组和 UnionFS 三大技术支撑了目前 Docker 的实现。
优秀的工具 docker 软件将虚拟化的技术进行封装了人们常用的指令工具,屏蔽了底层 Cgroup、Namespace、UnionFS等具体的技术细节,使其推广和使用成本大大降低。
打包方式
因此, Docker 是站在巨人的肩膀上伟大。在技术上的优势并不能直接使 Docker 成为主流,Uninx 系统就是一个很好的例子,一款开源软件能否在商业上成功,很大程度上依赖三件事 - 成功的 user case(用例), 活跃的社区和一个好故事。 dotCloud 之家的 PaaS 产品建立在docker之上,长期维护且有大量的用户,社区也十分活跃,接下来我们看看docker的故事。
1.3. 尾篇,开源铸就伟大
Docker 的开源让全球的开发都能贡献代码来不断的完善这一产品。
Docker 相比其他容器技术的优势
- 虚拟化的抽象使用方式
- 软件打包方式,docker镜像
- 开发的生态
1.4. 终章
docker 设想是交付运行环境如同海运,OS如同一个货轮,每一个在OS基础上的软件都如同一个集装箱,用户可以通过标准化手段自由组装运行环境,同时集装箱的内容可以由用户自定义,也可以由专业人员制造。这样,交付一个软件,就是一系列标准化组件的集合的交付,如同乐高积木,用户只需要选择合适的积木组合,并且在最顶端署上自己的名字(最后一个标准化组件是用户的app)。这也就是基于docker的PaaS产品的原型。
Docker 的出现很好的体现了天时、地利、人和的强大之处。
容器出现后,容器的管理也曾经有多辉煌的三剑客,而随着 Kubernetes 的独领风骚,容器成了更基础的存在。容器也出现了多个新的竞争对手,同时 Docker 的 Containerd 和 RunC 的独立拆分,完整的 Docker 并非必选。
2021年 Kubernetes 发布 v1.20 版本(还是v1.21??) 同时发布在 V1.22 版本默认不使用 Docker 作为其默认的运行时,届时 Docker 依然可用,但或许不是最佳的推荐。
回收 Docker 历史,从一枝独秀称霸容器世界,成为容器的事实上的标准,可预见的是 Docker 在 2020 年或许就是巅峰。下一个焦点将会是 Kubernetes 。