C4容器图用来回答:一个软件系统内部有哪些应用和数据存储,它们分别负责什么,又怎样通信。画图时先圈定一个系统,再识别运行边界,最后给关系标注用途和协议。这里的“容器”不等于Docker容器,也不是把功能模块换一种颜色排列。
如果团队已经确认系统面向谁、依赖哪些外部系统,可以在Boardmix在线架构图画布中展开内部结构。下面以团队资料中心为例,完成一份可以交给开发、测试和运维共同检查的容器图。

先分清容器图、上下文图和部署图
C4官方对容器图的说明把范围限定在单一软件系统内部,关注应用、数据存储、职责与通信。它比系统上下文图更细,但不需要一路展开到类和函数。
| 当前要回答的问题 | 适合的视图 | 团队资料中心里会出现什么 |
|---|---|---|
| 谁使用系统,它依赖谁? | 系统上下文图 | 员工、资料管理员、资料中心、企业身份系统 |
| 系统内部由哪些运行部分组成? | 容器图 | Web应用、资料API、索引Worker、数据库等 |
| 一个应用内部如何组织代码职责? | 组件图 | 资料API内部的权限校验、资料管理、检索接口等组件 |
| 这些部分在某个环境里运行在哪里? | 部署图 | 生产环境的服务器、运行实例、网络区域和部署节点 |
同一个资料API在生产环境运行三个副本,通常仍是容器图中的一个应用;三个运行实例到部署图里说明。反过来,两个应用即使部署在同一台机器上,也不因此合成一个容器。
如果“资料中心到底负责哪些事”还没有共识,先完成系统上下文图的边界梳理。容器图应展开已确认的系统边界,不能在画内部结构时悄悄增加另一个完整业务系统。
从资料上传与检索任务中识别六个容器
本例的资料中心允许员工查找和下载团队文件,由资料管理员上传文件、维护标题与所属团队。企业身份系统负责登录认证,资料中心负责自身的资料访问规则。第一版不包含在线编辑文档、外部客户分享和多人协同写作。
准备三类材料就能开始:已确认的系统范围、主要用户任务,以及当前应用和数据存储清单。技术未确定时可以先画候选方案并标明待定;不要为了填满图框,把自己喜欢的技术栈写成已经采用的事实。
为便于看清边界,下面给出一套具体设计:前端采用Vue,资料API采用Java,独立Worker采用Python;资料元数据保存在PostgreSQL,原文件放在兼容S3接口的对象存储,检索文档保存在OpenSearch。这些是本例的设计选择,不是制作C4图的必选技术。
| 容器与类型 | 负责什么 | 不要放进同一个框的内容 |
|---|---|---|
| 资料Web应用 客户端应用 · Vue | 呈现上传、搜索和下载入口,向资料API发出请求 | 浏览器窗口不是另一个业务应用;服务端资料权限仍由API判断 |
| 资料API 服务端应用 · Java | 校验资料访问规则,维护资料记录,协调文件存取和查询 | “上传模块”“权限模块”是其内部职责,不在这一层另画成容器 |
| 索引Worker 后台应用 · Python | 读取待索引资料,提取可检索内容,写入索引并更新处理状态 | 它独立运行,不因与API同属资料团队就合并成一个框 |
| 资料元数据库 数据存储 · PostgreSQL | 保存资料编号、标题、团队归属、文件位置和索引状态 | 不存放本例中的文件正文;不要用“数据库”统称三种存储 |
| 文件对象存储 数据存储 · S3兼容接口 | 保存原文件,由资料编号关联对应对象 | 存储服务托管在哪里,交给部署图说明 |
| 全文检索索引 数据存储 · OpenSearch | 保存用于搜索的索引文档,向API提供匹配结果 | 搜索索引不替代资料归属和权限记录 |
识别容器的关键是运行或存储边界。C4的容器定义包含客户端应用、服务端应用和数据存储;代码包、DLL或普通功能模块通常不因此成为容器。托管在外部云服务中的专用数据库或存储空间,也可以作为系统内部的数据存储建模:逻辑责任边界与物理机房位置不是一回事。
连线要说明“为什么通信”,而不只是“调用”
先把六个内部容器放进“团队资料中心”边界框。员工和资料管理员放在边界之外,分别连接Web应用;企业身份系统也放在外部。人员关系写“查找与下载资料”“上传并维护资料”,技术关系再标注相应协议。
本例将异步处理简化为Worker定期读取待索引记录,不额外引入消息队列。下面八条关系足以说明内部通信及登录依赖;箭头表示发起依赖或请求的方向,不表示业务动作一定按表格顺序发生。
| 起点 → 终点 | 连线上写什么 | 评审时确认什么 |
|---|---|---|
| Web应用 → 企业身份系统 | 请求登录认证 · OIDC / HTTPS | 实际身份协议是否确定;不要自行补出不存在的登录能力 |
| Web应用 → 资料API | 提交资料、搜索与下载请求 · JSON / HTTPS | API是否按用户身份与资料归属检查访问 |
| 资料API → 元数据库 | 读写资料信息与归属 · SQL / TCP | 哪些业务事实以这里的记录为准 |
| 资料API → 对象存储 | 写入和读取原文件 · HTTPS | 本方案是否由API传输文件;若采用直传,应重新画关系 |
| 索引Worker → 元数据库 | 查询待索引记录、更新状态 · SQL / TCP | 处理失败怎样记录,是否允许再次处理 |
| 索引Worker → 对象存储 | 读取待处理文件 · HTTPS | 文件读取范围和失败结果由谁确认 |
| 索引Worker → 检索索引 | 写入检索文档 · HTTPS | 同一资料更新后如何替换旧索引 |
| 资料API → 检索索引 | 查询匹配资料 · HTTPS | 返回结果之后,资料API仍需落实访问规则 |
“API→数据库:调用”说得太少,“API→数据库:创建资料后执行SQL第1步”又细到了执行过程。容器图保留职责和通信关系即可。一次上传如何协调文件写入与元数据写入、失败怎样补偿,需要在详细设计或时序图中继续展开。
C4的图形标注建议强调清楚的元素类型、职责和有方向的关系。颜色可以辅助区分,但不能代替“应用”“数据存储”“外部系统”等文字类型。

在Boardmix中把清单排成一张可读的图
先写图名“团队资料中心——C4容器图”,在图名旁注明第一版范围。画一个大的系统边界,里面分三列:左侧是Web应用,中间是资料API与索引Worker,右侧是三种数据存储。人员放到最左侧;企业身份系统放在边界上方,避免与内部存储混在一起。
每个容器按“名称—类型与技术—一句职责”排三层文字。先检查文字能否读清,再连接上表中的八条关系。API和Worker都需要访问元数据库及对象存储,连线较密时应增加容器间距、调整出线方向,不要用一条没有说明的公共线代替多个不同关系。
在画布右下角留一块“待确认”区域,只放尚未决定的事项,例如文件大小限制、索引失败的处理方式。不要把这些问题塞进容器名称,也不要用问号箭头表示所有未知事项。已经确认的关系与待定问题分开,评审者才能知道哪些是当前方案,哪些需要继续讨论。
与团队一起检查时,可以直接在相关容器或连线附近记录意见。若有人提出“让前端直接上传对象存储”,先讨论授权、上传确认和异常处理,再决定是否修改关系;不要只移动一根箭头,就把设计变化当成已经解决。
用上传、检索和索引失败走查这张图
上传成功后,为什么可能暂时搜索不到?
沿资料管理员→Web应用→资料API查看上传入口。API在本例中保存原文件与元数据,Worker随后建立索引。上传完成与索引完成不是同一时刻,因此不能画一条“上传成功→立即可搜索”的必然关系。产品与研发需要约定待索引状态如何呈现,以及用户能否从资料列表访问已上传文件。
搜索结果出现一份资料,是否就允许下载?
检索索引用于寻找匹配资料,不能仅凭“搜索到了”就授予访问权。API应结合当前身份和资料归属落实访问规则。走查时检查哪些结果可以显示、哪些文件允许下载;若权限检查只画在前端按钮上,就暴露了需要澄清的责任缺口。
Worker失败时,谁知道哪些资料还没处理?
图中的Worker与元数据库有状态读写关系,这是追查处理进度的入口。继续追问:失败状态记录在哪里、哪些失败可以重试、由谁跟进无法处理的文件。容器图可以表达这些责任依赖,但不能证明重试、告警和故障恢复已经实现。
每个问题只追到本层能说明的位置。若要解释一次失败请求的消息顺序,另开时序图;若要讨论Worker有几个副本、运行在哪个网络区域,另开部署图。这样总图不会在一次次补充后变成看不清的“全部架构”。
交付前改掉三种常见画法
- 把功能菜单画成容器。“上传资料、搜索资料、下载资料”描述用户任务,不代表三个独立运行应用。先查实际运行边界,再放入应用职责或下层组件视图。
- 把数据库、数据库服务器和云供应商画成同一层。本图表达资料存储的职责;具体服务器、集群与托管环境放到部署视图,避免读者把一个逻辑存储误读为一台机器。
- 把技术关系当流程顺序。API依赖对象存储,不代表任何API请求都必须访问文件。为关系写用途,具体请求路径再用走查或时序图解释。
完成后,让没有参与画图的同事找出:系统内的三个应用、三种存储、外部身份系统,以及文件从上传到可检索的责任链。如果他必须猜每个方框和箭头的含义,先补名称、职责与图例。等这张图能独立读懂,再将需要深入的应用展开成组件图。
你可以打开Boardmix梳理当前系统的容器边界,先放入实际应用和数据存储清单,再用一条真实用户任务检查关系。不要为追求图的复杂度增加系统里并不存在的组件。

