【编者的话】本篇文章是介绍Docker生态系统的第二篇,该文章首先简要介绍了Linux容器化的历史,然后介绍容器化的优点,再讨论Dockerfile的优点,最后讨论了容器化应用的架构,将容器化这个知识介绍的很到位。
将应用从开发周期中迁移出并部署到生产环境,这个过程中有很多的障碍。除去需要针对每个环境做具体的适配的具体开发工作,还要很多其他问题:检查必要的依赖组件、如何扩展应用、如何在不影响整体应用的情况下更新独立组件。
Docker容器化的思想和面向服务式的设计模式在试图解决这些问题。应用程序可以被拆分为可控的、功能性的组件,独立打包它们所需要的全部依赖,并且容易部署在非常规架构中。扩展和更新组件也被简化了。
在这个指南中,我们将讨论容器化的好处和Docker是如何帮助我们解决前面提到的问题。Docker是分布式容器部署的核心组件,它们可以容易的扩展和管理。
###Linux容器化的简要历史回顾
容器化和隔离化在计算领域并不是新概念。许多Unix系的操作系统已经实现了成熟的容器化技术超过十年了。
在2008年,LXC被添加到了系统内核中,它的编译模块构成了后续的容器化技术的基础。LXC综合了内核cgroups(隔离和跟踪资源的使用)的使用和命名空间(使组与组之间被隔离)的使用来实现线程隔离。
后来,Docker作为一种简化创建和管理容器的工具而被认识。它最初使用LXC作为默认的执行驱动器(而现在,这个模块已经被开发成了一个工具包libcontainer
)。虽然Docker没有引入什么新的思想,但是之所以它被一般的程序员和系统管理员所认识,是因为它简化了这个过程并标准化了接口。它在Linux程序员中再次激起了一个容器化的兴趣热潮。
虽然在本篇中我们会泛泛的讨论几个容器化的话题,但是由于其超高的人气和标准化的适用,我们将重点讨论Docker容器化。
###容器化可以给我们带来什么?
容器化给程序员、系统管理员和系统维护团队带来了很多富有新引力的好处。
下面将逐个介绍:
####对容器化应用的宿主机抽象化
容器是完全标准化的。这就是说容器与宿主机、与外界的一切通信交互都是用的预定义的接口。一个容器化的应用不依赖也不需要关心宿主机资源或者架构的细节。这就简化了部署时对操作系统的要求。同样,对于宿主机来说每一个容器都是个黑盒子,它也不需要关心容器内部的细节。
####容易扩展
宿主机与容器间的虚拟化带来的其中一个好处是:对于一个既定的应用,可以简单而直接的进行扩展。容器化的应用结合面向服务的设计奠定了易扩展性的基础。
当系统处于筹备阶段或者测试环境中,程序员可能在他们的工作站上部署多个容器。当容器进入生产环境,它们将再次被扩展。
####简单的依赖管理和应用版本控制
容器可以让程序员将一个应用或者应用组件与它们的依赖打包成一个单元。宿主机不需要去关心某一个容器运行所需要的依赖。只要它可以运行Docker,那么它就可以运行所以Docker容器。
这同样可以简化依赖管理和版本控制。宿主机和开发团队不再需要负责应用程序的依赖库管理,因为除了依赖相关的容器,它们都应该在容器内部。
####极度轻量化,隔离的运行环境
虽然容器不提供相同级别的隔离和资源管理虚拟化技术,但是这个折中却带来了其他优势:极度轻量化的运行环境。容器从线程级别上隔离,且共享着同一个内核。这就是说容器内并没有一个完整的操作系统,它可以瞬间启动。开发者可以从他们的工作站上无差别的启动几百个容器。
####层共享
“容器是轻量化的”还可以从另一个角度理解,它们是由层组成的。如果多个容器都基于同一个层,那么他们就可以共享底层,而不需要冗余,这使得后续的镜像占用硬盘空间可以最小。
####可组合型和可预测性
Docker文件允许用户自定义创建镜像时的具体操作。这就允许你去定制自己的运行环境,如果需要的话还可以保存在版本控制系统里。在同样环境下,同样的Docker文件编译出的容器镜像是严格一致的。
###用Dockerfile来可复现和一致构建
当可以采用交互式的操作来创建容器镜像时,通常来说及时把已知的操作加入到配置步骤中是比较好的使用习惯。Dockerfile是个简单的构建文件,它描述了如何从一个已知起点开始构建一个容器镜像。
Dockerfile非常的有用和容易掌握,它有以下几个优点:
- 易于版本控制:Dockerfile文件可以提交到一个版本控制软件中来追踪变更和复现任何错误。
- 可预测性:基于Dockerfile构建镜像可以从镜像创建的环节来避免操作上的错误。
- 问责制:如果要分享你的镜像,最好的办法是提供Dockerfile,这样别人可以创建这个镜像并审阅这个过程。Dockerfile提供了创建这个镜像的历史操作步骤。
- 灵活性:基于Dockerfile来创建镜像可以允许用户覆盖原有的默认交互操作。这就意味着不需要提供尽可能多的运行时选项来使得镜像有预期的功能。
在实现可重复的自动化构建容器方面,Dockerfile是一个非常好的工具。
###容器化应用的架构
在设计将被容器化部署的应用系统的架构时,首先要考虑的是应用系统的实际架构。一般来说,当采用面向服务式设计时,容器化应用工作的最好。
通常在用Docker来设计应用或者服务时,最好的方法是打破面向服务架构的设计,而采用独立容器的设计。Docker技术本身也倾向于这种设计,因为以后可以容易的扩展或者升级独立组件。
实现这种设计的应用应该具有以下几个特点:
- 它们不应该依赖或者关心宿主机上的任何细节。
- 每一个组件应该提供一致性的接口,使得调用者可以访问服务
- 每一个服务应该在初始化阶段从环境变量中获取参数
- 应用产生的数据应该通过Volumes存储在容器外部或者使用数据容器。
只要接口不变,这些策略使得组件可以被独立的更换或者升级。这使得它们向着水平扩展的方向发展,也就是根据瓶颈情况,每一个组件都可以扩展。
每一个组件通常都有定义合理的参数默认值,而不是硬编码它们。组件可以使用这些值作为候选值,但最好是从运行环境中获取这些值。这通常需要借助于服务发现工具,使得组件可以在启动过程中去查询这些参数。
将配置文件放在实际的容器外面,使得可以在不需要重新构建镜像的情况下容易的改变应用的行为。这样可以使得一个配置可以影响同一组件的不同实例。通常来说,面向服务的设计与运行环境配置策略配合的比较好,这是因为二者都需要更灵活的部署和更直接的扩展。
###用Docker Registry来做容器管理
一旦应用被切分为功能组件、配置为对其他容器做出适当反馈、在运行环境配置标识,下一步通常是确保你的容器可以通过registry获取。将容器镜像上传到registry可以使得Docker宿主机简单的通过已知名称来下拉容器并启动其实例。
满足这个要求的Docker registry有很多。有一些是对外公开的,任何人都可以查看和使用已经被提交的镜像,相对的也有些是私人的registry。镜像可以用标签标示,方便准确的获取或更新。
###总结
Docker提供了分布式容器部署的基础构建模块。通过将应用打包到它们各自的容器中,水平扩展变成了简单的启动或者关闭每个组件的实例群的过程。Docker不仅提供了创建镜像的必需工具,也提供了方便新用户或宿主机管理和分享镜像的工具。
尽管容器化应用提供了必要的隔离和打包来协助部署过程,还是需要一些在分布式集群或者宿主机上管理和批量化容器的工具。在下一个教程中,我们将讨论服务发现和全局配置存储如何协助集群容器部署。
###本系列的其他文章
Docker已经为开发者和管理员提供一个简单的平台来创建和部署可扩展的应用。在这个系列中,我们将探索Docker如何与其他组件整合在一起,并用它们提供的工具集来便捷地提供高可用性的分布式系统。
- 常用组件介绍(已翻译)
- 容器化的综述(本文)
- 服务发现和分布式配置存储(翻译中)
- 网络与通信(翻译中)
- 调度与编制(翻译中)