容器设计模式

容器化引领了云原生风潮。在云原生生态下,容器是最原子的个体,云原生下的容器非常类似上个世纪80年代末OOP引领变革后的模块/组件,而90年代中期GoF引领的设计模式将OOP推向了一个新的高度。因此,基于容器的设计模式方法论也可以驱使分布式系统设计模式的进一步发展,这也是了解容器设计模式的重要所在。Google的容器设计模式的小论文,是对容器设计模式的一个梳理,其文中提到的几种模式。这些模式基本是多年来Google内部Borg沉淀出的,目前,它们在k8s生态也有着广泛的落地。

用作者的话来说,容器是密闭的,包含了依赖关系,并且有一个原子的部署信号(“succeeded”/“failed”),他们很大程度上提升了之前在数据中心或云端部署软件的技术。然而,容器不仅仅只是一个很好的部署工具,容器最终会成为面向对象软件系统中的对象一样,并且因此驱使了分布式系统设计模式的发展。

文中提到了如下几类模式:

单容器管理模式(single-container management patterns)

即最传统的单容器模式。容器为定义接口提供了一个自然的边界,类似于对象边界。容器不仅能够暴露专用应用功能,还能够通过这个接口跟管理系统挂钩。这些接口分为两类:

  • Upward”方向,容器可以通过接口暴露一套丰富的应用程序信息。比如k8s的probe。
  • Downward”方向,容器通过接口提供定义生命周期的能力,从而使得写容器管理系统对容器内的软件组件进行控制管理。比如k8s的优雅关闭接口。

单节点多容器管理模式(single-node, multi-container application patterns)

即同时运行在单个主机上的共生容器。容器管理系统支持同时运行多个容器作为一个整体单元,这就是k8s中的Pod。

这里它又分为如下几种模式:

Sidecar pattern

利用共享存储能力进行同一Pod内的容器协同。

比如k8s官方示例中的tomcat容器和war包容器;业务应用容器和日志收集容器。

Sidecar模式是应用最广泛的一类模式,它进行了应用容器和工具容器的解耦,同时对主应用容器能力进行了扩展和增强。从而带来了如下好处:

  • 容器是资源分配的单元,拆分可以做更细粒度的分配;
  • 容器是打包的单元,拆分可以进行团队解耦;
  • 容器通过镜像机制成为可以复用的单元,拆分可以将工具容器镜像复用多个场景;
  • 容器有自己的控制边界,拆分可以进行故障隔离;
  • 容器是配置的单元,拆分方便部署,升级,回滚.

Ambassador pattern

利用共享网络的能力进行同一个Pod内的容器协同。

这种模式非常类似反向代理。业务容器可以利用Ambassador容器访问外部服务。比如k8s中业务容器通过redis ambassador访问redis服务。

Adapter pattern

利用容器间统一的接口进行协同,

这种模式通常应用与容器的监控管理

比如k8s中利用Prometheus进行分布式监控,Prometheus的Exporter就是对应的一个Adapter容器。

多节点应用模式(multi-node application patterns)

分布式场景下会有很多场景涉及到多个节点协同问题,这些问题可以使用容器的方式解决。因此衍生出如下几类模式:

Leader election pattern

利用容器来解决有状态场景下的选主问题。比如多个节点对应不同的pod,每个pod下有一个选主容器,这样选主容器进行选主行为,业务容器只需要关注业务开发,从选主容器读取选举结果即可。

Work queue pattern

工作队列模式主要利用容器解决基于队列的计算资源调度问题

由于容器天然具有弹性,可以利用多个节点的容器协同来实现动态计算资源调度,具体如上图。

Scatter/gather pattern

分散收集模式主要利用容器解决弹性计算问题。

根容器接受到来自客户端的服务请求,将服务请求fan-out到弹性容器上,并通过容器收集获得结果返回给调用方,具体如上图。

总结

容器的设计模式解决的问题本质上是让业务人员只专注与业务,非业务部分下沉到基础设施层面。这几类模式及类似的Service Mesh解决方案,都是提供了一个无侵入的基础能力,将原来分布式系统全生命周期开发过程中遇到的技术问题下沉到工具类容器中来进行解决。