如何将DDD应用到基础设施设计?

前段时间在面试的时候,面试官问到:你是如何将DDD(领域驱动设计)应用到基础设施的?

我很惊讶,终于有人问我这个问题了。

在过去从事基础设施(DevOps、SRE、运维)的这5年里,我经常说起DDD是一种思维模式,可以应用到任何的领域,包括基础设施的设计。

但是,从来没有人像这位面试官问起我具体的做法。

为什么没有人问?原因大概是这两个概念通常是不会放在一起的。大多数开发不会深入理解基础设施的设计,而大多数从事基础设施设计的人是不会接触到DDD。而且,开发人员对于DDD的理解,也仅局限于用它开发业务系统。

我就是那少部分人,即做基础设施的设计,又觉得自己懂DDD的人。

说回问题本身。

我所理解的DDD

我首先会向提问的人澄清我所理解的DDD。

为什么要这样呢?很久以前有一次面试,因为我说我擅长DevOps,面试官就认为我不懂GitOps。然后在这个点上他就认为我不适合,不再问我DevOps方面的问题。我只能说没有缘份。

我是这样解释DDD的:

就像开发一个象棋游戏,不论你要开发手机端,还是web端,象棋规则本身都是不变的。这个规则本身就可以理解为“领域”。 其它所有的技术(包括架构)都是具体实现,它们应该由“领域”来驱动设计。

当时的解释与以上的解释大差不差。

将DDD应用到基础设施设计的具体做法

那么该如何将DDD应用到基础设施的设计呢?

DDD的思维方式要求我们首先问:我们要设计的软件的领域(核心)问题是什么?

基础设施的领域问题是什么?我的回答是配置

我认为基础设施的搭建、维护,本质就是配置的设计、部署、维护。

寻找领域(本质)问题的能力是DDD的核心能力。

为了让读者更好理解,我们以一个一个基于云上的虚拟机的分布式系统为例。它的基础设施就包括:vpc、LB、MQ、DB等。

要搭建、维护这一套基础设施。

根据“配置管理是基础设施设计的核心问题”,我首先将基础设施的所有的配置放在清单代码(并不一定是一个文件)中,如下:

vpc:
  # ....
LB:
  # ...
DB:
  # ...
MQ:
  # ...
APP1:
  mq_addr: "{{ MQ.addr }}"
  db_host: "{{ DB.addr }}"
APP2:
  mq_addr: "{{ MQ.addr }}"
  db_host: "{{ DB.addr }}"
  app1_addr: "{{ APP1.addr }}"

从清单中,你看不出它使用何种部署方式、部署顺序。你只知道APP1引用了MQ和DB,APP2会调用APP2这样纯粹的领域知识。

现实通常是多个环境,所以,我一开始就会将不同环境的值从清单上抽离到独立的文件夹中。

第二步,我才会考虑如何部署它们。这时,我通过两个工具实现:

  1. Terraform负责云基础设施;
  2. Ansible负责业务基础设施。

Ansible是可以直接读取我们的YAML格式配置文件。而Terraform代码引用YAML代码,就没有那么方便了。

所以,我决定使用Jsonnet这门配置语言来统一所有的配置,这样不同的配置之间就可以相互引用了。

配置之间的相互引用功能是配置管理的核心功能。

假如某一天,我们需要将云虚拟机的基础设施,迁移到K8s呢?

最上层的清单配置是不需要做什么变更的,因为它和你的具体的基础设施实现是无关的,你只需要更改底层的部分配置。

比如,你需要将Ansible部署工具改成Helm,那么,你需要做的就是写一套通用的Helm chart,然后chart values配置引用上层的APP的配置即可。这时,你会发现,配置的标准化,我们在一开始实现了,而不需要后期返工。

最终我们的基础设施的配置的架构,可以简化成下图:

小结

我是如何将DDD应用到基础设施的:

  1. 基于自己对基础设施的理解,将“配置管理”定义为这个领域的核心问题;
  2. 分析配置管理的所带来的具体问题;这一步通常由领域专家来做。本文我是直接略过这一环节;
  3. 根据第二步,决定使用代码去管理配置;
  4. 根据基础设施的上下文(是否使用云,是否云原生)选择工具,读取配置,然后实现部署与维护。

不论你是否赞同使用基础设施即代码,我的基础设施的设计都是由配置管理(领域)这个问题驱动。


Last modified on 2024-01-27