容器和虚拟机的对比
下面这张图是 docker 官方中截取下来的,我们来分析下 docker 和 传统 VM 的区别:
迁移性和性能
传统 VM: 需要基于 Hypervisor 的硬件虚拟化技术,模拟出 CPU,内存等硬件。然后在其上搭建一套完整的操作系统,自然在性能上会有很大的损失。迁移自然更不用说,传统的 ova 导出后就是一个完整的操作系统。
Docker:Docker 将 Hypervisor 的位置换成自己的 Docker Engine,然后运行的容器仅仅是一个特殊的进程,自然性能不会有太大的损失。并且可以应用和其所需要的系统文件打包成镜像,无论在哪读可以正常运行,而且相对于 ova 来说体积也小了更多。(需要内核支持)
一般来说,运行着 CentOS 的 KVM,启动后,在不做优化的前提下,需要占用 100~200M 内存。在加上用户对宿主机的调用,需要通过虚拟化软件拦截和处理,又是一层性能损耗,特别是对计算资源,网络和磁盘I/O等。
隔离性
传统 VM:由于是虚拟化出一套完整的操作系统,所以隔离性非常好。比如微软的 Azure 平台,就是在 Windows 服务器上,虚拟出大量的 Linux 虚拟机。
Docker:在隔离性上相差就很多了,因为本身上容器就是一种进程,而所有的进程都需要共享一个系统内核。
- 这就意味着,在 Windows 上运行 Linux 容器,或者 Linux 宿主机运行高版本内核的容器就无法实现。
- 在 Linux 内核中,有许多资源和对象不能 Namespace 化,如时间,比如通过
settimeofday(2) 系统调用
修改时间,整个宿主机的实际都会被修改。 - 安全的问题,共享宿主机内核的事实,容器暴露出的攻击面更大。
资源限制
传统 VM:非常便于管理,控制资源的使用,依赖于虚拟的操作系统。
Docker:由于 docker 内资源的限制通过 Cgroup 实现,而 Cgroup 有很多不完善的地方,比如
- 对 /proc 的处理问题。进入容器后,执行 top 命令,看到的信息和宿主机是一样的,而不是配置后的容器的数据。(可以通过 lxcfs 修正)。
- 在运行 java 程序时,给容器内设置的内存为 4g,使用默认的 jvm 配置。而默认的 jvm 读取的内存是宿主机(可能大于 4g),这样就会出现 OOM 的情况。
解决的问题
1.容器是如何进行隔离的?
在创建新进程时,通过 Namespace 技术,如 PID namespaces 等,实现隔离性。让运行后的容器仅能看到本身的内容。
比如,在容器运行时,会默认加上 PID, UTS, network, user, mount, IPC, cgroup 等 Namespace。
2.容器是如何进行资源限制的?
通过 Linux Cgroup 技术,可为每个进程设定限制的 CPU,Memory 等资源,进而设置进程访问资源的上限。
3.简述下 docker 的文件系统?
docker 的文件系统称为 rootfs,它的实现的想法来自与 Linux unionFS 。将不同的目录,挂载到一起,形成一个独立的视图。并且 docker 在此基础上引入了层的概念,解决了可重用性的问题。
在具体实现上,rootfs 的存储区分根据 linux 内核和 docker 本身的版本,分为 overlay2 , overlay, aufs, devicemapper 等。rootfs(镜像)其实就是多个层的叠加,当多层存在相同的文件时,上层的文件会将下层的文件覆盖掉。
4.容器的启动过程?
1.指定 Linux Namespace 配置
2.设置指定的 Cgroups 参数
3.切换进程的根目录
5.容器内运行多个应用的问题?
首先更正一个概念,我们都说容器是一个单进程的应用,其实这里的单进程不是指在容器中只允许着一个进程,而是指只有一个进程是可控的。在容器内当然可以使用 ping,ssh 等进程,但这些进程是不受 docker 控制的。
容器内的主进程,也就是 pid =1 的进程,一般是通过 DockerFile 中 ENTRYPOINT 或者 CMD 指定的。如果在一个容器内如果存在着多个服务(进程),就可能出现主进程正常运行,但是子进程退出挂掉的问题,而对于 docker 来说,仅仅控制主进程,无法对这种意外的情况作出处理,也就会出现,容器明明正常运行,但是服务已经挂掉的情况,这时编排系统就变得非常困难。而且多个服务,在也不容易进行排障和管理。
所以如果真的想要在容器内运行多个服务,一般会通过带有systemd
或者supervisord
这类工具进行管理,或者通过--init
方法。其实这些方法的本质就是让多个服务的进程拥有同一个父进程。
但考虑到容器本身的设计,就是希望容器和服务能够同生命周期。所以这样做,有点背道而驰的意味。