目录
一. 虚拟化和容器化的概念
什么是虚拟化、容器化
案例
为什么要虚拟化、容器化?
二. 虚拟化实现方式
应用程序执行环境分层
虚拟化常见类别
虚拟机
容器
JVM 之类的虚拟机
三. 常见虚拟化实现
主机虚拟化(虚拟机)实现
容器虚拟化实现
容器虚拟化实现原理
容器虚拟化基础之 NameSpace
容器虚拟化基础之 cgroups
物理机:实际的服务器或者计算机。相对于虚拟机而言的对实体计算机的称呼。物理 机提供给虚拟机以硬件环境,有时也称为“寄主”或“宿主”。
虚拟化:是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上 同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都 可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。
容器化:容器化是一种虚拟化技术,又称操作系统层虚拟化( Operating system level virtualization),这种技术将操作系统内核虚拟化,可以允许用户空间软件实例(instances)被分割成几个独立的单元,在内核中运行,而不是只有一个单一实例运 行。这个软件实例,也被称为是一个容器(containers)。对每个实例的拥有者与用户 来 说 ,他 们使 用的 服务 器 程 序, 看起 来就 像是 自 己 专 用 的。 容器 技术 是 虚 拟 化 的一 种。 docker 是现今容器技术的事实标准。
举个生活中的例子。
物理机, 就像一个庄园,独立占用了一块土地,花园都是自己的,其他人无法共享使用。
虚拟机相当于开发商的一个楼盘,一栋楼一套房子一户人家,共享一块宅基地,共享小区的花园,共享小区的游乐设施。
容器相当于在 1 个房子里面,开辟出来一个又一个的胶囊公寓,共享这套房子的卫生间、共享厨房、共享 WiFi,只有衣服、电脑等私人物品是你自己的。
我们从上面的历史发展来看,虚拟化和容器化的最主要目的就是资源隔离,随着资源隔离的实现逐渐也带来了更大的收益。
• 资源利用率高
将利用率较低的服务器资源进行整合,用更少硬件资源运行更多业务,降低 IT 支出和运维管理成本。
比如土地可以直接复用,使用这块土地的人多了,但是成本还是庄园那块地 。
• 环境标准化
一次构建,随处执行。实现执行环境的标准化发布,部署和运维。开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些 bug 并未在开发过程中被 发现。而 Docker 的镜 像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
• 资源弹性伸缩
根据业务情况,动态调整计算、存储、网络等硬件及软件资源。比如 遇到双 11 了,把 服务扩容 100 个,双 11 过去了, 把扩容的 100 个收回去。
• 差异化环境提供
同时提供多套差异化的执行环境,限制环境使用资源。
• 沙箱安全
为避免不安全或不稳定软件对系统安全性、稳定性造成影响,可使用虚拟化技术构建虚拟执行环境。
比如我在容器里面执行 rm -rf /* 不会把整个服务器搞死,也不影响其他人部署的程序使用。
• 容器对比虚拟机更轻量,启动更快
传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运 行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时 间。大大的节约了开发、测试、部署的时间。
docker 不需要虚拟内核,所以启动可以更快,相当于 windows 的开机时间省去了。
• 维护和扩展容易
Docker 使用的分层存储以 及镜像的技术,使得应用重复部分的复用更为容易,也使得 应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外, Docker 团队同各个开源项 目团队一起维护了一大批高质量的 官方镜像,既可以直接 在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成 本。比如 docker hub 提供了很多镜像,各个系统的一个命令就可以拿到了,研发也可 以自己定制镜像分享给各个产品。
硬件层:提供硬件抽象,包括指令集架构、硬件设备及硬件访问接口
操作系统层 :提供系统调用接口,管理硬件资源
程序库层:提供数据结构定义及函数调用接口
存在于硬件层和操作系统层间的虚拟化技术。虚拟机通过“伪造”一个硬件抽象接口, 将一个操作系统以及操作系统层以上的层嫁接到硬件上,实现和真实物理机几乎一样 的功能。比如我们在一台 Windows 系统的电脑上使用 Android 虚拟机,就能够用这台 电脑打开 Android 系统上的应用。
存在于操作系统层和函数库层之间的虚拟化技术。容器通过“伪造”操作系统的接口, 将函数库层以上的功能置于操作系统上。以 Docker 为例,其就是一个基于 Linux 操作 系统的 Namespace 和 Cgroup 功能实现的隔离容器,可以模拟操作系统的功能。简单 来说,如果虚拟机是把整个操作系统封装隔离,从而实现跨平台应用的话,那么容器 则是把一个个应用单独封装隔离,从而实现跨平台应用。所以容器体积比虚拟机小很多,理论上占用资源更少。容器化就是应用程序级别的虚拟化技术。容器提供了将应 用程序的代码、运行时、系统工具、系统库和配置打包到一个实例中的标准方法。容 器共享一个内核(操作系统),它安装在硬件上。
存在于函数库层和应用程序之间的虚拟化技术。Java 虚拟机同样具有跨平台特性,所 谓跨平台特性实际上也就是虚拟化的功劳。我们知道 Java 语言是调用操作系统函数库 的,JVM 就是在应用层与函数库层之间建立一个抽象层,对下通过不同的版本适应不 同的操作系统函数库,对上提供统一的运行环境交给程序和开发者,使开发者能够调 用不同操作系统的函数库。
主机虚拟化的原理是通过在物理服务器上安装一个虚拟化层来实现。这个虚拟化层可 以在物理服务器和客户操作系统之间建立虚拟机,使得它们可以独立运行。
从软件框架的角度上,根据虚拟化层是直接位于硬件之上还是在一个宿主操作系统之 上,将虚拟化划分为 Type1 和 Type2.
Type1 类的 Hypervisor(Hypervisor 是一种系统软件,它充当计算机硬件和虚拟机之间 的中介,负责有效地分配和利用由各个虚拟机使用的硬件资源,这些虚拟机在物理主 机上单独工作,因此,Hypervisor 也称为虚拟机管理器。)直接运行在硬件之上,没有 宿主机操作系统,Hypervisor 直接控制硬件资源和客户机。典型框架为 Xen、Vmware ESX。
容器虚拟化,有别于主机虚拟化,是操作系统层的虚拟化。通过 namespace 进行各程 序的隔离,加上 cgroups 进行资源的控制,以此来进行虚拟化。
什么是 Namespace(命名空间)
namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进 程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的 资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把 一个或多个进程 的相关资源指定在同一个 namespace 中。
Linux 提供了多个 API 用来操作 namespace,它们是 clone()、setns() 和 unshare() 函 数,为了确定隔离的到底是哪项 namespace,在使用这些 API 时,通常需要指定一些 调用参数:CLONE_NEWIPC、CLONE_NEWNET、CLONE_NEWNS、 CLONE_NEWPID、CLONE_NEWUSER、CLONE_NEWUTS 和 CLONE_NEWCGROUP。如果要同时隔离多个 namespace,可以使用 | (按位或)组合 这些参数。
举个例子
三年一班的小明和三年二班的小明,虽说他们名字是一样的,但是所在班级不一样, 那么,在全年级排行榜上面,即使出现两个名字一样的小明,也会通过各自的学号来 区 分 。对 于学 校来 说, 每 个 班级 就相 当于 是 一 个 命 名 空 间, 这个 空间 的 名 称是 班级 号。 班级号用于描述逻辑上的学生分组信息,至于什么学生分配到 1 班,什么学生分配到 2 班,那就由学校层面来统一调度。
namesp ace |
系统调用参数 |
被隔离的全局系统资源 |
引入内 核版本 |
|
UTS |
CLONE_NEWUTS |
主机名和域名 |
2.6.19 |
|
IPC |
CLONE_NEWIPC |
信号量、消息队列和共享内存 - - 进程间通信 |
2.6.19 |
|
PID |
CLONE_NEWPID |
进程编号 |
2.6.24 |
|
Network |
CLONE_NEWNET |
网络设备、网络栈、端口等 |
2.6.29 |
|
Mount |
CLONE_NEWNS |
文件系统挂载点 |
2.4.19 |
以上命名空间在容器环境下的隔离效果:
UTS:每个容器能看到自己的 hostname,拥有独立的主机名和域名。
IPC:同一个 IPC namespace 的进程之间能互相通讯,不同的 IPC namespace 之间 不能通信。
PID:每个 PID namespace 中的进程可以有其独立的 PID,每个容器可以有其 PID 为1 的 root 进程。
Network:每个容器用有其独立的网络设备,IP 地址,IP 路由表,/proc/net 目录,端口号。
Mount:每个容器能看到不同的文件系统层次结构。
User:每个 container 可以有不同的 user 和 group id。
想想以下如果我们要隔离两个进程需要怎么办?
1. 什么是 cgroups
cgroups(Control Groups) 是 linux 内核提供的一种机制,这种机制可以根据需求把一 系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而为系统资源 管理提供一个统一的框架。简单说,cgroups 可以限制、记录任务组所使用的物理资 源。本质上来说,cgroups 是内核附加在程序上的一系列钩子(hook),通过程序运行时 对资源的调度触发相应的钩子以达到资源追踪和限制的目的。
2. 为什么使用 cgroups
其可以做到对 cpu,内存等资源实现精细化的控制,目前越来越火的轻量级容器Docker 及 k8s 中的 pod 就使用了 cgroups 提供的资源限制能力来完成 cpu,内存等部 分的资源控制。
比如在一个既部署了前端 web 服务,也部署了后端计算模块的八核服务器上,可以使 用 cgroups 限制 web server 仅可以使用其中的六个核,把剩下的两个核留给后端计算 模块。
3. cgroups 的用途
Resource limitation: 限制资源使用,例:内存使用上限/cpu 的使用限制
Prioritization: 优先级控制,例:CPU 利用/磁盘 IO 吞吐
Accounting: 一些审计或一些统计
Control: 挂起进程/恢复执行进程
4. cgroups 可以控制的子系统
blkio |
对块设备的 IO 进行限制。 |
|
cpu |
限制 CPU 时间片的分配 |
|
cpuacct |
生成 cgroup 中的任务占用 CPU 资源的报告,与 cpu 挂载在同 一目录。 |
|
cpuset |
给 cgroup 中的任务分配独立的 CPU(多处理器系统) 和内存节 点。 |
|
devices |
限制设备文件的创建,和对设备文件的读写 |
|
freezer |
暂停/恢复 cgroup 中的任务。
|
|
memory |
对 cgroup 中的任务的可用内存进行限制,并自动生成资源占用 报告。 |
|
perf_event |
允许 perf 观测 cgroup 中的 task |
|
net_cls |
cgroup 中的任务创建的数据报文的类别标识符,这让 Linux 流量 控制器(tc 指令)可以识别来自特定 cgroup 任务的数据包,并 进行网络限制。 |
|
hugetlb |
限制使用的内存页数量。 |
容器虚拟化基础之 LXC
LXC 是什么?
LXC(LinuX Containers)Linux 容器,一种操作系统层虚拟化技术,为 Linux 内核容 器功能的一个用户空间接口。它将应用软件系统打包成一个软件容器(Container), 内含应用软件本身的代码,以及所需要的操作系统核心和库。透过统一的名字空间和 共 享 API 来分配 不同软件容 器的可用硬件 资源,创造 出应用程序的 独立沙箱运 行环境, 使得 Linux 用户可以容易的创建和管理系统或应用容器。
LXC 是最早一批真正把完整的容器技术用一组简易使用的工具和模板来极大的简化了 容器技术使用的一个方案
LXC 虽然极大的简化了容器技术的使用,但比起直接通过内核调用来使用容器技术, 其复杂程度其实并没有多大降低,因为我们必须要学会 LXC 的一组命令工具,且由于 内核的创建都是通过命令来实现的,通过批量命令实现数据迁移并不容易。其隔离性 也没有虚拟机那么强大。
后来就出现了 docker,所以从一定程度上来说,docker 就是 LXC 的增强版。