Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。
本篇内容主要介绍了:Docker 技术介绍、Docker 的基本概念与组成以及部署技术发展史。
Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中,然后发布到任何流行的 Linux 或 Windows操作系统的机器上,也可以实现虚拟化。容器是完全使用沙箱机制,相互之间不会有任何接口,更重要的是容器性能开销极低。
Docker 的开源项目诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc 。
在计算机技术中,虚拟化(Virtualization)是一种资源管理技术,是将计算机的各种实体资源,如服务器、网络、内存及存储等,予以抽象、转换后呈现出来,打破实体结构间的不可切割的障碍,使用户可以用比原本的组态更好的方式来应用这些资源。
作为一种新兴的虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。
具体说来,Docker 在如下几个方面具有较大的优势:
Docker 的架构图:
一个完整的 Docker 主要由以下几部分构成:
组成部分 | ||
---|---|---|
1 | Docker 主机 | Docker 主机(Host)是可以是一个物理机或者虚拟机,用于运行 Docker 服务进程和容器 |
2 | Docker 服务端 | Docker 服务端(Server)也叫 Docker Daemon 其实就是 Docker 的服务端。它负责监听 Docker API 请求(如 Docker Client)并管理 Docker 对象(Docker Objects),如镜像、容器、网络、数据卷等 |
3 | Docker 客户端 | Docker 客户端(Client)是用户与 Docker 进行交互的最主要方式。当在终端输入 Docker 命令时,对应的就会在服务端产生对应的作用,并把结果返回给客户端。Docker Client 除了连接本地服务端,通过更改或指定 DOCKER_HOST 连接远程服务端 |
4 | Docker 镜像 | Docker 镜像(Images)可以理解为是是用于创建 Docker 容器的模板 |
5 | Docker 容器 | Docker 容器(Container)是独立运行的一个或一组应用,是镜像运行时的实体 |
6 | Docker 仓库 | Docker 仓库(Registry)是保存镜像的仓库,类似于 git 和 svn 这样的版本控制系统 |
Linux 操作系统包括 Linux 内核和用户空间两部分,当 Linux 系统启动后,会挂载 root 文件系统为其提供用户空间支持。Docker 镜像就类似于这样一个 root 文件系统,Docker 镜像中含有启动容器所需要的文件系统及所需内容,因此镜像主要用于创建并启动 Docker 容器。
Docker 镜像里包含一层层的文件系统,叫做 Union File System(Union FS,联合文件系统)。联合文件系统可以将多个目录挂载到一起,从而形成一整个虚拟文件系统,该虚拟文件系统的目录结构就像是普通的 Linux 目录结构一样。Docker 通过这些文件系统,再加上宿主机的内核就构成了一个 Linux 的虚拟环境。
在联合文件系统中,每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置只读(readonly)、读写(readwrite)和写出(writeout-able)三种权限。
但是 Docker 镜像中每一层的文件系统都是只读的,构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做了一层的修改,增加了一层文件系统,这样一层一层的网上叠加,上层的修改会覆盖底层该位置的可见性。当我们使用镜像的时候,只会看到一个完整的整体,而不知道也无需知道里面有几层文件系统。
Docker 容器就相当于从模板复制过来运行时的实例,Docker 容器可以被创建、复制、暂停和删除等。每一个 Docker 容器在运行时都是以镜像为基础层,并在镜像的基础上创建当前容器的存储层,容器存储层的生存周期与容器是一致的,因此当某一个容器删除后,该容器存储层的数据也会随之被删除掉。
Docker 仓库是一个集中存储、分发 Docker 镜像的仓库,客户端的 docker pull 和 docker push 命令都是直接与 Docker 仓库发生交互的。
一个 Docker 仓库可以包含多个仓库,每个仓库可以包含多个标签,这些标签对应每一个镜像。一般情况下,一个仓库可能会包含同一个软件的不同版本(例如 Nginx 1.18 和 1.20 版本等)镜像,标签就类似于该软件的不容版本,客户端可以通过 <仓库名>:<标签>
的格式来指定具体版本的软件镜像,如不指定,默认会以 latest
作为标签。
按照镜像是否公开,Docker 仓库可分为公共仓库和私有仓库两种。Docker hub 作为 Docker 官方的公共仓库,已经保存了大量的常用镜像,可以方便用户直接使用;如果不想使用公共仓库,也可使用 Image registry 这一 Docker 官方提供的私有仓库部署工具。
在虚拟机出现于业务环境中以前,应用往往部署在物理机器上,但是 无论是 Windows 服务器还是 Linux 服务器都缺乏相应的技术手段保证一台服务器上可以稳定且安全的同时运行多个应用,因此,这样的部署方式存在弊端就是:空闲资源难以得到复用,部署异构系统时需要重新采购物理资源,大量中小容量的机器使得运维成本提升。
在这样的情况下,如何降低基础设施的管理成本便成为急切的需求。
为解决上述问题,VMware 推出了他们的产品————虚拟机,虚拟机的出现使得用户在一台物理机上能够独立运行多个相互隔离的系统,通过对资源的抽象化使得主机资源能够被有效复用,这对于企业IT管理十分有益。
然而,虚拟机同样也会带来一些问题:
此时需求便关注到如何减少虚拟化时的资源损耗,同时还能保证隔离性,以及使应用的上线周期更短,这便引导了容器技术的发展。
现代的容器技术起源于 Linux ,其是很多人长期的、持续的贡献产物,自 2000 年开始各家类 Unix操 作系统厂商开始陆续推出容器相关的项目。
2008 年 Google 的 Cgroups 贡献给 Linux kernel 2.6.24 后,创造了LXC( Linux Containers),实现了多个独立的 Linux 环境(容器)可运行在同一个内核。对于一个完整独立运行环境来说,需要包含三个关键:环境隔离、资源控制和文件系统。在 LXC 中则分别通过 Namespace、Cgroups、rootfs 来实现相应的能力:
在通过 LXC 构建容器后,一台宿主机能够实现多个相互隔离应用的运行。同时,共享内核使得每个容器又很轻量,解决了运行大量隔离应用时虚拟机资源消耗过重的弊端。
然而,LXC 虽解决了应用隔离的问题,但却只是轻量的容器技术,没有解决各平台软件交付标准不统一的问题,如不同的软件交付工具、应用运行规范不统一、环境依赖复杂等带来的配置开销。这些问题使容器技术的推广依然比较有限,直到 Docker 的出现。
早期 Docker 是基于 LXC 开发,因此 Docker 容器也有着和 LXC 相似的特性,仅需要较少资源便可以启动。但不同于 LXC,Docker除了容器运行,还是一个打包、分发和运行应用程序的平台。Docker 允许将应用和其依赖的运行环境打包在一起,打包好的 “集装箱“(镜像)能够被分发到任何节点上执行,无需再进行配置环境的部署。这样使得 Docker 解决了开发和部署应用时环境配置的问题,规范化了应用交付和部署,降低了部署测试的复杂度以及开发运维的耦合度,极大提升了容器移植的便利性,便于构建自动化的部署交付流程。
Docker 和虚拟机都是资源虚拟化发展的产物,但二者在架构上又有区别:
虚拟机的启动时间可能是分钟级的,而 Docker 容器创建是秒级别。对于硬盘的使用 Docker 一般为 MB 级别,远小于包含操作系统的虚拟机 GB 级磁盘使用量。对于操作系统来说,能支持运行的 Docker 容器数量远多于虚拟机。
Docker 容器技术在快速部署、环境标准化、隔离性方面的优势得到了开发人员普遍认可,但是如果以一个完整 PaaS 平台为标准来衡量这些还不够。首先,Docker 提供了名为 “容器” 的隔离环境,但是面对多容器间有拓扑有关联的场景,Docker还难以应对;其次,虽然容器解决了应用交付规范问题,但难以实现完全应用托管;另外,随着基础设施规模的扩大,开发中心必将分布式化,调度问题就需要解决。
2014 年 7 月 Docker 宣布收购单机容器编排软件 Fig(后来命名为 Docker Compose),并在同年 12 月推出了自己的容器集群编排项目 Docker Swarm。Docker Swarm 成功打造了两方面能力:
Docker Compose 和 Dockers Swarm 可以基本满足开发人员对于 PaaS 平台的需求,对于Docker向平台化发展的规划具有基石一般的意义。至此,Docker未来的发展似乎很乐观,但是随着Google加入,容器市场的局面发生了重大改变。
2014 年 Google 开源了名为 Kubernetes(简称K8S)的项目,它是由 Google 内部 Borg 项目而开源出来的容器集群管理系统。Kubernetes 继承了 Google 丰富的大规模集群运维的经验和基因,能够提供复杂的、大规模的容器编排管理服务。2015 年 Google 发布了 Kubernetes 第一个商业版本,代表 Kubernetes 进军生产级容器规模管理,也意味着开始与 Docker 竞争 PaaS 平台的未来版图。
Kubernetes 集群由两类节点构成:Master Node 和 Worker Node。Kubernetes 采用声明式的设计,任何操作指令都通过声明式 API 与 Master 通信。Master Node 可响应 API 声明,进行集群管理和容器调度。容器则运行在 Worker Node,Worker 负责响应 Master 指令,执行容器启停等维护操作。
除了紧密的容器关系,一个面向生产的编排系统必然应当支持更多的容器关系,所以 Kubernetes 还提供了 Deployment 无状态多副本关系、StatefulSet 有状态多副本关系、Job 一次性长任务等许多对象以满足多样的编排需求。这些对象的基础调度单元还是 Pod,由控制器 Controller 控制 Pod 对象的状态来实现声明的编排关系。
Kubernetes 使开发人员和工程师拥有了快速处理大型项目所需的管理工具和基础架构。从负载测试或创建过渡环境,到将业务和在线应用程序移至生产环境,Kubernetes 集群都可以对其进行管理。