1. 项目概述:为什么用Python画架构图
说实话,我在接触 Diagrams 之前,画架构图一直是个很折腾的事情。用过 Visio、draw.io,也试过在线工具,但每当架构调整,就要手动挪方块、拉箭头,改完一张图往往要花一下午。后来团队里有人推荐了 Python 的 Diagrams 库,用代码描述架构,思路一下子清晰了:架构图本质上是"代码即文档",改图就是改代码,跑一遍命令就重新生成一张干净整洁的图。
Diagrams 这个库的核心价值可以用一句话概括:用 Python 代码描述云系统架构,然后自动渲染成架构图。它底层封装了 Graphviz 的绘图能力,但对使用者非常友好——你不需要学 DOT 语言,只要知道你想要什么节点、什么连线,代码写出来基本就是"所见即所得"。
这个库适合谁?我是这样看的:
- 架构师:快速画设计稿,迭代调整架构方案,画完还能直接放进设计文档。
- 开发工程师:README 里放一张架构图,项目仓库的逼格和可维护性都上来了。
- 运维/DevOps:描述部署拓扑、网络链路,排查问题时有一张准确的图比什么都有用。
- 喜欢"代码驱动一切"的人:图是文本文件,可以走 Git 版本管理、代码评审、自动化生成。
在接下来的内容里,我会从安装配置、基础概念讲起,然后带你走一遍实战案例,最后聊聊我在实际使用中踩过的坑和积累的小技巧。整个流程我已经跑了不知道多少遍,你只需要跟着做,很快就能画出自己的第一张架构图。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 环境准备与核心概念
2.1 安装 Diagrams 及其系统依赖
安装 Diagrams 本身很简单,一句话的事:
bash复制pip install diagrams
但装完不一定能用,因为 Diagrams 依赖 Graphviz 这个系统级工具。Graphviz 是底层用来做布局和渲染的引擎,你必须单独安装它。不同系统的安装方式不一样:
- macOS:
brew install graphviz - Ubuntu/Debian:
sudo apt install graphviz - Windows:去官网下载 Graphviz 的安装包,或者在
choco install graphviz - CentOS/RHEL:
sudo yum install graphviz
我个人最常用的环境是 macOS + Python 3.9,在 macOS 上 brew install graphviz 一条命令就能装完。装完之后,可以用下面的命令验证环境是否正常:
bash复制python -c "from diagrams import Diagram"
如果没有任何报错,说明依赖已经就绪。如果这里报 ModuleNotFoundError: No module named 'diagrams',大概率是 pip 和 python 不在同一个虚拟环境里。建议在项目里先建一个虚拟环境再装依赖,后面会少很多麻烦。
2.2 基本概念:节点、连线与集群
用 Diagrams 画图,你只需要掌握三个核心概念:节点(Node)、连线(Edge)、集群(Cluster)。
节点就是架构图里的一个组件,比如一台 EC2、一个 MySQL 实例、一个 Kafka 集群。Diagrams 按照云厂商和服务类型对节点做了分类,比如 aws、azure、gcp、alibaba、onprem 等,每个分类下又有更细的子模块。以 AWS 为例:
python复制from diagrams.aws.compute import EC2, Lambda
from diagrams.aws.database import RDS
from diagrams.aws.network import Route53, ALB
这行代码从不同的子模块导入了对应节点类。实际上你完全可以按需导入,只导入当前页需要用到的节点类型,避免一长串 import 影响阅读。
连线就是图中的箭头,表示两个节点之间的交互关系。最简单的用法是在节点之间用 >> 符号:
python复制client >> load_balancer >> ec2_instance
这会生成一条从 client 指向 load_balancer、再从 load_balancer 指向 ec2_instance 的链路。
集群则是把一组节点圈在一起的视觉容器,通常用来表示一个子系统、一个网络分区或者一个逻辑上的服务边界。比如:
python复制from diagrams import Cluster
with Cluster("前端层"):
frontend_ec2 = EC2("Web Server")
frontend_lb = ALB("Load Balancer")
2.3 第一个架构图:最小示例
聊完概念,直接上一个最小可运行的示例。假设我们要画一个"用户 -> CDN -> 后端负载均衡 -> 应用服务器 -> 数据库"的经典链路:
python复制from diagrams import Diagram
from diagrams.aws.network import Route53, ALB
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
with Diagram("Web 服务架构", show=False):
dns = Route53("example.com")
lb = ALB("负载均衡")
app = EC2("应用服务器")
db = RDS("MySQL")
dns >> lb >> app >> db
运行这段代码后,会在当前目录下生成一张名为 web_service_architecture.png 的图片(文件名默认取自 Diagram 的标题,把空格替换成下划线)。
这里有两个细节值得注意:
show=False表示生成图片后不自动打开预览窗口。如果是在命令行环境跑,不用加这个参数的话会调用系统默认看图软件,可能有点烦人。我在 CI 里生成文档图时一定用show=False。Route53、ALB这些节点类在渲染时是有默认图标的,这是这个库最讨喜的地方:不是拿方块画图,而是直接贴云厂商官方的图标。
如果你现在跑去跑这段代码,大概率能成功,因为 Graphviz 的大部分功能都被 Diagrams 封装好了。但有些人会在这里踩坑,比如生成出来的图中文乱码、节点重叠、布局不合理,这些在后面的常见问题部分我会展开讲。
3. 核心细节解析:节点体系与自定义能力
3.1 节点分类体系梳理
Diagrams 的节点分类体系是理解整个库的钥匙。它按照"云厂商/供应商 -> 服务大类 -> 具体产品"的层级组织模块,这个设计和真实云产品的组织方式一致,用起来非常直觉。
以 AWS 为例,diagrams.aws 下面有 compute、database、network、storage、analytics、security 这些大类,每个大类再具体到产品级节点:
compute: EC2、Lambda、EKS、ECSdatabase: RDS、DynamoDB、Redshift、ElastiCachenetwork: Route53、ALB、VPC、CloudFrontstorage: S3、EBS、EFS、Glacieranalytics: Kinesis、EMR、Athena、QuickSightsecurity: IAM、Cognito、KMS
不只 AWS,GCP、Azure、阿里云、腾讯云等主流云厂商都有对应的模块。此外还有 onprem 模块用来画本地基础设施,比如:
python复制from diagrams.onprem.workflow import Airflow
from diagrams.onprem.database import PostgreSQL
from diagrams.onprem.queue import Kafka
这个"混合架构"的支持很实用。大多数真实系统并不是纯云,而是云上云下混合的,Diagrams 能在一张图里同时呈现云原生产品和本地自部署组件。
3.2 节点属性定制
节点不是印死不能变的,你可以在创建节点时传入许多参数来定制样式。
名称:节点下方显示的标签,比如 EC2("API Server"),这里 EC2 是节点类型,"API Server" 是图上显示的文本。
文字标签与节点 ID:
python复制ec2 = EC2("API\nServer")
注意这里的 \n 可以换行,如果你的节点名称较长,换行后图会显得整齐很多。
字体颜色与大小:
python复制ec2 = EC2("API Server", fontsize="14", fontcolor="white")
节点本身颜色:颜色修改是通过 Graphviz 的样式属性透传的:
python复制ec2 = EC2("API Server", style="filled", fillcolor="orange")
不过说实话,我很少自定义节点的填充颜色,因为默认配色已经符合云厂商的品牌视觉,乱改反而容易让图看起来像拼贴画。
图例关键字:Diagrams 支持为节点指定别名,这在批量创建节点时非常有用:
python复制instances = [EC2(f"worker-{i}") for i in range(3)]
3.3 自定义节点类型与自定义图标
如果内置节点类型不满足需求,Diagrams 提供了两种扩展路径。
路径一:使用 Custom 节点加载自定义图标
python复制from diagrams import Node
from diagrams.custom import Custom
custom_node = Custom("自研服务", "local_logo.png")
Custom 接收一个本地图片路径(支持 png/jpg/svg),渲染时会用这个图片作为节点图标。这个功能适合画自研组件或非标准技术栈组件,比如某个内部系统、某个开源软件没有内置图标时,找一个 logo 图就能用。
路径二:继承自定义节点类型
我踩过的一个实用场景是:某个内部组件在系统里大量出现,如果用 Custom 每次都要写图片路径,代码会重复。这时可以自定义一个子类:
python复制from diagrams import Node
class MyService(Node):
def __init__(self, name, **kwargs):
super().__init__(name, "my_service.png", **kwargs)
之后就可以 MyService("订单服务") 这样简洁地使用了。
3.4 节点方向与图布局控制
Graphviz 支持有向图和无向图,Diagrams 默认是有向图(因为架构图大多描述依赖关系和调用关系)。
布局方向是控制图整体走向的关键参数。Diagrams 的 Diagram 构造器接受 direction 参数:
python复制with Diagram("架构图", direction="TB"):
可用的方向有:
LR:从左到右(最常用,符合阅读习惯)RL:从右到左TB:从上到下BT:从下到上
我在画"请求链路"型架构图时(用户请求从入口到后端),选 LR 最合适,因为用户的注意力顺着横向走非常自然。画"分层架构"时(接入层 -> 服务层 -> 数据层),选 TB 比较合适。
方向选定后,节点顺序对布局的影响也值得注意。在代码里的书写顺序,基本决定了 Graphviz 排列节点时的相对位置,但 Graphviz 有自动布局算法,它不是严格的按书写顺序从左到右排列。如果你对某条链路的走向有强烈要求,方向参数就必须设置清楚。
4. 实操过程:三种经典架构图的完整实现
4.1 案例一:事件驱动架构
先看一个偏实战的场景:事件驱动架构。这种架构里,用户请求先到 API Gateway,经过处理后将事件发送到 Kafka,再由不同的消费者分组异步消费、处理、写入数据库。这是一个非常典型的互联网业务数据链路。
python复制from diagrams import Cluster, Diagram
from diagrams.aws.network import APIGateway, Route53
from diagrams.aws.compute import Lambda
from diagrams.aws.integration import SQS, SNS
from diagrams.onprem.queue import Kafka
from diagrams.aws.database import DynamoDB, RDS
from diagrams.aws.storage import S3
with Diagram("事件驱动架构", direction="LR", show=False):
dns = Route53("api.example.com")
api = APIGateway("API 网关")
with Cluster("事件总线"):
kafka = Kafka("Kafka")
queue = SQS("消息队列")
with Cluster("消费处理"):
consumer_1 = Lambda("消费者 A")
consumer_2 = Lambda("消费者 B")
with Cluster("数据存储"):
db_primary = RDS("主数据库")
db_analytics = DynamoDB("分析库")
bucket = S3("数据湖")
dns >> api >> kafka
kafka >> [consumer_1, consumer_2]
api >> queue
consumer_1 >> db_primary
consumer_2 >> [db_analytics, bucket]
这个示例里有几个值得留意的点。
dns >> api >> kafka这种链式写法生成一条连续的链路,简洁直观。kafka >> [consumer_1, consumer_2]这种列表连法,一条线变成两条线,一个生产者被两个消费者消费的关系一目了然。consumer_2 >> [db_analytics, bucket]表达的则是消费者二同时写入两个存储。
运行后得到的图,左右走向,左侧是域名入口,中间是事件总线,右侧是消费处理和数据存储,层次非常清晰。
4.2 案例二:微服务与 API 网关
微服务架构图是需求率最高的场景。我一般画这种图时,会按"接入层 -> 服务发现 -> 业务服务 -> 基础设施依赖"的层级来组织。
python复制from diagrams import Cluster, Diagram
from diagrams.aws.compute import ECS, EKS, Lambda
from diagrams.aws.network import ALB, Route53, VPC
from diagrams.aws.database import RDS, ElastiCache
from diagrams.aws.security import Cognito, IAM
with Diagram("微服务架构", direction="TB", show=False):
vpc = VPC("VPC")
with Cluster("接入层"):
dns = Route53("域名解析")
lb = ALB("负载均衡")
auth = Cognito("用户认证")
with Cluster("业务服务"):
svc_order = ECS("订单服务")
svc_user = ECS("用户服务")
svc_pay = Lambda("支付服务")
with Cluster("数据层"):
db_order = RDS("订单库")
db_user = RDS("用户库")
db_cache = ElastiCache("Redis 缓存")
dns >> lb >> auth
auth >> [svc_order, svc_user, svc_pay]
svc_order >> [db_order, db_cache]
svc_user >> db_user
svc_pay >> db_order
这里我用 VPC 作为整个架构的容器,但其实这只是个概念示意,把 VPC 放在图里会导致整个布局偏向"圆角矩形包住一切"的效果,视觉上很像网络拓扑图。如果你画的图在文档里是用来表达逻辑调用关系的,VPC 这个节点不一定要出现在图里。
微服务图最怕画成"一团乱麻"。我的经验是:先分组,再连线。分组拆好之后,连线数量自然就下降了。如果某个服务要连很多个数据库,可以考虑用 Edge 的 label 参数加上文字说明,让图更易读:
python复制from diagrams import Edge
svc_order >> Edge(label="读写", color="green") >> db_order
4.3 案例三:多云混合架构
再来一个更复杂的场景:多云。许多公司会在 AWS 上跑核心业务,在 GCP 上跑大数据分析,在自建机房跑内部系统。画这种图时,"集群"这个工具会显得尤为重要。
python复制from diagrams import Cluster, Diagram
from diagrams.aws.network import Route53, CloudFront, ALB
from diagrams.aws.compute import EC2
from diagrams.aws.database import RDS
from diagrams.gcp.analytics import BigQuery
from diagrams.gcp.storage import GCS
from diagrams.onprem.database import PostgreSQL
from diagrams.onprem.workflow import Airflow
with Diagram("多云混合架构", direction="LR", show=False):
dns = Route53("入口 DNS")
with Cluster("AWS 生产区"):
cdn = CloudFront("CDN")
lb = ALB("负载均衡")
app = EC2("应用")
db = RDS("业务库")
with Cluster("GCP 分析区"):
bq = BigQuery("分析仓库")
gcs = GCS("数据湖")
airflow = Airflow("调度器")
with Cluster("本地机房"):
internal_db = PostgreSQL("内部系统")
dns >> cdn >> lb >> app
app >> db
app >> airflow
airflow >> [bq, gcs]
app >> internal_db
这种图画出来,三个云区域被三个圆角矩形框住,区域边界一目了然,比用文字在标题里强调"这是 AWS 的"直观得多。跨区域的连线虽然可能会多一些交叉线,但 Graphviz 的布局引擎通常能处理得不错。
4.4 归档图:保存格式与文件名控制
很多人在用 Diagrams 一段时间后,会碰到"我想导出 SVG 格式用作网页插图"或者"需要不同文件名"的需求。Diagram 构造器支持 outformat 参数:
python复制with Diagram("架构图", outformat="jpg", show=False):
# 节点连接
pass
outformat 支持 png、jpg、svg、pdf 等。在 CI 流程里,我经常同时导出 png(给文档用)和 svg(给网页用)。文件名的控制也很有意思,默认是根据标题自动转换,但如果你想要自定义输出路径,可以用 filename 参数:
python复制with Diagram("架构图", filename="./assets/architecture_v2", show=False):
这个参数在生成多个版本对比时特别有用,比如 architecture_v1.png、architecture_v2.png,不用每次手动改文件名。
5. 常见问题与排查技巧实录
5.1 Graphviz 相关报错排查
报错一:graphviz.backend.execute.ExecutableNotFound
这个报错几乎都是因为 Graphviz 没有装,或者装了但系统 PATH 找不到。
第一种情况:确认 Graphviz 是否真正安装成功。
bash复制dot -V
如果提示 command not found: dot,说明 Graphviz 没装或 PATH 没配好。macOS 用户可以用 brew list graphviz 检查;Windows 用户请在"环境变量 -> Path"里加上 Graphviz 的 bin 目录(通常是 C:\Program Files\Graphviz\bin)。
第二种情况:Python 环境里装的是另一个同名库,导致实际使用的 graphviz 包版本不对。Diagrams 对 Graphviz 的调用是通过 graphviz 这个 Python 包来做的,如果版本过低,也可能报错。
bash复制pip install -U graphviz
报错二:Format: png not recognized
Windows 环境的常见问题,因为 ImageMagick 没有正确关联。但最简单的解决办法是在 Diagram 里显式指定 engine:
python复制with Diagram("架构图", engine="dot", show=False):
默认引擎就是 dot,但显式指定有时候能避免某些环境下的格式识别问题。
5.2 中文乱码问题
这是最让人头疼的问题之一。节点的名称里有中文时,渲染出来的图里中文可能变成方块。原因很简单:Graphviz 渲染文字时使用的字体不支持中文。
解决办法有两个方向:
方向一:指定一个支持中文的字体
Diagrams 允许透传 Graphviz 的字体配置到节点或整个图:
python复制from diagrams import Diagram
from diagrams.aws.compute import EC2
with Diagram("中文架构图", show=False):
ec2 = EC2("应用服务器", fontname="Microsoft YaHei")
但这里 fontname 只对当前节点生效,如果图里中文字符串太多,一个个指定太痛苦。可以在全局设置:
python复制import diagrams
diagrams.config.FONTNAME = "Microsoft YaHei"
在 Windows 下我用 Microsoft YaHei,在 macOS 我用 PingFang SC,在 Linux 上可以用 Noto Sans CJK SC。前提是系统已经安装了对应字体。
方向二:直接用英文标签
这个方法比较无脑但很实用。我在很多正式技术文档里反而倾向于用英文标签,因为开发者社区对英文术语的接受度更高,也完全不用考虑编码问题。
5.3 图片清晰度与布局控制
Diagrams 生成的默认 png 分辨率有时候不够用,尤其是大图。想提高清晰度,可以调整 Graphviz 的 DPI 参数:
python复制with Diagram("架构图", graph_attr={"dpi": "150"}, show=False):
graph_attr 是给 Graphviz 底层引擎透传属性用的,你可以在这里设置很多细节参数,比如 ranksep(同级间距)、nodesep(节点间距)、bgcolor(背景色):
python复制with Diagram(
"架构图",
direction="LR",
graph_attr={
"dpi": "150",
"ranksep": "0.8",
"nodesep": "0.5",
"bgcolor": "white"
},
show=False,
):
如果图的节点非常多,Graphviz 自动布局有时会产生大量交叉线。我的经验是:
- 把强关联的节点放到同一个
Cluster里,Graphviz 会把集群当作一个整体来布局,交叉线会明显减少。 - 方向调整为
TB可能在节点多时比LR更整齐,可以根据实际效果快速切换试试。 - 适当引入不可见的边(
Edge(style="invis"))来微调节点对齐。比如你希望两个节点水平对齐,可以在它们之间加一条透明线,Graphviz 会尽量保持这两个节点在同一水平线。
5.4 性能问题与大型架构图
有朋友跑了一张包含上百个节点的架构图,发现渲染时间特别长。这个场景下我做过的优化主要有三个:
减少集群嵌套层级:Graphviz 对嵌套集群的处理开销较大,三层以上的 Cluster 嵌套要尽量避免。
简化节点标签:节点文字内容太多,会加大排版计算的复杂度,可以在大图里用简洁代号,然后在图例里解释。
分而治之:架构非常庞大时,不要试图在一张图里画完所有细节。我一般画两张图,一张是高层架构图(只画服务大模块),另一张是核心子系统详图(画到具体组件、甚至具体实例)。这个在工程文档里其实更利于阅读。
5.5 版本管理与自动化集成
最后聊一个非常实用的话题:如何把架构图纳入项目的自动化流程。
因为图是代码生成的,所有 .py 脚本可以直接进 Git。推荐项目结构是这样的:
code复制/docs/
├── diagrams/
│ ├── architecture.py
│ ├── event_driven.py
│ └── outputs/
│ ├── architecture.png
│ └── event_driven.png
在 CI 里加一个步骤:每当 docs/diagrams/ 下的代码有变更时,就跑一次 Python 脚本重新生成图片。这样图永远和代码同步。
yaml复制# 伪 CI 配置
job:
steps:
- run: pip install diagrams
- run: python docs/diagrams/architecture.py
- run: python docs/diagrams/event_driven.py
这个流程跑通之后,架构图就进入了"代码评审"的流程里,审查者可以直接在 MR/PR 里看到架构改动。团队协作时,这个习惯会极大提升架构文档的保鲜度。
6. 实战心得与进一步扩展
在实际项目中用 Diagrams 画了大半年,一个很深的体会是:图的质量不取决于工具,而取决于画图前你对系统的理解程度。Diagrams 把你从"对齐方块、调箭头"的体力劳动中解放出来,但前提是你要先想清楚:这张图要回答什么问题?
- 如果是给新人讲系统全貌,那就在一张图里画清楚模块边界和关键链路。
- 如果是定位性能问题,那就画清楚每个环节的依赖和瓶颈节点。
- 如果是给客户看方案,那就突出架构的高可用、扩展性,别把内部细节全都堆上去。
另外,Diagrams 还支持把 edge 加上颜色和标签,用来区分不同协议或不同流量:
python复制from diagrams import Diagram, Edge
with Diagram("链路标识", show=False):
client = EC2("客户端")
server = EC2("服务端")
client >> Edge(label="HTTP", color="blue") >> server
client >> Edge(label="gRPC", color="green") >> server
这种"一图双链路"的表达方式在排查线上问题时非常管用,能在图上直接标出哪条链路是你关心的。
如果你想更进阶,可以结合 jinja2 模板或者调用云平台的 API 读取真实的资源列表,自动生成当前环境的架构图。我之前做过一个小工具,从 AWS 的标签系统里读取所有 EC2 和 RDS 实例的 tag,然后自动生成一张当前生产环境的资源关系图。这种玩法放在 CMDB 或运维平台上,一次投入,长期受益。
总结起来就一句话:用代码画图的本质,是把画图这件事从"手工作业"升级成"工程产物"。它可能不会让你的架构图在一夜之间变得更好看,但它让架构图的维护成本降到了足够低,低到你愿意每次改动都顺手更新下图,低到团队愿意把图纳入版本管理。这件事本身就值回票价了。
