软件和硬件

操作系统

操作系统就是管理计算机的硬件软件和资源,并且为软件运行提供通用服务的系统软件。

  • 硬件管理,包括分配CPU时间、内存;从网络、存储设备等IO设备读写数据。
  • 软件管理,就是各种软件的运行,线程、进程调度之类的工作。
  • 为软件提供运行环境,这个运行环境通常一部分由操作系统内核(Kernel)提供,另一部分由运行库(Runtime Library)提供。

Image

安迪-比尔定律:”what Andy giveth, Bill taketh away.”

随着硬件的性能提升,以及软件种类的丰富,有两种情况变得很常见:

  1. 硬件性能过剩——很多计算机的硬件配置,即使不能完全满足峰值性能的要求,也往往会有大量时间处于硬件资源闲置的状态。例如一般家用电脑,已经是四核、六核的配置了,除了3A游戏、视频制作、3D渲染、高性能计算等特殊应用外,通常有90%以上时间CPU是闲置的。
  2. 软件冲突——因为业务需要,两个或者多个软件之间冲突,或者需要同一个软件的不同版本。例如早几年做web前端的,要测试网页在不同版本的IE上是否能正常显示,然而Windows只能装一个版本的IE。

在硬件性能过剩的时候,硬件虚拟化的普及就很自然而然的提出来了。


云计算中的虚拟化和容器化

Image

2000 年前后,虚拟化技术逐渐发展成熟,虚拟化技术的成熟,使得云计算市场开始真正出现。

Image

  • IaaS(Infrastructure as a service,基础设施即服务)的出现:通过按时计费的方式租借服务器(卖资源),将资本支出转变为运营支出,这使得云计算得以大规模兴起和普及。
  • PaaS(Platform as a service,平台即服务)的出现:使开发者不必费心考虑操作系统和开发工具更新或者硬件维护,云服务提供商由 IaaS 阶段的卖资源进阶为卖服务
  • 开源 IaaS 的出现:云计算开始进入开源时代
  • 开源 PaaS 的出现:云计算开始推动容器技术兴起
  • FaaS(Function as a Service,功能即服务)的出现:通过 FaaS,物理硬件、虚拟机操作系统和 Web 服务器软件管理等等都由云服务提供商自动处理。无服务器(Serverless)的概念已经初现,开发者将无需再关注任何服务、资源等基础设施。

Image

2013 年发生了一件影响深广的技术变革:Docker 降世。

从虚拟机到容器,整个云计算市场发生了一次重大变革,甚至是洗牌,基于容器技术的容器编排市场,则经历了 Mesos、Swarm、kubernetes 三家的一场史诗大战,最终以 kubernetes 全面胜利而告终。

Image

  • 2013 年,Docker 发布,容器逐步替代 VM,云计算进入容器时代。
  • 2017 年底,Kubernetes 赢得容器编排的胜利,云计算进入 Kubernetes 时代。
  • 2018 年,Istio 正式发布,服务网格(ServiceMesh)从理念走向成熟。

对云计算演进总结分析,可以发现以下规律:

  • 核心构建块的变化:从早期的物理服务器,通过虚拟化技术演进为虚拟机,再通过容器化技术演进为目前的 container。
  • 隔离单元:无论是启动时间还是单元大小,物理机、虚拟机、容器一路走来,实现了从重量级到轻量级的转变。
  • 供应商:从闭源到开源,从单一供应商到跨越多个供应商。

虚拟化

Image

所谓硬件虚拟化,就是某个特殊的软件,仿真出一台或者多台计算机的各种硬件,用户可以在这一台虚拟机上安装、运行操作系统(一般叫来宾操作系统,Guest OS)和各种应用,并且把Guest OS和上面应用软件对硬件资源的访问转发到底层的硬件上来实现。对于Guest OS和上面的应用程序来说,这台虚拟机和普通的物理计算机是完全一样没有任何区别的——除了性能可能差一点。著名的VMware就是这么一个软件,这类软件英语有一个专用的单词是Hypervisor(维基的Hypervisor词条说另一种叫法是虚拟机监视器)

容器化

chroot

能否在现有的操作系统环境下,隔离出一个用来重构和测试软件的独立环境?于是,一个叫做 chroot(Change Root)的系统调用功能就此诞生。

chroot 被认为是最早的容器化技术之一,chroot 可以重定向进程及其子进程的 root 目录到文件系统上的新位置,也就是说使用它可以分离每个进程的文件访问权限,使得该进程无法接触到外面的文件,因此这个被隔离出来的新环境也得到了一个非常形象的命名,叫做 Chroot Jail(监狱)。

这便是容器最重要的特性–进程隔离。

虽然chroot是一种简单而有效的容器化技术,但它也存在一些限制。例如,chroot只能限制进程对文件系统的访问,而不能限制进程对其他系统资源的访问,如网络、进程、用户等

Image

容器的核心技术

主要有三点:使用 Namespace 用来进行资源隔离、使用 Cgroups 进行资源限制、基于 Unionfs 设计了镜像分层机制

  1. Linux 通过对内核资源进行封装抽象,提供了八类系统资源的隔离(Namespace):
类型 用途
Cgroup Cgroup root directory cgroup 根目录
IPC System V IPC, POSIX message queues 信号量,消息队列
Network Network devices, stacks, ports, etc.网络设备,协议栈,端口等等
Mount Mount points 挂载点
PID Process IDs 进程号
User 用户和组 ID
UTS 系统主机名和 NIS(Network Information Service) 主机名(有时称为域名)
Time 时钟
  1. Cgroups

    • cgroup的api以一个伪文件系统的实现方式,用户的程序可以通过文件系统实现cgroup的组件管理
    • cgroup的组件管理操作单元可以细粒度到线程级别,另外用户可以创建和销毁cgroup,从而实现资源载分配和再利用
    • 所有资源管理的功能都以子系统的方式实现,接口统一子任务创建之初与其父任务处于同一个cgroup的控制组

    四大功能:

    • 资源限制:可以对任务使用的资源总额进行限制
    • 优先级分配:通过分配的cpu时间片数量以及磁盘IO带宽大小,实际上相当于控制了任务运行优先级
    • 资源统计:可以统计系统的资源使用量,如cpu时长,内存用量等
    • 任务控制:可以对任务执行挂起、恢复等操作
  2. Unionfs

    联合文件系统(Union File System, UnionFs)它可以不同物理位置的目录合并、挂载到同一个目录中,而实际上目录的物理位置是分开的。UnionFs 把文件系统的每一次修改作为一个个层进行叠加,同时可以将不同目录挂载到同一个虚拟文件系统下。如果一次同时加载多个文件系统,UnionFs 会把各层文件叠加起来,最终文件系统会包含所有底层文件和目录,从外部视角看,就是一个完成的文件系统。

    容器镜像设计中,为了解决各类依赖以及依赖共享,正是利用 UnionFs 实现了镜像分层,再结合 bootfs、rootfs,一层层继承、叠加。启动容器时把相关的层挂载到一个目录,作为容器的根文件系统,这就是容器镜像的原理。

    • bootfs(boot file system):包含操作系统 bootloader 和 kernel。用户不能修改 bootfs,在内核启动后,bootfs 会被卸载。
    • rootfs(root file system):包含系统常见的目录结构,如/dev 、/lib、/proc、/bin、/etc/、/bin 等

Image

Docker

why docker?

Image

Image

Build, Ship, And Run Any App, Anywhere

Image

Docker 的核心创新”容器镜像(container image)”:

  • 容器镜像打包了整个容器运行依赖的环境,以避免依赖运行容器的服务器的操作系统,从而实现”build once,run anywhere”。
  • 容器镜像一但构建完成,就变成 read only,成为不可变基础设施的一份子。
  • 操作系统发行版无关,核心解决的是容器进程对操作系统包含的库、工具、配置的依赖,但是容器镜像无法解决容器进程对内核特性的特殊依赖。

Image

2015 年 6 月,Docker 带头成立 OCI(Open Container Initiative,开放容器标准),OCI 组织着力解决容器的构建、分发和运行问题,其宗旨是制定并维护容器镜像格式和容器运行时的正式规范(OCI Specifications)。

OCI 其核心产出是:

  • OCI Runtime Spec(容器运行时规范):该规范定义了如何根据相应的配置构建容器运行时。
  • OCI Image Spec(镜像格式规范):该规范定义了容器运行时使用的镜像的打包规范。
  • OCI Distribution Spec(镜像分发规范)。

Image

  • 将 libcontainer 独立出来,封装重构成 runC 项目,并捐赠给 Linux 基金会管理,runC 是 OCI Runtime 的首个参考实现
  • 与运行时交互的部分抽象为了 containerd 项目。这是一个负责管理容器执行、分发、监控、网络、构建、日志等功能的核心模块,其内部会为每个容器运行时创建一个 containerd-shim 适配进程,默认与 runC 搭配工作

Image

其他操作系统上的 docker

  • windows: Hyper-V
  • macOS:

从 Docker 到 K8s

如果说以 Docker 为代表的容器引擎,是把软件的发布流程从分发二进制安装包,转变为了直接分发虚拟化后的整个运行环境,让应用得以实现跨机器的绿色部署。那以 Kubernetes 为代表的容器编排框架,就是把大型软件系统运行所依赖的集群环境也进行了虚拟化,让集群得以实现跨数据中心的绿色部署,并能够根据实际情况自动扩缩。

Image

k8s 容器编排

Image

kubelet


参考资料


概念表

VM:VMware

VMware就这么一个软件。这个能够虚拟出一台或者多台电脑,并对这些虚拟机进行管理的软件,就是Hypervisor。知道VMware的大部分人都听说过两个版本:一个是VMware Workstation,一个是VMware ESXi。

KVM

而Linux从2.6.20开始,就从内核支持虚拟化,可以理解为内核就是Hypervisor的一部分,配合Qemu实现完整的Hypervisor功能。所以叫”基于内核的虚拟机(英语:Kernel-based Virtual Machine,缩写为KVM)”,不过因为内核部分跟近似于Type I但又不是完整的Hypervisor,Qemu部分则更接近于Type II,所以在维基的Hyperviso词条的Talk页面中,不少人为KVM属于Type I还是Type II而激烈争论。

Hypervisor

Hypervisor根据其对硬件资源的访问方式,可以分为两大类,Type I是Hypervisor直接访问硬件资源,通常会有另一个操作系统运行于Hypervisor之上来对硬件资源,例如VMware EXSi,Windows的Hyper-V,Linux的Xen;Type II是Hypervisor和普通的应用一样,运行在某个操作系统(例如Windows或者Linux等,这里称之为宿主机操作系统,Host OS)之上,Hypervisor通过Host OS访问硬件资源,例如VMware Workstation,Virtual Box等。

Image

ESXi属于Type I,Workstation属于Type II。Windows自带的Hyper-V,Linux上的Xen也属于Type I,Virtual Box之类的属于Type II。

Docker

Image

Docker是目前最流行的容器引擎,它把容器技术从“只有运维专家才会用”变成了“开发者人人都能用”。Docker的核心创新是容器镜像(container image)——把应用和它依赖的整个运行环境打包成一个不可变的文件,真正做到“build once, run anywhere”。

OCI

OCI(Open Container Initiative,开放容器标准)是2015年由Docker带头成立、Linux基金会管理的组织,致力于制定容器的工业标准。它的核心产出是两个规范:容器运行时标准(runtime spec)定义了容器的状态和生命周期管理;容器镜像标准(image spec)定义了镜像的打包格式。这样做的好处是,不同厂商的容器工具可以互相兼容,不会被某一家绑定。

containerd

containerd是Docker从docker daemon中剥离出来的容器运行时核心模块,负责管理容器的完整生命周期,包括容器执行、分发、监控、网络、构建、日志等功能。它通过grpc与上层(Docker或Kubernetes)通信,接收“运行容器”的请求后,内部会为每个容器创建一个containerd-shim适配进程,最终调用runC来实际创建和运行容器。

containerd的意义在于,它把“管理容器”和“运行容器”这两件事拆开了:containerd做管理层的事,runC做底层运行的事,各司其职。

runC

runC是从Docker的libcontainer中独立、重构而来的,后来捐赠给Linux基金会,成为OCI Runtime Spec的首个参考实现。简单说,runC就是一个CLI工具,它负责真正和Linux内核打交道——配置cgroup、namespace,创建和启动容器进程。

当你执行docker run的时候,实际经历的步骤是:下载镜像→将镜像解开为bundle文件(文件系统拆分成多层)→从bundle运行容器。runC做的就是最后一步。它只关心“怎么把一个容器跑起来”,镜像拉取、网络、存储这些事情都不管。

既然runC只是OCI标准的一个实现,那自然还有其他符合OCI标准的容器运行时,比如Kata Containers、gVisor等,它们也可以通过containerd接入Docker或Kubernetes使用。

CRI

CRI(Container Runtime Interface,容器运行时接口)是Kubernetes定义的一套标准接口,让kubelet可以通过统一的协议来调用不同的容器运行时,而不用关心底层是Docker、containerd还是其他实现。

docker独立出来了containerd。kubernetes也顺应潮流,孵化了cri-containerd项目,用以将containerd接入到cri的标准中。

cri-containerd

为了进一步与oci进行兼容,kubernetes还孵化了cri-o,成为了架设在cri和oci之间的一座桥梁。通过这种方式,可以方便更多符合oci标准的容器运行时,接入kubernetes进行集成使用。可以预见到,通过cri-o,kubernetes在使用的兼容性和广泛性上将会得到进一步加强。

kubelet