# 虚拟机与容器

运行多个进程时,隔离它们的运行环境有利于管理。常见的几种隔离方式:

  • 运行多个物理主机
  • 在一个物理机上,运行多个虚拟机
  • 在一个主机上,运行多个容器,每个容器内运行一组进程

# 虚拟机

  • 原理:
    • 在物理计算机(称为宿主机)中,运行一个虚拟机管理程序。称为 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

# 容器

  • 容器(Container)是新一代的虚拟化技术。
  • 原理:
    • 以镜像作为模板,在主机上创建容器并保持运行。
    • 运行容器的主机称为宿主机,可以是物理机或虚拟机。
    • 每个容器内运行一组进程。
    • 所有容器共用宿主机的一些资源,比如操作系统。但也独享一些资源,比如每个容器使用独立的虚拟网口。
      • 换句话说,Container 是在应用程序与操作系统之间,隔离出一个中间层。
  • 优点:
    • 能隔离进程的运行环境
      • 隔离程度比虚拟机低,比如容器会共享宿主机内核,但足够满足一般项目的需求。
    • 便于管理进程
      • 包含了进程管理工具的功能,比如启动、停止、自动重启。
      • 进程及其子进程都运行在容器中,不会游离到容器外。
    • 轻量级
      • 运行容器引擎,大概只消耗 5% 的系统资源。
      • 部署一个应用时,直接启动一个容器即可,耗时为几秒。
    • 兼容性好
      • 同一个镜像可以拷贝到不同平台上,创建容器,只需系统内核相同。
      • 便于将应用迁移部署到其它主机。
  • 总之,容器能在一般场景下模拟虚拟机,更轻量级,但不能完全替代虚拟机。

# 相关历史

  • 1979 年,Unix 系统加入了 chroot() 函数(change root directory),用于更改正在运行的进程的根目录。
    • 比如将一个进程的根目录改为 /tmp ,此时该进程执行 cd / 相当于其它进程执行 cd /tmp ,该进程只能看到该目录下的文件,不能通过 cd .. 命令跳到该目录之外。
    • 这不会修改进程的工作目录。
    • 更改根目录时,需要事先拷贝 /lib 等库文件到新的根目录下,供进程调用,否则进程不能正常运行。
  • 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 等底层的容器运行时来管理容器。例如:

    • containerd (opens new window)
      • 是对 OCI 规范的标准实现,支持 k8s 的 CRI 接口。
      • 支持 Linux、Windows 系统。
    • CRI-O
      • 是对 k8s CRI 接口的标准实现,符合 OCI 规范。

# 容器编排工具

当容器数量较多时,手动管理很麻烦,需要使用容器编排工具,例如:

  • Docker Compose :由 Docker 公司发布,只能管理当前宿主机上的容器,不能管理服务器集群。
  • Docker Swarm :由 Docker 公司发布,在 docker 软件包中自带,可以管理多台宿主机上的容器。
  • Mesos :由 ASF 基金会管理。
  • k8s :由 Google 公司发布,能管理大量主机上的大量容器,功能多也复杂,已成为容器编排领域的事实标准。