对于大多数团队而言,采用Docker主要是为了让开发人员更快地迭代和缩短发布周期,这对于开发环境是非常有益的,但对于生产环境,在同一台服务器上运行多个Docker容器,可能会导致安全方面的漏洞。事实上,几乎所有关于在生产环境中运行Docker的话题,都是围绕着将开发环境与生产环境区分开来进行的:一是编排,二是安全。
在生产环境中,Docker有时是用于接收公共网络流量的容器,有时则是用来处理来自负荷的异步后台作业,不管哪种用途,在生产环境中运行Docker与在其他环境中运行相比,最主要的差异就是都需要在其安全性与稳定性上投入较多的注意力。Docker生产环境很难管理,它简化了从开发到生产的工作流程,但同时增加了安全和编排的复杂度。所有在生产环境中运行Docker的团队,都会在传统的安全最佳实践上做出一项或多项妥协。如果无法完全信任容器内运行的代码,那么就只得选用容器与虚拟机一对一的拓扑方式。对于很多团队而言,在生产环境中运行Docker的优势远远大于其带来的安全与编排问题。
哪些东西不要Docker化?不要期望能在Docker容器中运行所有的东西。Herok风格的“十二要素”应用是最容易Docker化的,因为它们不维护状态。在理想的微服务环境中,容器能在几毫秒内启动、停止而不影响集群的健康或应用程序的状态。Docker还不适用于任何需要动态调整CPU和内存要求的应用。允许动态调整的代码已经完成,但尚不清楚何时才能在一般的生产环境中投入使用。目前,若对被容器的CPU和内存的限制进行调整,需要停止并重新启动容器。另外,对网络吞吐量有高要求的应用进行最佳优化时不要使用Docker,因为Docker使用iptables来完成宿主机IP到容器IP的NAT转换,通过禁用Docker的NAT来提升网络性能是可行的,但这是一个高级使用场景,很少有团队会在生产环境中这么做。
Docker最好的使用方式是将应用程序代码预先打包成一个Docker镜像,镜像通常包含所有的应用程序代码、运行时的依赖及系统的需求,而包含数据库凭证和其他敏感信息的配置文件通常在运行时添加,而非内建到镜像中。有些团队会在开发机上手工构建Docker镜像,然后推送到镜像仓库,之后再从仓库中拉取镜像到生产环境宿主机中,这是个很简单的用例,虽然行得通,但从工作流和安全角度考虑并不理想。一个更常见的生产环境示例是,使用持续集成/持续交付系统在应用程序代码或Dockerfile文件发生变更时自动构建新镜像。
最近几年,科技发展迅速,从物理服务器到虚拟服务器,从虚拟服务器到拥有PaaS环境的云计算,无论是否采用了全新架构,Docker镜像都可以在当前环境中很容易地被使用,要使用Docker,并不需要立即从单体应用程序迁移到面向服务架构,有很多用命允许在不同层次上集成Docker,以下是Docker常用的场景:
。使用以镜像为基础的部署方式取代常规代码部署系统;
。安全地在同一台服务器上运行遗留应用和新应用;
。使用一个工具链循序渐进地迁移到面向服务架构;
。管理云端或裸机上的水平扩展和弹性;
。确保从开发环境到预演环境再到生产环境的一致性;
。简化开发人员的机器设置和一致性;
将应用的后台程序迁移到Docker集群中,同时保持网页服务器和数据库服务器不变是开始使用Docker常见示例。另一示例是将应用的部分Restful Api迁移到Docker中运行,前端使用Nginx代理在遗留服务和Docker集群之间路由通信,通过使用此类技术,团队可以渐进式地从单体应用无缝地迁移到面向服务架构。如今的应用程序往往需要几十个第三方库,用于加速功能开发或连接第三方SaaS和数据库服务。每个库都可能产生BUG,或是让用户陷入版本依赖的泥沼,再加上库频繁更改,要在基础设施上完成工作代码的持续部署而不引起失败,压力巨大。Docker可贵的镜像思想使得技术团队在部署工作代码时,不论是单体架构、面向服务或是二者的混合,由于代码及其依赖捆绑在同一个镜像中,所使用的方式对每次部署都是可测试、可重复、文档化且一致的,一旦一个镜像构建完毕,就可以部署到任意多个运行着的Docker守护进程的服务器上。另外一个常见的Docker用例是跨环境部署一个单一容器,其典型的代码路径是从开发环境到预演环境再到生产环境,容器为整个代码路径提供了一个一致的、可测试的环境。作为一个开发人员,Docker模型允许在其个人电脑上调试与生产环境完全一致的代码,开发人员可以很容易地下载、运行和调试有问题的生产环境镜像,且无需事先对本地开发环境进行修改。