随着大数据和移动技术的快速发展以及企业业务需求的不断变化,越来越多的企业选择使用云服务器来处理业务,以适应庞大数据量和复杂业务下基础设施部署困难、运营成本高的现状。在这样的背景下,诞生了许许多多的云服务商,一系列和云服务相关的概念如 IaaS、PaaS、SaaS 也孕育而生。
在云服务发展的过程中,容器技术和云服务促成了相互推进和成就,而其中知名度最高的两个开源项目毫无疑问便是 Docker 和 Kubernetes。那么 Docker 和 Kubernetes 为什么会诞生,前世今生是什么,又有怎样的联系和关系呢?本文将详细介绍。
容器技术的由来
在虚拟机出现前的业务环境中,应用往往部署在物理机器上,但这样的部署方式存在一些弊端:
1、空闲资源难以得到复用;
2、部署异构系统时需要重新采购物理资源;
3、大量中小容量的机器使得运维成本提升。
在这样的情况下,如何降低基础设施的管理成本便成为急切的需求。虚拟机的出现使得用户在一台物理机上能够独立运行多个相互隔离的系统,通过对资源的抽象化使得主机资源能够被有效复用,这对于企业 IT 管理十分有益。
然而,虚拟机同样也会带来一些问题:大量独立系统的运行会占用许多额外开销,消耗宿主机器资源,资源竞争时可能会严重影响系统响应;此外,每运行新的虚拟机都需要重新配置一遍环境,和在物理机上的情况基本无异,重复的环境配置操作则会消耗开发和运维人员的工作时间。此时需求便关注到如何减少虚拟化时的资源损耗,同时还能保证隔离性,以及使应用的上线周期更短,这便引导了容器技术的发展。从 2000 年开始,各家类 Unix 操作系统厂商开始陆续推出容器相关的项目,2008 年 Google 的 Cgroups 贡献给 Linux kernel 2.6.24 后创造了 LXC( Linux Containers),实现了多个独立的 Linux 环境(容器)可运行在同一个内核。对于一个完整独立运行环境来说,需要包含三个关键:环境隔离、资源控制和文件系统。在 LXC 中则分别通过 Namespace、Cgroups、rootfs 来实现相应的能力。
环境隔离——Namespace:LXC 将内核全局资源封装,每个 Namespace 都有一份独立的资源,使得不同的进程在各自 Namespace 内对同一种资源的使用互不干扰,不会影响其他 Namespace 下的资源,实现了进程隔离。
资源控制——Cgroups:LXC 通过 Cgroups 对资源进行控制,限制和隔离一组进程对系统资源的使用。在 Cgroups 出现之前 OS 只能对一个进程做资源限制,而 Cgroups 可以对进程进行任意分组,如何分组由用户自定义,借此实现对于一个 Namespace 的资源调度管理。
文件系统——rootfs:rootfs 挂载在容器根目录上,用来为容器进程提供隔离后执行环境的文件系统。rootfs 包含一个操作系统所涉及的文件、配置和目录,在 Linux 操作系统内核启动时,内核会先挂载一个只读的 rootfs,当系统检测其完整性之后,决定是否将其切换到读写模式。
在通过 LXC 构建容器后,一台宿主机能够实现多个相互隔离应用的运行。同时,共享内核使得每个容器又很轻量,解决了运行大量隔离应用时虚拟机资源消耗过重的弊端。然而,LXC 虽解决了应用隔离的问题,但却只是轻量的容器技术,没有解决各平台软件交付标准不统一的问题,如不同的软件交付工具、应用运行规范不统一、环境依赖复杂等带来的配置开销。这些问题使容器技术的推广依然比较有限,直到 Docker 的出现。
Docker 的诞生
早期 Docker 是基于 LXC 开发,因此 Docker 容器也有着和 LXC 相似的特性,仅需要较少资源便可以启动。但不同于 LXC,Docker 除了容器运行,还是一个打包、分发和运行应用程序的平台。Docker 允许将应用和其依赖的运行环境打包在一起,打包好的“集装箱“(镜像)能够被分发到任何节点上执行,无需再进行配置环境的部署。这样使得 Docker 解决了开发和部署应用时环境配置的问题,规范化了应用交付和部署,降低了部署测试的复杂度以及开发运维的耦合度,极大提升了容器移植的便利性,便于构建自动化的部署交付流程。- ## Docker 与虚拟机架构对比
Docker 和虚拟机都是资源虚拟化发展的产物,但二者在架构上又有区别。虚拟机通过 Hypervisor 虚拟化主机硬件资源,然后构建客户机操作系统,由宿主机的管理程序管理;Docker 直接运行于主机内核,应用在主操作系统的用户空间上执行独立任务,不需要从操作系统开始构建环境,赋予了应用从交付到部署再到运维的独立性。
Docker 容器和虚拟机架构区别(图片来源:https://www.docker.com/resources/what-container)
虚拟机的启动时间可能是分钟级的,而 Docker 容器创建是秒级别。对于硬盘的使用 Docker 一般为 MB 级别,远小于包含操作系统的虚拟机 GB 级磁盘使用量。对于操作系统来说,能支持运行的 Docker 容器数量远多于虚拟机。
用 Docker 运行一个应用
那么,如何用 Docker 启动一个应用呢?对于启动应用来说,首先需要获得程序本身和所需要的环境配置。Docker 会将应用运行所有需要的静态资源如代码、运行时环境、配置封装为镜像,镜像通过 Union FS 采用分层存储架构,通过描述文件 Dockerfile 指令构建镜像层。Dockerfile 里包含多条指令描述该层应当如何构建,随着镜像层的逐层叠加,将一个完整的镜像所需要的信息全部包含。外部则通过统一文件系统将相互叠加的层整合起来,以只可读的统一文件(Union Read-Only File System)形式展现,这样的分层存储使得镜像的复用和定制变的更为容易,压缩了存储空间。镜像运行之后的实体是容器。Docker 容器同样采用分层存储,通过在镜像顶部增加一层可读可写层,外部以可读写的统一文件(Union Read-Wirte File System)形式展现。当容器运行时所有的进程操作均在可读可写层,而下面的镜像则不会被修改。容器的实质是进程,运行于自己独立的命名空间。容器存储层的生命周期和容器一样,一旦容器消亡,存储层也一并消亡,所以原生的容器是无状态的,这也就是为什么之后编排系统会引入有状态服务和持久化存储以支持有状态服务。
容器分层存储示意图(图片来源:https://docker-doc.readthedocs.io/zh_CN/latest/terms/layer.html)
Docker 架构
Docker 的镜像和容器通过三端的服务操作和管理:请求端 Docker Client、主机端 Docker Host 和远端拉取镜像的仓库 Registry。Docker Client 负责接收指令,与 Docker Host 下的守护进程 Docker Daemon 进行交互。Host 提供了执行和运行应用程序的完整环境,其中的 Docker Daemon 用于管理 Docker 镜像、容器、网络和存储卷,负责所有与容器相关的操作如拉取镜像、创建容器等,会不断侦听 Docker API 请求并进行处理。Registry 则是镜像管理的仓库,用户可以将创建的镜像提交到仓库进行存储,同时方便从仓库拉下来镜像为自己所用。
Docker 架构简图(图片来源:https://docs.docker.com/get-started/overview/#docker-architecture)
本文小结
虚拟化技术的出现使企业只需要通过线上租用即可获得所需的运行环境。而 Docker 容器技术实现了容器间的相互隔离并提供标准化和可复用的服务,给予开发、测试和生产环境统一的运行环境,为企业实现 DevOps 提供有力支持。
然而,Docker 也并非可完全取代虚拟机。与虚拟机相比,Docker 隔离性相对较弱,属于进程之间的隔离,而虚拟机可实现系统级别隔离;Docker 尚且面向开发人员,和虚拟机的可视化操作界面相比增加了学习成本,并且对 GUI 应用不够友好;对于使用场景而言,虚拟机面向虚拟资源隔离,容器面向应用隔离,因此在虚拟机上面跑容器并不冲突。
综上所述,虽然 Docker 容器技术帮助开发人员提升了生产力,但实际生产环境相比开发环境更复杂、规模更大,仅靠 Docker 容器技术并不意味着能把系统架构以微服务化的形式带上生产。当面对容器间通信处理、跨节点的资源调度等情况时,必须存在接口规范以及编排工具进行容器统一管理。那么主流容器编排工具有哪些?编排工具的作用又是什么呢?下一篇文章会详细介绍。
往期原创文章TCOS – 业界首个支持生产级大数据业务的容器操作系统
行业观察: 云+大数据+AI推动企业数据业务演进TCOS 2.0 发布 | 面向异构联邦的容器操作系统
作者介绍:
本文转载自大数据开放实验室,已经过对方授权。大数据开放实验室由星环信息科技(上海)有限公司运营,致力于大数据技术的研究和传播。
评论