# 虚拟机与容器
运行多个进程时,隔离它们的运行环境有利于管理。常见的几种隔离方式:
- 运行多个物理主机
- 在一个物理机上,运行多个虚拟机
- 在一个主机上,运行多个容器,每个容器内运行一组进程
# 虚拟机
- 原理:
- 在物理计算机(称为宿主机)中,运行一个虚拟机管理程序。称为 Hypervisor ,又称为 VMM(Virtual Machine Monitor)。
- Hypervisor 以子进程的方式,创建一个或多个虚拟机,称为VM、guest 。
- 每个虚拟机像一个独立计算机,可以运行一套操作系统。该系统不会访问宿主机的硬件设备,而是访问 Hypervisor 提供的虚拟设备。
- 这些虚拟设备可能是用软件模拟的设备,也可能代理到宿主机的硬件设备。
- 换句话说,Hypervisor 是在操作系统与计算机硬件之间,隔离出一个中间层。
- 优点:
- 每个虚拟机可以运行不同的操作系统。比如宿主机使用 Windows 系统,虚拟机使用 Linux 系统。
- 虚拟机中可以运行任意软件。不同虚拟机之间,实现了操作系统程度的隔离。
- 缺点:
- 重量级
- 运行 Hypervisor 软件,可能消耗 10% 的宿主机资源。
- 每个虚拟机需要分配一定系统资源,比如至少 1 核 CPU 。但应用程序可能只需使用少量系统资源,因此冗余大。
- 部署一个应用程序时,需要先创建一个虚拟机,然后安装操作系统、配置运行环境、拷贝应用程序,手动操作的耗时为几小时。
- 重量级
- Hypervisor 类型的软件举例:
- Xen
- 2003 年发布。
- OpenVZ
- 2005 年发布。
- 允许所有虚拟机共用宿主机的内核,从而减少冗余。但必须都是 Linux 系统。
- KVM(Kernel-based Virtual Machine)
- 2006 年发布。
- 每个虚拟机,使用一个独立的操作系统,独立的内核。
- OpenVZ 属于半虚拟化,而 KVM 属于全虚拟化,开销更大。
- VirtualBox
- VMwareWorkstation
- Windows Hyper-V
- Xen
# 容器
- 容器(Container)是新一代的虚拟化技术。
- 原理:
- 以镜像作为模板,在主机上创建容器并保持运行。
- 运行容器的主机称为宿主机,可以是物理机或虚拟机。
- 每个容器内运行一组进程。
- 所有容器共用宿主机的一些资源,比如操作系统。但也独享一些资源,比如每个容器使用独立的虚拟网口。
- 换句话说,Container 是在应用程序与操作系统之间,隔离出一个中间层。
- 优点:
- 能隔离进程的运行环境
- 隔离程度比虚拟机低,比如容器会共享宿主机内核,但足够满足一般项目的需求。
- 便于管理进程
- 包含了进程管理工具的功能,比如启动、停止、自动重启。
- 进程及其子进程都运行在容器中,不会游离到容器外。
- 轻量级
- 运行容器引擎,大概只消耗 5% 的系统资源。
- 部署一个应用时,直接启动一个容器即可,耗时为几秒。
- 兼容性好
- 同一个镜像可以拷贝到不同平台上,创建容器,只需系统内核相同。
- 便于将应用迁移部署到其它主机。
- 能隔离进程的运行环境
- 总之,容器能在一般场景下模拟虚拟机,更轻量级,但不能完全替代虚拟机。
# 相关历史
- 1979 年,Unix 系统加入了 chroot() 函数(change root directory),用于更改正在运行的进程的根目录。
- 比如将一个进程的根目录改为 /tmp ,此时该进程执行
cd /
相当于其它进程执行cd /tmp
,该进程只能看到该目录下的文件,不能通过cd ..
命令跳到该目录之外。 - 这不会修改进程的工作目录。
- 更改根目录时,需要事先拷贝 /lib 等库文件到新的根目录下,供进程调用,否则进程不能正常运行。
- 比如将一个进程的根目录改为 /tmp ,此时该进程执行
- 2002 年,Linux 系统加入了 namespace 技术,用于隔离进程可见的系统资源。
- 2008 年,Linux 系统加入了 Control group 技术,简称为 Cgroup ,用于限制进程对 CPU、内存等系统资源的使用量。
- 2008 年,Linux 系统加入了 LXC 工具,用于控制 namespace 和 Cgroup 。
- 2013 年,dotCloud 公司发布 Docker 软件,使得容器技术流行、普及,公司也改名为 Docker 公司。
# 容器引擎
- 容器引擎(Container Engine):通常是一个复杂的软件,负责与用户交互、管理镜像、管理容器。
- 容器引擎举例:
- LXC(Linux Container)
- Docker
- Podman :兼容 Docker CLI 的大部分命令。
- Windows Hyper-V Containers
# 容器运行时
容器运行时(Container Runtime):通常是一个 CLI 程序,用于创建、运行、管理容器。
- 有的容器引擎会直接管理容器,而有的容器引擎会调用容器运行时来管理容器。
- 早期版本的 Docker 引擎是通过 LXC 来控制 namespace、Cgroup ,实现容器化。从 0.9 版本开始,弃用 LXC ,改用 libcontainer 等自研的 Golang 库,后来演变为 runC 组件。
- 2016 年,Docker 引擎将其底层组件 runC、containerd 抽离出来,成为独立的容器运行时项目。
- 此后,Docker 引擎会调用 containerd 来管理容器,而 containerd 会调用 runc 命令来管理容器。
OCI(Open Container Initiative ,开放容器倡议)
- :定义了容器的镜像规范、容器运行时规范。
- 2015 年,Docker 公司将 OCI 规范捐赠给 CNCF 基金会。
- 如果一个镜像符合 OCI 规范,则可以被符合 OCI 标准的容器运行时读取,用于创建容器。
底层的容器运行时:
- runC
- 只支持 Linux 系统。
- crun
- rkt(CoreOS Rocket)
- 由 CoreOS 公司发布,以 Pod 为单位管理容器。但不符合 OCI 规范,已被弃用。
- kata-containers
- 在一个轻量级虚拟机中运行容器,不共享宿主机的内核,隔离程度更高。
- runC
高层的容器运行时:基于 runC 等底层的容器运行时来管理容器。例如:
- containerd (opens new window)
- 是对 OCI 规范的标准实现,支持 k8s 的 CRI 接口。
- 支持 Linux、Windows 系统。
- CRI-O
- 是对 k8s CRI 接口的标准实现,符合 OCI 规范。
- containerd (opens new window)
# 容器编排工具
当容器数量较多时,手动管理很麻烦,需要使用容器编排工具,例如:
- Docker Compose :由 Docker 公司发布,只能管理当前宿主机上的容器,不能管理服务器集群。
- Docker Swarm :由 Docker 公司发布,在 docker 软件包中自带,可以管理多台宿主机上的容器。
- Mesos :由 ASF 基金会管理。
- k8s :由 Google 公司发布,能管理大量主机上的大量容器,功能多也复杂,已成为容器编排领域的事实标准。