目录
- 1. 容器技术发展史
- 1.1 Jail 时代
- 1.2 云时代
- 1.3 云原生时代
- 1.3.1 Google & Docker 竞争
- 1.3.2 k8s 成为云原生事实标准
- 2. 虚拟化和容器化的概念
- 2.1 什么是虚拟化、容器化
- 2.2 为什么要虚拟化、容器化?
- 2.3 虚拟化实现方式
- 2.3.1 应用程序执行环境分层
- 2.3.2 虚拟化常见类别
- 2.4 常见虚拟化的实现
- 2.4.1 主机虚拟化(虚拟机)的实现
- 2.4.2 容器虚拟化的实现
- 2.4.3 容器虚拟化基础之cgroups
- 2.4.4 容器虚拟化基础之LXC
- 3. Docker的简介
- 3.1 Docker的本质
- 3.2 Docker和虚拟机的区别
- 3.3 Docker为什么比虚拟机资源利用率高,启动快
- 3.4 Docker 和 JVM 虚拟化的区别?
- 4. Docker的版本介绍
- 5. Docker的架构介绍
- 6. Docker的生态
- 6.1 新时代软件诉求
- 6.2 Docker的解决方案
1. 容器技术发展史
1.1 Jail 时代
(1)容器不是一个新概念或者新技术,很早就有了,只是近几年遇到了云计算,整个技术被彻底引爆了。
(2)1979 年 贝尔实验室发明 chroot:
-
chroot 系统调用是在 1979 年开发第 7 版 Unix 期间引入的。贝尔实验室在 Unix V7 的开发过程中,发现当一个系统软件编译和安装完成后,整个测试环境的变量就会发生改变,下一次测试需要重新配置环境信息。
-
设计者们思考能否隔离出来一个独立的环境,来构建和搭建测试环境,所以发明了chroot,可以把一个进程的文件系统隔离起来。
-
chroot 系统调用可以将进程及其子进程的根目录更改为文件系统中的新位置。隔离以后,该进程无法访问到外面的文件,因此这个被隔离出来的新环境像监狱一样,被命名为 Chroot Jail (监狱)。后续测试只需要把测试信息放到 Jail 中就可以完成测试了。
-
这一进步是进程隔离的开始:为每个进程隔离文件访问。所以 chroot 可以认为是容器技术的鼻祖。
(3)1.3 2000 年 FreeBSD 4.0 发行 FreeBSD Jail:
-
2000 年,当时一家小型共享环境托管提供商提出了 FreeBSD Jail,以实现其服务与其客户服务之间的明确分离,以实现安全性和易于管理。每个 Jail 都是一个在主机上运行的虚拟环境,有自己的文件、进程、用户和超级用户帐户,能够为每个系统分配一个IP 地址。
-
FreeBSD Jail 不仅仅有 chroot 的文件系统隔离,并且扩充了独立的进程和网络空间。
(4)1.4 2001 年 Linux VServer 发行:
- 与 FreeBSD Jails 一样, Linux VServer 是一种监狱机制,可以对计算机系统上的资源(文件系统、网络地址、内存)进行分区。
(5)1.5 2004 年 Solaris Containers 发行:
-
2004 年, Solaris Containers 的第一个公开测试版发布,结合系统资源控制和区域进行隔离,并添加了快照和克隆能力。
-
这个时期的进程隔离技术大多以 Jail 模式为核心,基本实现了进程相关资源的隔离操作,没有更大的应用场景发展有限。
1.2 云时代
(1)云时代的到来:
-
2006 年, Google 101 计划提出云的概念,对当前的主流开发模式产生深远的影响。也许以后我们会更多考虑如果出现比现在多 1000 倍, 10000 倍的数据量的时候,我们该如何处理?要想让”云”发挥潜能,与此相关的编程和操作就应该与使用互联网一样简单。随后,亚马逊、 IBM 等行业巨头也陆续宣布各自的“云”计划,宣告“云”技术时代的来临。
-
云计算需要处理海量数据、超高并发、快速扩展等问题,此时不仅仅需要隔离还需要能够对资源进行控制和调配。
(2)1.7 2006 年 google 推出 Process Containers:
- Process Containers(由 Google 于 2006 年推出)旨在限制、统计和隔离一组进程的资源使用(CPU、内存、磁盘 I/O、网络)。一年后它更名为“Control Groups(cgroups)”,并最终合并到 Linux 内核 2.6.24。
(3)1.8 2008 年 LXC 推出:
-
LXC(Linux 容器)是 Linux 容器管理器的第一个、最完整的实现。它是在 2008 年使用 cgroups 和 Linux 命名空间实现的,它可以在单个 Linux 内核上运行,不需要任何补丁。
-
同年谷歌推出 GAE(Google App Engine),首次把开发平台当做一种服务来提供,采用云计算技术,跨越多个服务器和数据中心来虚拟化应用程序。
-
同时 Google 在 GAE 中使用了 Borg (Kubernetes 的前身)来对容器进行编排和调度。
-
LXC 和 Borg 其实就相当于最早的 docker 和 k8s。
(4)2011 年 CloudFoundry 推出 Warden:
- 2011 年启动了 Warden,早期使用 LXC,后来替换为自己的实现,直接对Cgroups 以及 Linux Namespace 操作。开发了一个客户端-服务器模型来管理跨多个主机的容器集合,并且可以管理 cgroups、命名空间和进程生命周期。
(5)2013 年 LMCTFY 启动:
- Let Me Contain That For You (LMCTFY) 于 2013 年作为 Google 容器堆栈的开源版本启动,提供 Linux 应用程序容器。应用程序可以“容器感知”,创建和管理它们自己的子容器。在谷歌开始和 docker 合作,后续转向了 docker 公司的 libcontainer, LMCTFY的于 2015 年停止。
(6)2013 年 Docker 推出到风靡全球:
-
Docker 最初是一个叫做 dotCloud 的 PaaS 服务公司的内部项目,后来该公司改名为Docker。 Docker 在初期与 Warden 类似,使用的也是 LXC,之后才开始采用自己开发的 libcontainer 来替代 LXC,它是将应用程序及其依赖打包到几乎可以在任何服务器上运行的容器的工具。与其他只做容器的项目不同的是, Docker 引入了一整套管理容器的生态系统,这包括高效、分层的容器镜像模型、全局和本地的容器注册库、清晰的 REST API、命令行等等。
-
Docker 为提供了一整套的解决方案,不仅解决了容器化问题,而且解决了分发问题,很快被各大厂商选择变成了云基础设施,厂商围绕 Docker 也开始了生态建设。
1.3 云原生时代
1.3.1 Google & Docker 竞争
(1)2013 年 CoreOS 发布和 Docker 合作终止:
- 技术革命带来新的市场机遇,CoreOS 也是其中的一员,在容器生态圈中贴有标签。专为容器设计的操作系统 CoreOS。作为互补, CoreOS+Docker 曾经也是容器部署的灵魂伴侣。 CoreOS 为 Docker 的推广和源码社区都做出了巨大的贡献。
- Docker 生态扩张,与最开始是“一个简单的基础单元”不同, Docker 也在通过开发或收购逐步完善容器云平台的各种组件,准备打造自己的生态圈,而这与CoreOS 的布局有直接竞争关系。
(2)2014 年 6 月 Google 发布开源的容器编排引擎 Kubernetes(K8S):
- 容器只是解决了容器化,分发问题,但是一个软件的网络问题、负载均衡问题、监控、部署、更新、镜像管理、发布等很多问题并没有有效的解决。
- Google 内部调度系统 Borg 已经拥有 10 多年的使用容器经验,在 2014 年 6 月推出了开源的 K8S,可以支持对容器的编排和管理,完成生态的闭环。
- 同年 7 月,微软、 Red Hat、 IBM、 Docker、 CoreOS、 Mesosphere 和 Saltstack 等公司,相继加入 K8S。之后的一年内, VMware、 HP、 Intel 等公司,也陆续加入。
(3)2014 年 12 月 CoreOS 发布开源容器引擎 Rocket(rkt):
- 2014 年底, CoreOS 正式发布了 CoreOS 的开源容器引擎 Rocket(简称 rkt),和Docker 正式分开发展。 Google 于 2015 年 4 月领投 CoreOS 1200 万美元,而CoreOS 也发布了 Tectonic,成为首个支持企业版本 kubernetes 的公司。从此,容器江湖分为两大阵营, Google 派系和 Docker 派系。
(4)2015 年 Docker 推出容器集群编排组件 Swarm:
- 在 Docker 1.12 及更高版本中, Swarm 模式与 Docker 引擎集成,为 Docker 容器提供原生集群管理功能。
- 两大派系的竞争愈演愈烈,行业标准的诉求越来越强烈。
(5)2015 年 6 月 Docker 成立 OCI:
- Docker 公司在容器运行因为高速迭代导致变更频繁,影响较大。
- 2015 年 6 月 22 日,由 Docker 公司牵头, CoreOS、 Google、 RedHat 等公司共同宣布, Docker 公司将 Libcontainer 捐出,并改名为 RunC 项目,交由一个完全中立的基金会管理,然后以 RunC 为依据,大家共同制定一套容器和镜像的标准和规范。
- RUNC 的本质就是可以不通过 Docker Damon 直接运行容器。
- 规范就是 OCI,旨在“制定并维护容器镜像格式和容器运行时的正式规范(OCISpecifications) ”。其核心产出是 OCI Runtime Spec(容器运行时规范)、 OCI ImageSpec(镜像格式规范)、 OCI Distribution Spec(镜像分发规范)。所以 OCI 组织解决的是容器的构建、分发和运行问题。
- 社区们期望通过标准来约束 Docker 公司的话语权,不过 Docker 公司并没有积极推动OCI 的发展,而且 OCI 也无法影响 Docker 的地位,因为 Docker 已经是事实的容器标准。
- Google 和 RedHat 等公司将方向调转到容器上面的平台层。
(6)2015 年 7 月 Google 带头成立 CNCF:
- Google 联合 Linux 基金会成立 CNCF (Cloud Native Computing Foundation)云原生计算基金会。旨在构建云原生基础设施。 K8S 是第一个纳入进来的项目,像后续有名的监控设施 Prometheus,配置设施 ETCD 都加入进来。 CNCF 组织解决的是应用管理及容器编排问题。和 OCI 共同制定了一系列行业事实标准。
1.3.2 k8s 成为云原生事实标准
(1)2016 年 发布 CRI 标准:
- Google 就和红帽主导了 CRI 标准,用于 k8s 和特定的容器运行时解耦。
CRI(Container Runtime Interface 容器运行时接口)本质上就是 k8s 定义的一组与容器运行时进行交互的接口,所以只要实现了这套接口的容器运行时都可以对接 k8s。 - 但是这个适合 Docker 还是事实标准,并 CRI 并没有话语权,但是又必须支持 Docker,所以就有了 dockershim,dockershim 的本质其实就是 k8s 对接 docker 的一个 CRI 的实现。
(2)2016 年 Docker 捐献 containerd:
- containerd 作为运行时标准, Docker 从 Docker Engine 种剥离出来,捐献给 CNCF。这个时候 Google 为了将 containerd 加入到 cri 标准中,又开发了 cri-containerd,用来完成 k8s 和容器之间的交互。
(3)2016 年 CRI-O 发布:
- CRI-O 可以让开发者直接从 Kubernetes 来运行容器,这意味着 Kubernetes 可以不依赖于传统的容器引擎(比如 Docker),也能够管理容器化工作负载。容器此时也回归到自己的位置,如何更好的封装云原生的程序。
- 在 2016 年, Docker 公司宣布了一个震惊全部人的计划:放弃现有的 Swarm 项目,将容器编排和集群管理功能所有内置到 Docker 项目中。
- 而 Kubernetes 的应对策略则是反其道而行之,开始在整个社区推动“民主化”架构,从API 到容器运行时的每一层, Kubernetes 项目都为开发者暴露出了能够扩展的插件机制,鼓励用户经过代码的方式介入到 Kubernetes 项目的每个阶段。
- 在进入 2017 年之后,更多的厂商愿意把宝压在 K8S 上,投入到 K8S 相关生态的建设中来。这两年包括阿里云、腾讯、百度等中国科技企业也陆续加入 CNCF,全面拥抱容器技术与云原生。
- Swarm 的失败后, 社区版 Docker 项目改名为 moby,将 Docker 引流到 Docker 的企业版上去,螳臂挡车。
(4)2017 年 containerd 确定作为标准 CRI:
- 2017 年各大厂商都开始拥抱 Kubernetes,亚马逊 AWS, Microsoft Azure, VMware,有的甚至抛弃了自家的产品。
- 亚马逊网络服务(AWS)于八月份以白金会员(最高级别)加入了 CNCF。
- VMware 都作为 CNCF 的白金会员注册。
- Docker Inc.ocker 企业版框架中添加了本地 Kubernetes 支持。 Docker 自己的 Swarm技术也借鉴了 k8s 的技术进一步发展。
- Kubernetes 已成了容器编排领域的绝对标准, Docker 已成容器事实的标准。
2. 虚拟化和容器化的概念
在介绍Docket之前我们需要了解什么是虚拟化以及容器化。
2.1 什么是虚拟化、容器化
(1)概念如下:
- 物理机:实际的服务器或者计算机。相对于虚拟机而言的对实体计算机的称呼。物理机提供给虚拟机以硬件环境,有时也称为“寄主”或“宿主”。
- 虚拟化:是指通过虚拟化技术将一台计算机虚拟为多台逻辑计算机。在一台计算机上同时运行多个逻辑计算机,每个逻辑计算机可运行不同的操作系统,并且应用程序都可以在相互独立的空间内运行而互不影响,从而显著提高计算机的工作效率。
- 容器化:容器化是一种虚拟化技术,又称操作系统层虚拟化(Operating system levelvirtualization),这种技术将操作系统内核虚拟化,可以允许用户空间软件实例(instances)被分割成几个独立的单元,在内核中运行,而不是只有一个单一实例运行。这个软件实例,也被称为是一个容器(containers)。对每个实例的拥有者与用户来说,他们使用的服务器程序,看起来就像是自己专用的。容器技术是虚拟化的一种。docker 是现今容器技术的事实标准。
(2)举个生活中的例子来理解物理机、虚拟化、容器化:
- 物理机如下,就像一个庄园,独立占用了一块土地,花园都是自己的,其他人无法共享使用。
- 虚拟机相当于开发商的一个楼盘,一栋楼一套房子一户人家,共享一块宅基地,共享小区的花园,共享小区的游乐设施。
- 容器相当于在 1 个房子里面,开辟出来一个又一个的胶囊公寓,共享这套房子的卫生间、共享厨房、共享 WiFi,只有衣服、电脑等私人物品是你自己的。
2.2 为什么要虚拟化、容器化?
(1)我们从上面的历史发展来看,虚拟化和容器化的最主要目的就是资源隔离,随着资源隔离的实现逐渐也带来了更大的收益。
- 资源利用率高:将利用率较低的服务器资源进行整合,用更少硬件资源运行更多业务,降低 IT 支出和运维管理成本。比如上图中我们的土地直接复用, 使用这块土地的人多了,但是成本还是庄园那块地。
- 环境标准化:一次构建,随处执行。实现执行环境的标准化发布,部署和运维。开发过程中一个常见的问题是环境一致性问题。由于开发环境、测试环境、生产环境不一致,导致有些bug 并未在开发过程中被发现。而 Docker 的镜像提供了除内核外完整的运行时环境,确保了应用运行环境一致性,从而不会再出现 「这段代码在我机器上没问题啊」 这类问题。
- 资源弹性伸缩:根据业务情况,动态调整计算、存储、网络等硬件及软件资源。比如遇到双 11 了,把服务扩容 100 个,双 11 过去了, 把扩容的 100 个收回去。
-
差异化环境提供:同时提供多套差异化的执行环境,限制环境使用资源。比如我的服务一个以来 Ubuntu 操作系统,一个服务依赖 CentOS 操作系统,但是没有预算购买两个物理机,这个时候容器化就能很好的提供多种不同的环境。
-
沙箱安全:为避免不安全或不稳定软件对系统安全性、稳定性造成影响,可使用虚拟化技术构建虚拟执行环境。比如我在容器里面执行 rm -rf /* 不会把整个服务器搞死,也不影响其他人部署的程序使用。
- 容器对比虚拟机更轻量,启动更快:传统的虚拟机技术启动应用服务往往需要数分钟,而 Docker 容器应用,由于直接运行于宿主内核,无需启动完整的操作系统,因此可以做到秒级、甚至毫秒级的启动时间。大大的节约了开发、测试、部署的时间。docker 不需要虚拟内核,所以启动可以更快,相当于windows 的开机时间省去了。
- 维护和扩展容易:Docker 使用的分层存储以及镜像的技术,使得应用重复部分的复用更为容易,也使得应用的维护更新更加简单,基于基础镜像进一步扩展镜像也变得非常简单。此外,Docker 团队同各个开源项目团队一起维护了一大批高质量的 官方镜像,既可以直接在生产环境使用,又可以作为基础进一步定制,大大的降低了应用服务的镜像制作成本。比如 docker hub 提供了很多镜像,各个系统的一个命令就可以拿到了,研发也可以自己定制镜像分享给各个产品。
2.3 虚拟化实现方式
2.3.1 应用程序执行环境分层
- 硬件层:提供硬件抽象,包括指令集架构、硬件设备及硬件访问接口。
- 操作系统层 :提供系统调用接口,管理硬件资源。
- 程序库层:提供数据结构定义及函数调用接口。
2.3.2 虚拟化常见类别
(1)虚拟机:
- 存在于硬件层和操作系统层间的虚拟化技术。 虚拟机通过“伪造”一个硬件抽象接口,将一个操作系统以及操作系统层以上的层嫁接到硬件上,实现和真实物理机几乎一样的功能。比如我们在一台 Windows 系统的电脑上使用 Android 虚拟机,就能够用这台电脑打开 Android 系统上的应用。
(2)容器:
- 存在于操作系统层和函数库层之间的虚拟化技术。 容器通过“伪造”操作系统的接口,将函数库层以上的功能置于操作系统上。以 Docker 为例,其就是一个基于 Linux 操作系统的 Namespace 和 Cgroup 功能实现的隔离容器,可以模拟操作系统的功能。简单来说,如果虚拟机是把整个操作系统封装隔离,从而实现跨平台应用的话,那么容器则是把一个个应用单独封装隔离,从而实现跨平台应用。所以容器体积比虚拟机小很多,理论上占用资源更少。
- 容器化就是应用程序级别的虚拟化技术。容器提供了将应用程序的代码、运行时、系统工具、系统库和配置打包到一个实例中的标准方法。容器共享一个内核(操作系统),它安装在硬件上。
(3)JVM 之类的虚拟机:
- 存在于函数库层和应用程序之间的虚拟化技术。 Java 虚拟机同样具有跨平台特性,所谓跨平台特性实际上也就是虚拟化的功劳。我们知道 Java 语言是调用操作系统函数库的, JVM 就是在应用层与函数库层之间建立一个抽象层,对下通过不同的版本适应不同的操作系统函数库,对上提供统一的运行环境交给程序和开发者,使开发者能够调用不同操作系统的函数库。
2.4 常见虚拟化的实现
2.4.1 主机虚拟化(虚拟机)的实现
(1)主机虚拟化的原理是通过在物理服务器上安装一个虚拟化层来实现。这个虚拟化层可以在物理服务器和客户操作系统之间建立虚拟机,使得它们可以独立运行。
(2)从软件框架的角度上,根据虚拟化层是直接位于硬件之上还是在一个宿主操作系统之上,将虚拟化划分为 Type1 和 Type2。
(3)Type1 类的 Hypervisor(Hypervisor 是一种系统软件,它充当计算机硬件和虚拟机之间的中介,负责有效地分配和利用由各个虚拟机使用的硬件资源,这些虚拟机在物理主机上单独工作,因此, Hypervisor 也称为虚拟机管理器。 )直接运行在硬件之上,没有宿主机操作系统, Hypervisor 直接控制硬件资源和客户机。典型框架为 Xen、 VmwareESX。
(2)Type2 类的 Hypervisor 运行在一个宿主机操作系统之上(Vmware Workstation)或者系统里面,Hypervisor 作为宿主机操作系统中的一个应用程序,客户机就是在宿主机操作系统上的一个进程。
2.4.2 容器虚拟化的实现
(1)容器虚拟化实现原理:
- 容器虚拟化,有别于主机虚拟化,是操作系统层的虚拟化。通过 namespace 进行各程序的隔离,加上 cgroups 进行资源的控制,以此来进行虚拟化。
(2)容器虚拟化基础之NameSpace以及什么是 Namespace(命名空间):
- namespace 是 Linux 内核用来隔离内核资源的方式。通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的资源,这两拨进程根本就感觉不到对方的存在。具体的实现方式是把一个或多个进程的相关资源指定在同一个 namespace 中。
- Linux namespaces 是对全局系统资源的一种封装隔离,使得处于不同 namespace 的进程拥有独立的全局系统资源,改变一个 namespace 中的系统资源只会影响当前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,可以使用 | (按位或)组合这些参数。
(3)举个例子:
- 三年一班的小明和三年二班的小明,虽说他们名字是一样的,但是所在班级不一样,那么,在全年级排行榜上面,即使出现两个名字一样的小明,也会通过各自的学号来区分。对于学校来说,每个班级就相当于是一个命名空间,这个空间的名称是班级号。
- 班级号用于描述逻辑上的学生分组信息,至于什么学生分配到 1 班,什么学生分配到2 班,那就由学校层面来统一调度。
(4)如下表是namespace系统调用参数介绍:
namespace | 系统调用参数 | 被隔离的全局系统资源 | 引入内核版本 |
---|---|---|---|
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 |
User | CLONE_NEWUSER | 用户和用户组 | 3.8 |
(5)以上命名空间在容器环境下的隔离效果:
- 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。
(6)想想以下如果我们要隔离两个进程需要怎么办?
- 首先容器进程与进程之间需要隔离,所以需要 PID 隔离。
- 首先容器 A 进程不能读取容器 B 进程通讯内容需要隔离信号量等,所以需要 IPC隔离。
- 首先容器 A 进程不能读取容器 B 进程的文件,所以需要 Mount 隔离。
- 首先容器 A 进程不能读取容器 B 进程的 socket,所以需要网络隔离、主机隔离。
- Docker 允许用户在主机和容器间共享文件夹,同时不需要限制容器的访问权限,这就容易让容器突破资源限制。需要借助用户空间来完成用户之间的隔离。
2.4.3 容器虚拟化基础之cgroups
(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 | 限制使用的内存页数量。 |
pids | 限制任务的数量。 |
rdma | 限制 RDMA 资源(Remote Direct Memory Access,远程直接数据存取) |
2.4.4 容器虚拟化基础之LXC
(1)LXC 是什么?
- LXC(LinuX Containers) Linux 容器,一种操作系统层虚拟化技术,为 Linux 内核容器功能的一个用户空间接口。它将应用软件系统打包成一个软件容器(Container),内含应用软件本身的代码,以及所需要的操作系统核心和库。透过统一的名字空间和共享 API 来分配不同软件容器的可用硬件资源,创造出应用程序的独立沙箱运行环境,使得 Linux 用户可以容易的创建和管理系统或应用容器。
- LXC 是最早一批真正把完整的容器技术用一组简易使用的工具和模板来极大的简化了容器技术使用的一个方案LXC 虽然极大的简化了容器技术的使用,但比起直接通过内核调用来使用容器技术,其复杂程度其实并没有多大降低,因为我们必须要学会 LXC 的一组命令工具,且由于内核的创建都是通过命令来实现的,通过批量命令实现数据迁移并不容易。其隔离性也没有虚拟机那么强大。
- 后来就出现了 docker,所以从一定程度上来说, docker 就是 LXC 的增强版。
3. Docker的简介
3.1 Docker的本质
(1)Docker是什么?
- Docker 本质其实是 LXC 之类的增强版,它本身不是容器,而是容器的易用工具。容器是 linux 内核中的技术, Docker 只是把这种技术在使用上简易普及了。 Docker 在早期的版本其核心就是 LXC 的二次封装发行版。
- Docker 作为容器技术的一个实现,或者说让容器技术普及开来的最成功的实现。
- Docker 是基于 Go 语言实现的一个开源项目,它的主要目标是“Build, Ship andRun Any APP, Anywhere”,即通过对组件的封装、分发、部署、运行等生命周期的管理,使得用户的应用及其运行环境能够做到“一次封装,到处运行”。
- 早期 Docker 利用 LXC 做容器管理引擎,但是在创建容器时,不再使用模板去安装生成,而是通过镜像技术(把一个操作系统用户空间所需要使用到的组件事先编排好,并整体打包成一个文件, image 文件),镜像文件集中放在一个仓库中。当需要创建容器时, Docker 调用 LXC 的工具 lxc-create,但不再通过 lxc 的模板去安装,而是连接到镜像服务器上下载匹配的镜像文件,而后基于镜像启动容器。
- 所以, Docker 极大的简化了容器的使用难度。以后我们创建启动容器,只需要一个命令, docker-run,docker-stop 就可以启动停止一个容器了。
(2)Docker的引擎迭代:
- Docker 早期是基于 LXC 容器管理引擎实现,当后来成熟之后, Docker 自建了一个容器引擎叫 libcontainer,后来 CNCF 的介入, Docker 又研发了一个工业化标准的容器引擎 runC,目前所使用的新版 Docker,所使用的容器引擎就是 RunC。
3.2 Docker和虚拟机的区别
(1)区别如下表所示:
传统虚拟机 | Docker 容器 | |
---|---|---|
磁盘占用 | 几个 GB 到几十个 GB左右 | 几十 MB 到几百 MB 左右 |
CPU内存占用 | 虚拟操作系统非常占用CPU 和内存,需要通过虚拟层调用占用率高 | Docker 引擎占用资源极低,直接作用于硬件资源占用少 |
启动速度 | (从开机到运行项目)几分钟 | (从开启容器到运行项目)几秒 |
安装管理 | 需要专门的运维技术 安装、管理方便应用部署 | 手动部署,速度慢 体系化部署,可以自动化,速度快 |
隔离性 | 系统级别 | 进程级别 |
封装程度 | 打包整个操作系统 | 打包项目代码和依赖信息 |
3.3 Docker为什么比虚拟机资源利用率高,启动快
(1)Docker比虚拟机资源利用率高,启动快如下解释:
- docker 有比虚拟机更少的抽象层。 docker 不需要 Hypervisor 实现硬件资源虚拟化,运行在 docker 容器上的程序直接使用的是实际物理机的硬件资源。因此在 cpu、内存利用率上 docker 将会在效率上有明显的优势。 docker 利用的是宿主机的内核,而不需要Guest OS,节省了 Guest OS 占用的资源。
- docker 不需要 Guest OS,创建一个容器时,不需要和虚拟机一样重新加载一个操作系统内核。从而避免引寻、加载操作系统内核返回时耗时耗资源的过程,当新建一个虚拟机时,虚拟机软件需要加载 Guest OS,返回新建过程是分钟级别的。而新建一个docker 容器只需要几秒钟。
3.4 Docker 和 JVM 虚拟化的区别?
(1)区别如下表:
JVM | 容器 | |
---|---|---|
性能 | Jvm需要占用一定的的CPU 和内存 | 基本没有损失 |
虚拟层面 | 基于 JVM 虚拟机,更加上层 | 基于操作系统,更加通用 |
代码无关性 | 一个特定代码的执行平台,它是运行时才存在的,只能支撑特定代码的执行,并且必须是在 jvm 进程内 | 模拟了一整个操作系统,它是静态存在的,可以支撑任何相同平台的应用程序 |
主机隔离性 | jvm 不隔离主机 通过命名空间实现隔离 | 通过命名空间实现隔离 |
4. Docker的版本介绍
(1)Docker 发展过程中衍生了以下版本,目前我们学习和使用提到的版本是 docker-ce。
- lxc:上文中提到, lxc 是最早的 linux 容器技术,早期版本的 docker 直接使用lxc 来实现容器的底层功能。虽然使用者相对较少,但 lxc 项目仍在持续开发演进中。
- libcontainer: docker 从 0.9 版本开始自行开发了 libcontainer 模块来作为 lxc 的替代品实现容器底层特性,并在 1.10 版本彻底去除了 lxc。在 1.11 版本拆分出 runc 后,libcontainer 也随之成为了 runc 的核心功能模块, runc 后续变成了容器标准。
- moby: moby 是 docker 公司发起的开源项目,其中最主要的部分就是同名组件 moby,事实上这个 moby 就是 dockerd 目前使用的开源项目名称, docker 项目中的 engine(dockerd)仓库现在就是从 moby 仓库 fork 而来的,使用 containerd 作为运行时标准。 https://mobyproject.org/
- docker-ce: docker 的开源版本, CE 指 Community Edition。 docker-ce 中的组件来自于 moby、 containerd 等其他项目。https://www.docker.com/pricing/
- docker-ee: docker 的收费版本, EE 指 Enterprise Edition。其基础组件来源和docker-ce 是一样的,但附加了一些其他的组件和功能。https://www.docker.com/pricing
(2)Docker 官方网站:https://www.docker.com/。
5. Docker的架构介绍
(1)官方架构:Docker 使用客户端-服务器 (C/S) 架构模式,使用远程 API 来管理和创建 Docker 容器。Docker 容器通过 Docker 镜像来创建。
- Docker 仓库(Registry):Docker 仓库用来保存镜像,可以理解为代码控制中的代码仓库。 Docker Hub 供了庞大的镜像集合供使用。
- Docker daemon:Docker daemon 是服务器组件,是 Docker 最核心的后台进程,我们也把它称为守护进程。
- Docker 客户端(Client):Docker 客户端通过命令行或者其他工具使用 Docker API 与 Docker 的守护进程通信。
- Docker 主机(Host):一个物理或者虚拟的机器用于执行 Docker 守护进程和容器。
- Docker 镜像(Images):Docker 镜像是用于创建 Docker 容器的模板。
- Docker 容器(Container):容器是独立运行的一个或一组应用。
(2)生活案例来理解:
- 上面概念比较难以理解,我们列举个生活中的案例,以一家人去旅游入住酒店为例。比特就业课我们一家人和朋友一块旅游去酒店,我们就是 Docker Client
- 到酒店办理入住,办理退房,缴费需要酒店前台提供各种服务,酒店前台就是我们的Docker Daemon, Docker 的核心服务端。
- 酒店是建在美丽的海边,酒店的宅基地和大楼就是我们实际的物理服务器或者虚拟服务器,也就是 Docker Host。
- 酒店就 1000 多个房间,每个房间里面不一样,有标间、大床房、家庭房等,这就是Docker 镜像仓库
- 酒店的标准的房间豪华大床房和双人标间,这个就是 Docker 镜像,我们客户是没有办法修改的。
- 我们办理完入住了一个豪华大床房,然后把行李,个人物品带到了一个具体的房间号,比如 9527,那么这个房间我们可以使用了,朋友也开了一间豪华大床房,虽然豪华大床房一样,当时我们携带的物品,我们的洗漱时间,睡觉时间都不一样,这个就是容器 Docker Container。
- 容器的销毁,也就是我们一周后旅游结束了,搬出了酒店,酒店把我们的房间恢复了镜像原来的样子。
6. Docker的生态
6.1 新时代软件诉求
(1)我们来考虑 2 个问题, Docker 为什么要设计镜像,然后又搭建个 Docker Hub,搞个镜像仓库呢?我们来看下现在的时代发生了什么数据量疯狂增长:
- 随着物联网、边缘计算等智能终端设备不断普及,受到来自物联网设备信号、元数据、娱乐相关数据、云计算和边缘计算的数据增长的驱动,全球数据量呈现加速增长。
- 根据 IDC 分布的《数据时代 2025》预测,全球数据量将从 2018 年的 33ZB 增至 2025年的 175ZB,增长超过 5 倍;中国平均增速快于全球 3%,预计到 2025 年将增至48.6ZB,占全球数据圈的比例由 23.4%提升至 27.8%。其中,中国企业级数据量将从2015 年占中国数据量的 49%增长到 2025 年的 69%。
(2)处理能力快速增加:
- 腾讯云全球服务器数量 100w+,数据量 EB+; 2020 年阿里云:在全国已建成 5 大超级数据中心,阿里云在全球 22 个地域部署了上百个数据中心,服务器的总规模数已经接近 200 万台。
- 某省疾控中心疫苗预约系统、全员核酸检测系统、健康码系统共 300 余台服务器,并为核酸检测系统快速扩容计算和存储资源。
(3)软件需求爆发式增长:
-
软件发布频繁:
- 研发模式从瀑布开发演变为敏捷开发,原来 3 个月上一次新功能,现在两周一次,而开发过程中我们也经常遇到需要修改需求,然后变更再发布的情况。
- 软件上线有问题需要快速回滚,对软件有着极强的版本管理和回滚诉求。
-
软件需要共享:软件的研发人员、研发公司在设计、研发好一款软件的时候,如何方便的共享给他人,而又能快速的使用起来。
-
环境搭建复杂,技术种类繁多:每个项目组使用的语言不一样,需要不同的环境,每个都得搞一套。每次都要从 yum开始一个个完成部署安装,每次都有各种奇怪的问题,运维成本很高。
6.2 Docker的解决方案
(1)云时代需要我们针对这些诉求有一套针对的解决方案。
- 我们要处理海量的数据,如何处理呢?购买大量的服务器,并研发对应软件。
- 开发的需求需要频繁的变更上线,如何才能将修改的代码快速的分发到几百或者几千台服务器呢?如何共享软件呢?搞一个中心仓库,让各个服务器去下载软件包,安装,所以 CentOS 搞了 yum 仓库,docker 设计了镜像仓库, docker hub 是公共的托管仓库。
- 软件设计好以后,怎么快速安装启动,有问题回滚呢?将 docker 需要的所有信息设计一套软件格式,把所有的依赖搞进去,并打上版本标签,这样不会换一个服务器各种问题,所以 Docker 设计了镜像。
- 不同的开发环境怎么搭建呢,一会 java,一会 C++?docker 设计了镜像来应对,镜像里面存放了需要运行的环境,就像我们的 iPhone 内置 ios,我们的华为 mate 70 内置鸿蒙一样,一条命令就可以完成某个环境的搭建。