过去几年容器逐渐成为了打包和部署代码的流行的方式。容器镜像解决很多现有的打包和部署工具所带来的问题,初次以外,还为我们提供了构建分布式应用的全新的思路。就如 SOA 提倡将应用拆分为模块化的内聚的服务,容器应当进一步提倡将这些服务拆分为紧密协作的模块化容器。通过构建应用边界,容器使用户能够使用模块化,可重用的组件构建其服务,从而使得服务比单机容器构建的应用程序更可靠,更具可扩展性并且构建速度更快。
从 VM 向容器的演变从各种角度来说就如同当年从单机应用转化为模块化的面向对象的应用程序。容器镜像提供的抽象层与面向对象编程中类的抽象边界有很大的共同点,而且也提高了开发者的效率和程序的质量。就像正确的编码方式是将关注点分离为模块化对象一样,在容器中打包应用程序的正确方法是将关注点分离为模块化容器。根本上来说,这意味着不仅要将整个应用程序分解,而且要将任何一个服务器中的各个部分分解为多个模块化容器,这些容器易于参数化和重复使用。这就像现代语言中的标准语言库,大多数应用程序开发人员可以将由其他人编写的模块化容器组合在一起,并使用更高质量的组件更快地构建应用程序。
从模块化容器方面进行思考的好处很多,特别是模块化容器提供以下内容:
加快应用的开发,因为容器可以在团队甚至是大型社区之间进行复用
支持敏捷团队,因为容器边界是一个天然的边界,划分给各个团队。
支持关注点分离,并专注于开发特定功能从而减少复杂的依赖和不可测试组件。
从模块化容器构建应用程序意味着考虑协作提供服务容器的共生组,而不是一个容器提供一个服务。在 Kubernetes 中,这种模块化容器服务的实施者是 Pod。一个 Pod 是指一组共享文件系统,内核命名空间和 IP 地址的一组容器。Pod 在 K8s 集群中是调度的基本单位,正是因为 Pod 中容器的共生特性要求它们共同安排在同一台机器上,而可靠地实现这一点的唯一方法是将容器组作为原子调度单元。
当你从 Pod 的角度思考时,自然会出现一些模块化应用程序开发的通用模式,这些模式会多次重复出现。我相信,随着我们在 Kubernetes 的开发中向前发展,将会发现更多这些模式,但这里有三个我们常见的模式:
例子 1:Sidecar 容器
Sidecar 容器拓展并且加强主容器,他们融合当前已有的容器并且将它们完善。举个例子,假设有一个运行这 Nginx web 应用的容器。添加另一个容器将文件系统与 git 仓库同步,在容器间共享文件系统,从而实现 git 的提交并部署。但是这种模块化实现使得 git 同步器可以交给另一个容器开发,并且跨不同的 web 服务器复用。因为这种模块化,你只需要编写并测试单个 git 同步应用并且提供给多个应用使用。而如果有别的团队开发了这个工具,你甚至不需要重复开发。
例子 2:Ambassador 容器
Ambassador 容器代理外界至本地的连接。比如,现在有一个 Redis 集群,包含多个读者和单个写者。你可以创建一个 Pod,包含主应用和 Redis ambassador 容器。ambassador 容器作为代理分离读写请求分别交给对应的服务器。因为这两个容器共享一个网络命名空间,即他们共享一个 IP 地址,因此主应用可以用 localhost 访问 ambassador 服务,无需通过服务发现。从主应用的视角来看,就仿佛在 localhost 上连接了 redis 集群。这种方式非常方便,不仅因为不同的团队可以管理自己的组件,而且因为在开发环境中,你可以跳过代理,直接连接到 Redis 集群上。
例子 3:Adapter 容器
Adapter 容器标准化输入输出。假设现在需要监控 N 个应用,每个应用可能使用了不同的方法来输出监控数据(比如 JMX, StatsD 等)。但是每个监控系统都希望用一个一致的数据模型来管理收集的数据。通过使用 Adapter 模式来组合容器,你可以创建一个 pod 将应用容器和适配器容器组合起来,从而将同质的监控数据转化为单个同一个的表现形式。同样的,因为这些 Pod 共享命名空间和文件系统,这两个容器间的协作简单明。
Refrence
Sidecar PatternAmbassador Pattern