跳转至

本站背后的平台

本平台的架构图位于站点结构地图和仓库 README 图表 中 — 本页讲述故事,而非堆砌图表。

这个作品集就是产品 — 而这个仓库是构建、检查、部署和运维它的工程平台。你正在 阅读的站点运行在它所记录的同一个仓库上:一个 MkDocs + Material 产品,周围环绕 着一套达到生产标准的交付体系,并以开源方式公开开发,作为对"如何在一个小型、 真实、公开的系统上做平台工程"的刻意示范。

为什么给作品集造一个平台?

作品集站点很小;但围绕它的流程不必小。这个项目刻意把生产软件应有的实践用在一个 公开仓库、作品集规模之上 — 在这里每一项权衡都清晰可见:

  • 一切按真实软件发布 — PR、必需检查、审批、发布。
  • 每个环境都是真实环境 — dev、staging、pre-prod、prod。
  • 安全是设计出来的 — 没有长期凭证、私有存储、最小权限。
  • 隐私是架构属性 — 访客分析只采集地理信息,绝不采集 IP。
  • 历史是诚实的CHANGELOG、带标签的发布,以及每次发布的 SBOM

价值不在于规模 — 而在于纪律。本页记录平台本身:它的架构、交付模型、治理、 安全态势,以及塑造它的真实事故。

架构

平台由三部分组成 — 内容交付访客指标,以及支撑两者的 Terraform 控制平面。(交互视图:站点结构图 描绘站点;仓库 README 承载交付、指标和控制平面图表。)

站点 — 内容交付

三个部署目标,一个构建产物。main 部署到 stagingAWS 中的 S3 + CloudFront 组合,bucket 私有,通过 OAC 服务)。v* 标签部署到 pre-prod — 规范站点的 AWS 镜像 — 然后到 prod:GitHub Pages,位于 prod 环境的必需审阅者之后。

指标 — 访客分析

一个刻意做小、完全 serverless 的指标栈。CloudFront 提供地理信息头 — 因此 任何 IP 地址都不会到达 Lambda。写入端存储国家/城市/地区,90 天 TTL;读取端 服务站点指标页面。每个 Lambda 有自己的最小权限角色;API 公开 但受来源限制(为什么用 CloudFront?)。

Terraform — 控制平面

terraform/ci 创建按环境的 state 后端以及 GitHub Actions 用于构建和运行各栈的 OIDC 角色。Bootstrap 是唯一带外步骤 — 一个 GitHub Actions 之外的 AWS 用户 用自己的 IAM 权限创建它们;任何工作流都不会使用密钥。实现细节见 terraform/README.md

交付模型

两条交付平面,各有自己的闸门:

平面 路径 闸门
内容 main → staging · v* → pre-prod → 带闸门 Pages prod 上必需审阅者
基础设施 main → staging 自动 apply · v* → prod 仅 plan 手动 terraform apply

部署在正确 ref 的每次成功 CI 构建后运行 (#20 将 prod 拆分为 Pages + S3 并改用官方 Pages actions)。当构建产物与上次部署 字节相同时 staging 会跳过 — 一种内容哈希标记方案,避免纯文档合并反复刷新 bucket(#29#31)。

开发工作流

  • 仓库是唯一事实来源 — 同一个 docs/ 目录既构建本地站点也构建 CI。
  • 只用容器podman-compose up 运行 MkDocs 开发服务器;无需本地 Python/venv。
  • 本地 HTTPS 通过每台机器的 mkcert 根 CA — 与线上站点的 TLS 对齐。
  • 开发容器还提供 /health 端点,供其自身的 healthcheck 使用。
  • 本地检查与 CI 完全一致(check-compose.yaml + scripts/check_changed.sh)。

上手步骤见仓库 README

CI / CD

一个变更分四个阶段发布 — 每个阶段都记录在 .github/workflows/README.md

  1. Build — 严格的 mkdocs build(坏链接、过期翻译和 CSS 不平衡都会使构建失败)、 pip-audit,并在每次 push/PR 到 main 及每个 v* 标签时产出站点构建产物。
  2. 检查 — 每个表面一个工作流(checks-{shell,python,js,terraform,yml}), 各自按变更路径自门控 (skip-model, #17): 未触及的表面跳过并报告成功,因此十个必需检查永远不会阻塞无关 PR。
  3. 部署 — Build 成功后 workflow_runmain → staging,v* → pre-prod + 带闸门的 prod(见交付模型)。
  4. 发布与基础设施v* 标签创建带 CycloneDX SBOM 的 GitHub Release;每次 基础设施变更 Terraform 都会 plan(apply 保持手动);toggle-env / invalidate-cloudfront 是手动运维附加项。

检查名就是闸门名 — CI 报告 job 名(ci-buildchecks-python-ruff、…),使分支 保护和 ruleset 要求的与真正运行的完全一致 (#12)。

治理

Ruleset 即代码,保护两个关键的 ref (rulesets/):

Ref 保护
main 仅 PR:1 个审批、squash/rebase、过期评审作废、全部 10 项必需检查、禁止 force-push、无绕过 — 包括所有者
v* 标签 仅维护者创建;要求 ci-build 通过;创建后不可变

执行发生在 push 时且经过验证 — 拒绝记录与配置存放在 rulesets/main.mdrulesets/tags.md 中。PR 携带映射到精选集合的标签(ci · infra · security · governance · dependencies),并由第二个 GitHub 账户以普通协作者 身份评审 — 所有者不会合入任何未经批准的内容。Issue 模板强制七部分结构 (#15#18)。

安全

  • 没有长期密钥 — 部署和 Terraform 通过 OIDC 承担 AWS 角色 (#22 扩展了对带环境 job 的信任)。
  • 每个 job 最小权限 — 独立的 -terraform · -deploy · -invalidate · -toggle 角色;prod 指标边缘按设计没有 toggle 角色。
  • 私有存储 — S3 bucket 从不公开;CloudFront 仅通过 OAC 服务。
  • 来源限制 API — 指标端点公开但限于配置的站点来源;WAF/VPC 可选(免费层优先姿态)。
  • 依赖卫生Dependabot、 每次构建 pip-audit、每次发布 CycloneDX SBOM、CI 中 Checkov。
  • 报告政策:SECURITY.md

真实事故与留下的教训

平台在生产环境中以极具教育意义的方式出过故障。每个事故都记录在 CHANGELOG 中:

事故 根因 修复
Staging 每个对象 403 SSE-KMS 与 CloudFront OAC 不兼容(无 kms:Decrypt 回退到 AES256(aee25c6
多提交批次使 staging 过期 部署闸门只对比 HEAD~1..HEAD 现在每次成功 CI 构建都会部署(1bf9bd9
纯文档合并反复刷新 bucket s3 sync 总是重新上传新解压的产物 内容哈希标记跳过(#29#31
"Expected — waiting" 检查 必需检查名还没有任何运行报告过 先注册名称;再用 skip-model 按路径门控(#12#17

每个事故的模式:一次真实故障、一次根治修复、以及防止复发的手册更新 — 正是本站 以版本时间线记录的同一个循环。

如何探索