跳到主要内容

系统架构

本章从部署拓扑、组件职责、运行时依赖与子系统间数据流等角度,完整描述 Cirrus CDN 的系统架构。

总体架构

Cirrus CDN 由四个核心层组成:

  1. 控制平面——基于 FastAPI 的应用(src/cirrus/app.py),提供配置与自动化的 REST 接口。
  2. 数据平面——基于 OpenResty 的反向代理(openresty/),负责服务终端流量、执行缓存并输出指标。
  3. 自动化底盘——Celery worker/beat 进程(src/cirrus/celery_app.py),承担 ACME 申请、证书续签与节点健康检查。
  4. 可观测性与运维工具——Prometheus、Grafana、logrotate 以及在 docker-compose.yml 中定义的支撑服务。

Redis 作为各层共享的状态存储与发布订阅总线。

            +-------------------+
| Frontend |
| Next.js (SPA) |
+-------------------+
|
v
+-------------------+
| FastAPI App |
| (src/cirrus/) |
+-------------------+
|
Redis <------> Celery Workers/Beat
|
v
+----------------------------------+
| OpenResty Edge (Data Plane) |
+----------------------------------+
|
v
End-user Requests

控制与数据平面

控制平面数据平面
配置中心(Redis)内容缓存与边缘路由
分发管道(Redis 发布订阅 + Celery 队列)健康检测与自治修复
调度引擎/区域构建日志回传与指标导出

高可用性设计

  • 多区域多活(独立边缘节点与权威 DNS 从节点)
  • 零中断发布(模板化 Compose/Ansible,蓝绿/滚动)
  • 自动容灾(NOTIFY 驱动的从节点 + 健康感知激活)
  • 自愈循环(Celery 健康检查驱动 active 切换并触发区域重建)

部署拓扑

docker-compose.yml 定义了本地场景下的服务编排。关键服务包括:

  • redis:启用 AOF 持久化的主数据存储(services.redis)。
  • api:由 Dockerfile 第二阶段构建的 FastAPI 服务,挂载 ./src 为只读,并封装静态化的 Next.js 导出内容。
  • openresty:基于 openresty/Dockerfile 的自定义镜像,使用宿主网络直接暴露 8080/8443 端口。
  • workerbeat:与 API 共享 Python 基础镜像的 Celery worker/beat 进程。
  • caddy:用于本地证书签发的内部 CA 与 ACME 目录。
  • acmedns:负责 ACME DNS-01 验证的权威服务器。
  • nsd:从隐藏主节点接收 NOTIFY 的权威 DNS 从节点。
  • prometheusgrafanalogrotatefakedns:运维支撑系统。

apiworkerbeatcaddyacmednsnsd 共同接入自定义的 acmetest bridge 网络,并通过静态 IP 简化 DNS/MX 信任关系。

构建与运行产物

Python 与前端镜像(Dockerfile

  • 第一阶段执行 pnpm build 构建 Next.js 前端,并利用缓存挂载加速 .next 产物。
  • 第二阶段(ghcr.io/astral-sh/uv:python3.13-trixie-slim)通过 uv sync 安装 Python 依赖(遵循 uv.lock),将静态导出复制至 /app/static,并配置入口脚本(docker/entrypoint.sh)在调用 uvicorn 前修复权限并按需复制 CA 证书。

OpenResty 镜像(openresty/Dockerfile

  • 构建阶段安装 lua-resty-httpnginx-lua-prometheus 并编译 nginx_cache_multipurge
  • 模板阶段依据构建参数(如 NGX_HTTP_PORTNGX_METRICS_ALLOW)渲染 openresty/conf/nginx.conf.j2
  • 运行阶段预置占位 TLS 证书、拷贝 Lua 脚本并以前台模式启动 openresty

Prometheus 镜像(prometheus/Dockerfile

Prometheus 镜像根据环境加载 prometheus.dev.ymlprometheus.prod.yml,默认抓取 127.0.0.1:9145 的 OpenResty 指标。

配置与状态管理

Redis 是唯一可信源。核心键空间如下:

键模式作用
cdn:domains(集合)所有受管域名。
cdn:dom:{domain}JSON 编码的域名配置(DomainConf)。
cdn:nodes(集合)已知边缘节点 ID。
cdn:node:{id}保存节点 IP、健康计数与激活状态的哈希。
cdn:cert:{domain}TLS 资产(完整链 PEM、私钥、签发时间)。
cdn:acme:{domain}ACME 注册状态,包括 acme-dns 凭据。
cdn:acme:lock:{domain} / cdn:acme:task:{domain}证书任务并发锁。
cdn:tokenscdn:token:{id}cdn:token_hash:{hash}服务令牌注册与检索。
cdn:acmeacct:global共享的 ACME 账号密钥材料。
cdn:acmecertkey:{domain}复用续签的证书私钥。

发布订阅通道包括 cdn:cname:dirty(触发 DNS 区域重建)与 cdn:purge(缓存失效通知)。

数据流概览

  1. 域名接入——前端向 /api/v1/domains/{domain} 发起 POST;API 将配置写入 Redis;DNS 服务重建区域;OpenResty 在后续请求中加载配置。
  2. 节点生命周期——操作人员向 /api/v1/nodes 提交列表;Redis 更新节点哈希;触发 DNS 重建;Celery 健康检查调整 active 状态。
  3. 缓存清除——API 向 cdn:purge 发布 JSON 消息;OpenResty 订阅者调用 cache_multipurge 执行 PURGE。
  4. TLS 签发——API 入队 Celery 任务;worker 申请/续签证书并写入 Redis;OpenResty 在 SNI 协商时动态加载。

依赖与集成

  • Redis(Python 使用 redis.asyncio,Lua 使用 resty.redis)——作为配置存储、缓存与发布订阅通道。
  • Celery——使用 Redis 作为 broker/backend 的异步任务执行引擎。
  • acme-dns——处理 ACME 的 DNS-01 验证。
  • Caddy——托管本地 ACME CA;Celery worker 通过 docker/entrypoint.sh 复制 CA 证书实现信任。
  • NSD——接收 HiddenMasterServer NOTIFY 的权威 DNS 从节点。
  • Prometheus 与 Grafana——指标采集与可视化。

环境

Docker 组合主要面向本地开发;生产环境依赖 just deploy 调用的 Ansible 剧本(见 ansible/)。环境变量(如 CNAME_BASE_DOMAINACME_DIRECTORYDNS_MASTER_PORT)需按环境调整。第 11 章列出了完整清单。

可扩展性考量

  • API/服务进程除内存会话缓存外是无状态的,如将会话机制迁移至 Redis,可横向扩容(参见第 11 章)。
  • OpenResty 可通过 /api/v1/nodes 注册更多节点实现扩容;一致性哈希保证域名在节点 churn 下的稳定性。
  • DNS 隐藏主节点仍为单实例;NSD 可横向扩展以满足区域冗余。
  • Redis 是单点;生产工作负载可考虑托管或集群部署。

本章之后将逐层展开,首先是第 3 章的控制平面 API。