绘制系统架构设计图是技术文档中的重要一环。系统越复杂,团队内部保持清晰的沟通就越重要。
不过,用画布类工具从零开始画图,效率未必高。
好在还有另一种画图方式:图即代码(diagram-as-code)。这种方式用预定义的语法描述图中的各个组件,而不是动手去画。
目录
图即代码的优势
改动可以通过版本控制来追踪。
节省时间:无论是从零开始画还是用工具绘制,手动调整格式都很耗时。
大多数图即代码工具都支持常见的技术图标,比如数据库、存储桶、负载均衡器等。
图还能用代码在 CI/CD 流水线或文档构建过程中自动生成。
前置条件与安装
在本教程中,你将学会用 Python 的 Diagrams 库来画图。基本的前置条件如下:
Python 3.7+
pip,用于安装 Python 包
操作系统中已安装 Graphviz,用于渲染输出的图片
Python 包:
pip install diagrams一个终端,用来运行如下文件:
python diagram.py
Diagrams 是什么?
Diagrams 是一个 Python 库,可以用 Python 代码绘制云系统架构图,支持 Azure、GCP、AWS 等多种云服务商。
读完本教程,你就能看懂下面这张架构图是怎么画出来的:
你的第一张架构图
首先,请确保已按前置要求完成环境配置。然后新建一个扩展名为 .py 的 Python 文件,把这段代码加进去:
from diagrams import Diagram
from diagrams.aws.compute import EC2
with Diagram("Practice Architecture"):
EC2("api-server")
我们来逐行解读这段程序。
首先是导入 Diagram:
from diagrams import Diagram
可以把 Diagram 想象成一张空白画布,所有图形都画在里面。Diagram 代表的是全局图表上下文。
接着我们导入节点类型。节点代表架构中的一个组件。例如,ECS、lambda、Service、firewall 都是资源类型。
from diagrams.aws.compute import EC2
节点对象由三部分组成:提供者、资源类型和名称。在上面的例子中,EC2 是一个资源类型为 compute 的节点,由 aws 提供者提供。
这条语句从 AWS 的 compute 组导入了 EC2 节点,稍后我们会用这个类来创建 EC2 节点。
diagrams.aws.compute 是导入路径,它指明了 EC2 图标所在的位置。
diagrams
└── aws
└── compute
└── EC2
各家服务商还有更多官方节点类型,你可以到这里浏览。
假设你想在图表里使用 AWS 的 Analytics 组件。首先,从上文列出的节点类型中找到 Analytics,对应的导入语句如下:from diagrams.aws.analytics import Analytics。
接着,用 with Diagram 创建图表上下文:
with Diagram("Practice Architecture"):
回到你的例子,这会创建一个名为 Practice Architecture 的图表。凡是缩进在 with Diagram 下面的内容,都属于这个图表。
接下来创建一个节点:
EC2("api-server")
这样就会创建一个 EC2 节点,节点下方显示 api-server 标签。
最后,运行代码。如果你把 Python 代码文件保存为 test.py,就用 python test.py 来运行。Diagrams 会在当前文件夹里生成一张图片:
简单来说,整个流程是这样的:
注意,你是在描述基础设施,而不是手动绘图。你无需考虑怎么画图标、怎么摆放图标,只需写下 EC2("api-server"),剩下的渲染工作交给 Diagrams 处理即可。
我们稍微扩展一下上面的例子,加入两个 EC2 实例:
from diagrams import Diagram
from diagrams.aws.compute import EC2
with Diagram("Practice Architecture"):
EC2("api-server")
EC2("worker")
注意,你可以把节点实例赋值给变量,这样引用起来就很方便。
下面的示例演示了如何给变量赋值:
from diagrams import Diagram
from diagrams.aws.compute import EC2
with Diagram("Practice Architecture"):
api_server = EC2("api-server")
worker = EC2("worker")
节点连接与数据流向
前面你已经学会了如何创建节点,接下来看看怎么把它们连接起来。
连接方向用下面这些符号表示:
>>表示从左到右的流向<<表示相反方向(从右到左)-表示无向连接
下面把这几个符号放在一起,看个例子:
from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB
with Diagram("The three directions"):
load_balancer = ELB("load-balancer")
web_server = EC2("web-server")
database = RDS("database")
backup_server = EC2("backup-server")
load_balancer >> web_server
web_server << database
database - backup_server
注意节点之间的连接:
# Connects load balancer to web server with a left to right arrow
load_balancer >> web_server
# Connects web server and database using a right to left arrow
web_server << database
# connects database and web server using a straight line
database - backup_server
对数据流进行分组
还可以用 Python 列表将一个节点同时连接到多个节点,省去逐个连接的麻烦。
假设你想实现这样的架构:
┌──► web-1 ───┐
load-balancer ──────┼──► web-2 ───┼──► database
└──► web-3 ───┘
首先,创建一个负载均衡器:
load_balancer = ELB("entry-point")
接下来创建几个服务器。与其像下面这样定义三个单独的变量:
server1 = EC2("web-1")
server2 = EC2("web-2")
server3 = EC2("web-3")
可以把它们放进 Python 列表里:
web_servers = [
EC2("web-1"),
EC2("web-2"),
EC2("web-3")
]
然后将 LB 节点连接到 load_balancer >> web_servers 这个列表,如下所示:
load_balancer >> web_servers
这样一来,你就不用手动编写:
load_balancer >> web_servers[0]
load_balancer >> web_servers[1]
load_balancer >> web_servers[2]
现在把整个列表接入数据库:
web_servers >> database
这种方式能有效减少代码冗余,特别适合处理多个 pod、worker 等重复出现的组件。
完整代码如下:
from diagrams import Diagram
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.aws.network import ELB
with Diagram("Scaled Web App"):
load_balancer = ELB("entry-point")
web_servers = [
EC2("web-1"),
EC2("web-2"),
EC2("web-3")
]
database = RDS("orders-db")
load_balancer >> web_servers >> database
群集(Clusters)
使用群集,可以把相关节点放进一个带标签的方框中。群集内的节点依然可以连接外部的节点。
分组能直观展示哪些内容彼此关联,适合用来表达以下概念:
应用层
数据库层
可用区
区域
环境
微服务分组
Worker 分组
创建群集的语法如下:
with Cluster("Cluster name"):
缩进在它下面的内容都会成为这个集群的一部分。
下面通过一个示例来演示集群的用法:
from diagrams import Diagram, Cluster
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Shop Platform"):
with Cluster("Application Tier"):
apps = [
EC2("app-1"),
EC2("app-2")
]
with Cluster("Database Tier"):
primary_db = RDS("primary-db")
replica_db = RDS("read-replica")
apps >> primary_db
primary_db - replica_db
用这种语法还可以嵌套集群:
with Cluster("Production"):
with Cluster("Backend"):
with Cluster("API"):
...
接下来看一个更贴近实际、包含嵌套集群的例子:
from diagrams import Diagram, Cluster
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Production Platform"):
with Cluster("Production Region"):
with Cluster("Application Tier"):
with Cluster("API Servers"):
api1 = EC2("api-1")
api2 = EC2("api-2")
database = RDS("main-db")
api1 >> database
api2 >> database
这个示例展示了一个 Production Platform,其中包含 Production Region,后者又包含 Application Tier。Application Tier 则进一步将两台 API 服务器归为一组。生产区域内另有一套独立的 RDS 数据库,两台 API 服务器都连接到该数据库。
把各个集群逐级缩进排列,即可实现集群的嵌套。具体写法参见下面的代码片段:
with Cluster("Production Region"):
with Cluster("Application Tier"):
with Cluster("API Servers"):
api1 = EC2("api-1")
api2 = EC2("api-2")
边
边是连接节点的另一种方式。与单纯的 >> 或 << 不同,使用边还可以添加标签、颜色、样式等属性。
之前你用过:
from diagrams import Diagram
要使用边,只需添加:
from diagrams import Diagram, Edge
现在,用一条边把 app 连接到 database:
# Labeling an edge
app >> Edge(label="SQL queries") >> database
这行代码用一条标签为 "SQL queries" 的边把 app 和 database 连接起来。
你还可以自定义边的颜色:
app >> Edge(label="SQL", color="red") >> database
你还可以修改线条样式:
app >> Edge(style="dashed") >> database
下面是其他一些可用的连线样式:
Edge(style="dotted")
Edge(style="bold")
下面的示例展示了多种边样式的组合用法:
from diagrams import Diagram, Edge
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Payment Service"):
api = EC2("payment-api")
database = RDS("payments-db")
api >> Edge(
label="payment records",
color="darkgreen",
style="dashed"
) >> database
注意,还可以将 << 和 - 与边搭配使用。
结语
在本教程中,你学会了如何用 diagram-as-code(图表即代码)的方式,绘制有意义、风格统一、易于在团队间推广扩展的图表。这样既能保持高效,又不必牺牲质量,也不耽误其他开发和维护工作。
本教程主要使用的是 AWS 组件。你可以在这份指南中了解其他可用的提供商,并按自己的需求绘制图表。
感谢你读到最后。如果这篇文章让你有所收获,欢迎分享给更多人。
保持联系,继续你的学习之旅!
欢迎通过以下方式与我联系:
LinkedIn:我在这里分享 Linux、网络安全和 DevOps 相关内容。如果你觉得这篇文章有帮助,欢迎在 LinkedIn 上为我留下推荐语。
X:我会在这里分享发布前的最新动态和一些幕后花絮。
祝编程愉快!