Cgroups-限制可用资源
如果应用优化得不够好,直接把CPU或内存吃光也完全不是新鲜事。但我们肯定不能容忍容器无限制地挤占宿主机的资源,甚至把宿主机搞down掉。
所以我们可以通过Linux的Cgroups(Control Groups,控制组)对某个容器可以使用的各种硬件资源设置配额。
根据wiki,Cgroups的功能包括:
- 资源限制(Resource Limitation):进程组使用的内存的上限,也包括文件系统与物理内存交换用的页缓存(Page Cache)
- 优先级分配(Prioritization):控制分配的CPU时间片数量及硬盘IO吞吐,实际上就相当于控制了进程运行的优先级
- 资源统计(Accounting):统计资源使用量,如CPU使用时长、内存用量等,主要用于计费
- 进程控制(Control):执行挂起、恢复进程组的操作
Cgroups的设置一般分为三个主要步骤:
- 创建cgroup
- 设置cgroup配额(将cpu/内存等各种子系统添加到该cgroup中)
- 将进程添加为cgroup的任务
Docker容器在启动时候会动态创建Cgroup,并在容器终止的时候删除。
容器的Cgroups相比虚拟机的优势主要在两方面:
- 资源利用率
- 性能损耗
首先从资源利用率方面来说,一部分虚拟化技术只能静态分配资源,一台物理机上也装不了几个虚拟机。如果虚拟机闲置,分配给虚拟机的硬件资源也无法分配给其他虚拟机。也有一部分虚拟化技术可以实现一定程度上的“动态分配”。但这种“动态分配”有各种各样的缺陷,比如回收速度慢(Balloon技术),影响性能(内存压缩),或即慢又影响性能(透明页共享)。
虚拟化技术也有很大的性能损耗。例如为了虚拟CPU,Hypervisor需要为每个虚拟的CPU创建一个数据结构,以模拟CPU的寄存器;为了虚拟内存,需要通过一个shadow page table,在物理内存和虚拟机内存之间增加一层虚拟的物理内存。而且操作系统本身的资源损耗是无论如何无法避免的。
相比之下,Cgroups虽然也会带来一些性能损耗。但通过一些测试可以发现,相比虚拟机接近50%的损耗,容器的性能损耗微乎其微(CPU密集场景下是5%)。此外Docker还节省了操作系统运行的资源损耗。此外,容器在启动时间上也有巨大的优势。
当然Cgroups也有自己的问题。比如高压力下容器与容器之间,以及容器和操作系统之间抢占资源的问题。有兴趣的话可以参考这篇,或者自己做个实验试一下。
Docker原理总结
从以上的介绍你可以看到,其实Docker engine并没有使用什么特别深奥的原理。甚至你可以通过shell脚本自己来实现一个docker engine(事实上github上就有这么一个开源项目,使用100行bash实现了精简版的docker)。所以事实上真正Docker的架构类似下图:
常见问题
建议在物理机上还是虚拟机上运行Docker?
当我要开始搭容器测试环境的时候,最纠结的其实是到底该搭在虚拟机上还是物理机上。万一搞错了还要铲掉重来。
按照我的经验,先到官方文档里找最佳实践,但翻了半天也没找到。
在了解了原理后,自然会得出结论:物理机上部署Docker的性能约等于直接在物理机上部署应用。所以物理机上部署肯定有性能和延迟优势。
不过Docker的博客上也提到了虚拟机化的几个好处:
- 方便上云
- 可以利用成熟且已有的虚拟化经验,例如:灾备,监控和自动化
- 节省虚拟机License
国内也有人测试过具体的性能差异,IO和CPU方面物理机快25%-30%。
运行Docker:物理机vs虚拟机,五方面详细对比理
在我们的场景下,性能远不及其他几个优点重要。于是最终还是选择了虚拟机上部署。
容器的操作系统是否能和宿主机不一样?
可以分成三种情况讨论:
- 容器的操作系统版本比宿主机高或低
- 操作系统是不同发行版本的(例如宿主机是CentOS,容器是Ubuntu)
- 操作系统完全不同(例如宿主机是Windows,容器是CentOS)
其实1和2都差不多。不同版本和发行版本的Linux内核的差别不那么大。容器只与主机共享一个内核。
操作系统=内核+文件系统/库
镜像=文件系统/库
这也是为什么不能在Linux宿主机上运行Windows容器。内核根本就不一样。
但为什么我们可以在Windows 10上运行容器?这多亏了Hyper-V。(回想起来Hyper-V最初发布的时候还是在微软内部看到消息并试用的。。。)
Hyper-V的技术细节就不多提了。与Docker相关的可以参见这张架构图:
与之原理类似,MacOS上运行Docker是通过虚拟化技术xhyve或者virtualbox来实现。
更多可以参见这篇:
Understanding Docker “Container Host” vs. “Container OS” for Linux and Windows Containers