de_DEen_USes_ESfa_IRfr_FRhi_INid_IDjapl_PLpt_PTru_RUvizh_CNzh_TW

掌握C4容器图:深入技术选择、职责划分与沟通(附PlantUML示例)

什么是C4容器图?

容器图是第二层西蒙·布朗C4模型中的第二层。它深入到单个软件系统(在第一层——系统上下文层中定义)以展示:

The Ultimate Guide to C4 Model Visualization with Visual Paradigm's AI  Tools - ArchiMetric

  • 系统的高层结构在系统边界内的架构概貌。

  • 主要的可部署/可运行的单元称为容器.

  • 每个容器的技术选择每个容器的技术选择。

  • 容器之间以及与外部参与者/系统之间的交互方式的交互方式。

重要说明:C4中的“容器”并非一定是Docker容器。它是指任何可独立部署或运行的单元,能够执行代码或存储数据。示例:

  • Web应用 / 单页应用(SPA)

  • 移动应用

  • 服务端API / 微服务

  • 数据库(模式)

  • 文件存储(S3存储桶、文件系统文件夹)

  • 消息代理 / 队列(当显式建模时)

  • 桌面应用 / 命令行应用(CLI)

  • 批处理进程 / 定时任务

该图保持高层—— 不包含内部类或代码细节(那是第3级组件或第4级代码)。

何时创建容器图

当满足以下条件时,创建(并维护)容器图:

  • 您已完成(或至少草绘了)系统上下文图,并需要回答:“我们的系统内部的主要构建模块是什么?”

  • 新开发人员、架构师或运维人员入职时——他们需要快速了解技术栈和高层职责。

  • 做出重大的技术或架构决策(单体架构 → 微服务,增加移动应用,选择数据库,引入消息队列,云迁移)。

  • 用于审计、合规性、安全审查或事件响应的文档记录(有助于展示攻击面和数据流)。

  • 您希望实现“架构即代码”,使其存在于代码仓库中并随系统演进。

  • 大多数团队止步于此—— 西蒙·布朗本人指出系统上下文 + 容器图对大多数软件团队来说已经足够。只有当容器内部的复杂性确实需要时,才深入到组件/代码级别。

如果满足以下情况,可跳过或推迟:

  • 系统极其简单(一个进程 + 数据库)。

  • 您正处于非常早期的构思阶段,仅需宏观上下文。

为何使用容器图?(主要优势)

  • 为不同受众提供清晰性
    开发人员看到技术栈和集成点。
    运维/基础设施团队看到可部署单元和通信路径。
    架构师看到责任边界和技术债务风险。
    管理者看到足够中立但又具体的技术视图。

  • 避免“一张大图”的问题
    防止将所有内容(用户 + 基础设施 + 类 + 云图标)塞进一张过载的图片中。

  • 突出关键决策
    清晰地展示诸如SPA + API + 关系型数据库 vs. 服务端渲染 + NoSQL,或同步 vs. 事件驱动等选择。

  • 沟通与协作
    在设计会议、事件事后分析、威胁建模和路线图制定期间,充当共享地图。

  • 动态文档
    当使用 PlantUML / Structurizr DSL 或类似语言编写时 → 在 Git 中版本化,在 CI 上自动重新生成,始终保持最新。

如何创建出色的容器图(分步指南 + 最佳实践)

  1. 从第1层开始
    从上下文图中复制人员和外部软件系统——它们将成为与你的容器交互的参与者。

  2. 绘制系统边界
    使用 System_Boundary 在 PlantUML 中使用,以清晰界定“我们系统内部”的范围。

  3. 识别容器
    提问:哪些是可独立运行/部署、能提供系统功能的组件?
    常见模式:

    • Web SPA ↔ API 后端 ↔ 数据库

    • 移动应用 ↔ 前端后端(BFF)↔ 共享服务

    • 带有消息代理的微服务

    • 遗留单体架构 + 新的 API 层

  4. 添加技术与简要描述
    每个容器应显示:名称、技术、简要用途。
    保持描述少于15个词。

  5. 定义交互(关系)
    显示方向 + 协议 + 目的(例如:“JSON/HTTPS”、“读取并写入”、“发布到”、“消费自”)。
    在关系上使用动词。

  6. 最佳实践

    • 保持可读性 — 目标控制在10到12个容器以内。如果更多 → 创建聚焦视图(例如:“API 子系统容器”)。

    • 保持一致 — 相同的布局方向(自上而下/自左而右),相同的细节程度。

    • 使用图标/精灵图 — 增加视觉吸引力(PlantUML 支持 devicons、font-awesome 等)。

    • 图例与说明 — 在 PlantUML 中启用自动图例。

    • 避免杂乱 — 如果队列或主题不增加价值,就省略它们;在箭头上标注协议 instead。

    • 版本化并以代码形式存储 — 将 .puml 文件提交到代码仓库。

    • 受众定制 — 为开发人员提供详细技术版本,为利益相关者提供简化版本。

PlantUML 示例 – 经典互联网银行系统(Big Bank plc 风格)

以下是一个使用官方 C4-PlantUML 库的清晰、生产级示例。

@startuml
!include https://raw.githubusercontent.com/plantuml-stdlib/C4-PlantUML/master/C4_Container.puml

' 可选:添加漂亮的图标(来自 tupadr3 精灵)
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/angular.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/java.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/postgresql.puml
!include https://raw.githubusercontent.com/tupadr3/plantuml-icon-font-sprites/master/devicons/android.puml

title 容器图:互联网银行系统

Person(customer, "个人银行客户", "Big Bank plc 的客户")

System_Boundary(c1, "互联网银行系统") {
    Container(spa, "单页应用", "JavaScript & Angular", "通过客户的网络浏览器提供所有互联网银行功能", $sprite="angular")
    Container(mobile, "移动应用", "Android/iOS (React Native)", "有限的互联网银行功能", $sprite="android")
    Container(api, "API 应用", "Java & Spring Boot", "通过 API 提供互联网银行功能", $sprite="java")
    ContainerDb_Ext(db, "银行数据库", "PostgreSQL", "存储用户偏好、缓存数据、会话(核心账户/交易仍保留在大型机中)", $sprite="postgresql")
}

System_Ext(core, "核心银行系统", "大型机系统 – 已存在")
System_Ext(email, "邮件系统", "发送邮件(例如 AWS SES)")

Rel(customer, spa, "使用", "HTTPS")
Rel(customer, mobile, "使用", "HTTPS")

Rel(spa, api, "调用", "JSON/HTTPS")
Rel(mobile, api, "调用", "JSON/HTTPS")

Rel(api, db, "读取和写入", "JDBC/SQL")
Rel(api, core, "使用", "JSON/HTTPS")
Rel(api, email, "使用发送邮件", "HTTPS")

LAYOUT_WITH_LEGEND()
LAYOUT_TOP_DOWN()

@enduml

这将生成一个清晰的图表,包含:

  • 系统边界

  • 技术标签

  • 精灵/图标

  • 清晰的关系

  • 图例

您可以直接将其粘贴到 PlantUML 在线服务器或任何兼容的 IDE/编辑器中。

使用此结构作为模板——将元素替换为您自己系统的名称、技术与流程。如需更高级的样式(主题、自定义颜色),请查看 C4-PlantUML GitHub 示例。

愉快地绘制图表吧——请记住:目标是 有效沟通,而不是 UML 的完美!

C4 容器图资源