容器是将来在共有云和私有云进行应用开发的主要趋势,可是容器究竟是什么,为何它们成为了一种广受欢迎的部署机制,并且你须要怎样来修改你的应用来为容器化的环境优化它?html
什么是容器?前端
容器技术的历史始于 2000 年的 SELinux 和 2005 年的 Solaris zones。今天,容器是由包括 SELinux、Linux 命名空间和控制组(cgroup)等几项内核特性构成,提供了用户进程、网络空间和文件系统空间的隔离。linux
为何它们如此流行?数据库
最近容器技术大规模的应用在很大程度上是因为旨在使容器更加易于使用的标准的发展,例如 Docker 镜像格式和分布模型,这个标准使用不可变镜像(immutable image),这正是容器运行时环境的起点,不可变镜像能够保证开发团队发布的镜像就是通过测试的,和部署到生产环境中的镜像是一样的镜像。缓存
容器所提供的轻量级隔离为一个应用组件提供了一个更好的抽象。在容器中运行的组件将不会干扰其它可能直接运行在虚拟机上的应用。它们能够避免对系统资源的争夺,并且除非它们共享一个持久卷,不然不会阻止对同一个文件的写请求。容器使得日志和指标采集的实践得以标准化,并且它们能够在物理机和虚拟机上支持更大的用户密度,全部的这些优势将致使更低的部署成本。服务器
咱们应该如何构建一个基于容器的应用呢?网络
将应用改成运行在容器中并非什么很高的要求。主要的 Linux 发行版都有提供了基础镜像,任何能够在虚拟机上运行的程序均可以在上面运行。可是容器化应用的趋势是遵循以下最佳实践:app
1. 实例是一次性的测试
你的应用的任何实例都不须要当心地保持运行。若是你的一个运行了许多容器的系统崩溃了,你还可以转移到其它可用的系统去建立新的容器。优化
2. 重试而不是崩溃
当你的应用的一个服务依赖于另外一个服务的时候,在另外一个服务不可用的时候它应该不会崩溃。例如,你的 API 服务正在启动并且监测到数据库不能链接。你应该设计它使得其不断重试链接,而不是运行失败和拒绝启动。当数据库链接断开的时候 API 能够返回 503 状态码,告诉客户端服务如今不可用。应用应该已经遵照了这个实践,可是若是你正在一个一次性实例的容器环境中工做,那么对这个实践的须要会更加明显。
3. 持久性数据是特殊的
容器是基于共享镜像启动,它使用了写时复制(COW)文件系统。若是容器的进程选择写入文件,那么这些写的内容只有在直到容器存在时才存在。当容器被删除的时候,写时复制文件系统中的那一层会被删除。提供给容器一个挂载的文件系统目录,使之在容器存活以外也能持久保存,这须要另外的配置,并且会额外消耗物理存储。明确的抽象定义了什么存储是持久的,催生出了实例是一次性的观点。拥有一个抽象层也使得容器编制引擎能够处理挂载和卸载持久卷的复杂请求,以便这些持久卷能够用于容器。
4. 使用 stdout 而不是日志文件
如今你或许会思考,若是持久的数据是特殊的,那么我用日志文件来作什么事情?容器运行时环境和编制引擎项目所采用的方法是进程应该写入 stdout/stderr,并且具备归档和维护容器日志的基础设施。
5. 敏感信息(以及其它配置信息)也是特殊的
你毫不应该将敏感信息例如密码、密钥和证书硬编码到你的镜像中。一般在你的应用与开发服务、测试服务,或者生产服务相交互时,这些敏感信息一般都是不一样的。大多数开发者并无访问生产环境的敏感信息的权限,因此若是敏感信息被打包到镜像中,那么必须建立一个新的镜像层来覆盖这个开发服务的敏感信息。基于这一点来看,你不再能使用与大家开发团队所建立的和质量测试所测试的相同的镜像了,并且也失去了不可修改的镜像的好处。相反的,这些值应该被存储在环境变量中文件中,它们会在容器启动时导入。
6. 不要假设服务的协同定位
在一个编排好的容器环境中,你会但愿让编排器将你的容器发送到任何最适合的节点。最适合意味着不少事情:它应该基于那个节点如今拥有最多的空间、容器所需的服务质量、容器是否须要持久卷,等等。这可能意味这你的前端、API 和数据库容器最终都会放在不一样的节点。尽管给每一个节点强制分配一个 API 容器是能够作到的(参考 Kubernetes 的 DaemonSets),但这种方式应该留给执行监控节点自身这类任务的容器。
7. 冗余/高可用计划
即便你没有那么多负载须要高可用性的配置,你也不该该以单路方式编写服务,不然会阻止它运行多份拷贝。这将会容许你运用滚动式部署,使得将负载从一个节点移动到另一个节点很是容易,或者将服务从一个版本更新到下一个版本而不须要下线。
8. 实现就绪检查和灵活性检查
应用在响应请求以前会有必定的启动时间是一件很正常的事情,例如,一个 API 服务器须要填充内存数据缓存。容器编排引擎须要一种方法来检测你的容器是否准备好服务用户请求。为一个新的容器提供就绪检查能够容许咱们进行滚动式部署,使得旧容器能够继续运行直到再也不须要它,这能够防止服务宕机。相似的,一个存活检查也是一种容器编排引擎持续检查容器是否在健康可用状态的方法。决定容器健康或者说“存活”应该由容器应用的建立者说了算。一个再也不存活的容器将会被结束,并且一个新的容器会被建立来替代它。
想查找更多资料?
我将会出席十月份的格雷丝霍普计算机女性峰会(Grace Hopper Celebration of Women in Computing),你能够在这里来看一下关于个人访谈:应用的容器化:是什么,为何,和如何实现。今年不去 GHC 吗?那你能够在 OpenShift 和 Kubernetes 的项目站点来了解关于容器、编排和应用的相关内容。