Files
tiku-backend.net/docs/operations.md
xiong fe594c9ef5
Some checks failed
ci / release-gate (push) Has been cancelled
Refactor documentation:
- Remove outdated development plan from `development-plan.md`.
- Update `operations.md` to include details on authorization cache configuration.
- Revise `quickstart.md` for clarity on local development setup and database initialization.
- Delete redundant `redis-authorization-cache.md`.
- Add new `tenant-provisioning.md` to document the process of setting up a tenant from an empty database.
2026-08-03 10:27:35 +08:00

11 KiB
Raw Blame History

配置与后台任务

本文列出 API、Worker 和 DbMigrator 当前实际读取的配置。敏感值应通过环境变量、Secret Manager 或部署平台密钥注入,不能提交到仓库。

进程与依赖

进程 PostgreSQL Redis 说明
Tiku.Api 必需 Development 可选Production 必需 提供 HTTP API、认证、授权和缓存
Tiku.Worker 必需 Development 可选Production 必需 承载周期任务、任务队列、商业账务和授权缓存失效重试
Tiku.DbMigrator 必需 不需要 执行 Migration、内置目录 seed 和管理员引导

Development 未配置 Redis 时,安全服务使用进程内/数据库防线。Production 不允许 Redis 降级;后台任务在所有环境统一使用 PostgreSQL。

数据库

解析顺序:

  1. ConnectionStrings:Database
  2. DATABASE_URL
  3. 仅 DevelopmentHost=localhost;Database=tiku;Username=<当前系统用户>

DbMigrator 命令:

dotnet run --project Tiku.DbMigrator

dotnet ef migrations script \
  --project Tiku.Infrastructure \
  --startup-project Tiku.DbMigrator

dotnet ef migrations has-pending-model-changes \
  --project Tiku.Infrastructure \
  --startup-project Tiku.DbMigrator

Production 首次创建平台管理员必须显式执行:

export TIKU_BOOTSTRAP_PLATFORM_ADMIN_EMAIL='admin@example.com'
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_PASSWORD='use-a-strong-temporary-password'
export TIKU_BOOTSTRAP_PLATFORM_ADMIN_NAME='Platform Administrator'
dotnet run --project Tiku.DbMigrator -- --bootstrap-platform-admin

该命令只允许在不存在平台角色用户绑定时执行。管理员首次登录后必须改密。

Redis

连接串读取 ConnectionStrings:RedisREDIS_URL。当前用途:

  • 密码、短信发送和短信校验的安全窗口计数;
  • 租户 Feature 分布式缓存;
  • Production 的 ASP.NET Core Output Cache。

Redis key 使用环境前缀;配置解析会强制 AbortOnConnectFail=false。Redis 不是用户、Session、权限、套餐或用量的权威数据源。

授权缓存由 Security:AuthorizationCache 配置,默认 ModeDisabled。切换为 ShadowActive 前,应先确认 API 与 Worker 使用同一 Redis 和 PostgreSQL并观察 Tiku.Security.AuthorizationCache 的 mismatch、fallback 与 Redis 延迟指标。回滚只需切回 Disabled,不应回退授权版本或失效事件相关数据库结构。详细故障语义见认证、授权与租户隔离

Worker 与后台处理配置

{
  "Worker": {
    "Enabled": true,
    "JobPollSeconds": 2,
    "JobParallelism": 4,
    "JobBatchSize": 5
  },
  "TenantDomains": {
    "Enabled": true,
    "PollSeconds": 60,
    "BatchSize": 50,
    "DnsJsonEndpoint": "https://cloudflare-dns.com/dns-query",
    "VerificationRecordPrefix": "_tiku-verification",
    "AllowedCnameTargets": [],
    "GatewayBaseUrl": null,
    "GatewayApiKey": null
  },
  "TenantProvisioning": {
    "DefaultBaseOfferingCode": "starter",
    "DefaultTrialDays": 14,
    "OwnerActivationMinutes": 30
  },
  "SaasSubscriptions": {
    "Enabled": true,
    "BatchSize": 100,
    "PastDueGraceDays": 7
  },
  "FeatureUsageReconciliation": {
    "Enabled": true,
    "BatchSize": 100,
    "IntervalMinutes": 60
  },
  "CommercialBilling": {
    "Enabled": true,
    "BatchSize": 100,
    "AllowedWebhookHosts": []
  }
}

域名只有在 AllowedCnameTargets、DNS JSON endpoint、Gateway URL 和 API key 配置完成后,才可能从 Pending/Failed 进入 Active。仅 DNS 验证成功不代表 TLS 已就绪。

TenantProvisioning:DefaultBaseOfferingCode 必须指向 Active 基础套餐中当前有效的最新 Published 版本。Production API 启动时会查询 PostgreSQL 验证该版本存在;开通事务也会再次校验,缺失时返回 default_offering_unavailable,不会留下半成品租户。平台运营流程为:创建租户并抄录 CNAME/TXT → 等待域名 Active → 领取一次性激活链接 → 通过既有安全渠道交付 Owner。链接关闭后无法再次查看需要补发时必须填写原因并撤销旧链接。

后台任务状态和 RunAfter 存在 PostgreSQL。Worker 使用 FOR UPDATE SKIP LOCKED、五分钟租约和有限重试处理即时、延时及失败待重试任务;周期循环使用 PostgreSQL advisory lock 防止多实例重复执行。当前六个循环分别处理域名、订阅生命周期、Feature 用量、通用任务、授权缓存失效和商业账务。商业账务会生成续费应收、提醒、外部催缴投递和已审批退款Webhook 必须使用 HTTPS、Host allowlist、签名和私网地址拒绝。Worker:Enabled=false 会关闭全部循环,通常只用于测试或维护。

API 和 Worker 必须使用同一 PostgreSQL 数据库与一致的对象存储配置。迁移必须在两者启动前由 Tiku.DbMigrator 单独执行。

容器镜像从仓库根目录构建:

docker build -f Tiku.Api/Dockerfile -t tiku-api .
docker build -f Tiku.Worker/Dockerfile -t tiku-worker .

API 和 Worker 应独立设置副本数与资源限制。发布顺序固定为 Tiku.DbMigratorTiku.WorkerTiku.ApiTiku.PlatformAdmin.Web;不要在容器入口自动执行 Migration。

发布门禁、备份恢复和告警

.github/workflows/ci.yml 执行 restore、build、完整测试、format、EF 模型漂移、幂等 Migration SQL、平台前端检查、OpenAPI 生成漂移、API/Worker 镜像构建和 git diff --check。本地发布前应执行相同检查。

PostgreSQL 恢复演练使用标准 PGHOSTPGPORTPGUSERPGPASSWORD 环境变量,并通过 TIKU_BACKUP_SOURCE_DATABASE 指定源数据库:

TIKU_BACKUP_SOURCE_DATABASE=tiku scripts/rehearse-postgres-restore.sh

脚本只创建并删除名称受限的 tiku_restore_drill_* 临时数据库,校验 Migration 历史与租户表后自动清理。生产演练仍应在隔离实例上执行,并把耗时、备份大小和恢复点记录到变更单。

deploy/monitoring/postgres-exporter-queries.yaml 提供 Worker stale、最老 Pending Job、支付回调失败、逾期应收和催缴死信指标deploy/monitoring/commercial-alerts.yaml 提供对应 Prometheus 告警。部署时必须让 PostgreSQL exporter 使用只读监控账号,并先在预发布验证规则名称与采集前缀。

安全与网络配置

Production 启动至少需要核对:

配置 作用
Security:Jwt issuer、audience、当前 key ID、RSA 私钥和验证公钥
Security:DataProtection application name、X509 证书路径和密码
Security:TenantSecrets key ID 和 Base64 编码的 32 字节 master key
Authentication:Sms 至少 32 字符的验证码 pepper 和频控阈值
Tenancy:Resolution 正式平台 Host、可信代理、tenant code 允许路径
AllowedHosts 非通配 Host allowlist
Cors 明确的 Origin、Header、Method 和凭据策略
BrowserAuth:AllowedOrigins 允许使用 Browser Auth 的 HTTP(S) Origin
RateLimiting 全局和认证端点限流

可用环境变量覆盖包括:

  • TIKU_DATA_PROTECTION_APPLICATION_NAME
  • TIKU_DATA_PROTECTION_CERTIFICATE_PATH
  • TIKU_DATA_PROTECTION_CERTIFICATE_PASSWORD
  • TIKU_TENANT_SECRET_KEY_ID
  • TIKU_TENANT_SECRET_MASTER_KEY
  • TIKU_SMS_CODE_PEPPER

不要在命令输出、文档、Git diff 或错误报告中粘贴这些值。

对象存储与外部 Provider

对象存储读取 Storage / Storage:AliyunOssAPI 与 Worker 都支持 STORAGE_*ALIYUN_OSS_* 环境变量。当前默认实现是阿里云 OSS并强制租户 key 前缀、上传大小和 MIME allowlist。租户导出使用 application/gzip,该类型不能从 allowlist 删除。

ClamAV 资源安全扫描

API 和 Worker 都读取 Security:ClamAV

{
  "Security": {
    "ClamAV": {
      "Host": "clamav",
      "Port": 3310,
      "TimeoutSeconds": 30,
      "ChunkBytes": 65536,
      "StreamMaxLength": 524288000
    }
  }
}

Worker 使用 ClamAV INSTREAM 协议,不在本地落盘待扫描对象。启动校验要求 StreamMaxLength >= Storage:MaxUploadBytes;同时必须把 clamd 自身的 StreamMaxLength 配到相同或更高值。扫描结果为 FOUND 时资源标记为 Failed 并记录病毒签名ClamAV 超时或不可用时任务保留 Pending 并退避重试。只有 Passed 或系统明确标记为可信的 NotRequired 资源可以签发访问地址。

身份、短信、支付、通知和 AI 的租户配置由业务后台写入 TenantExternalProvider;敏感值写入加密的 TenantSecret。全局默认配置不能绕过租户 Provider 状态和 Secret 边界。

健康检查与观测

  • GET /api/health:轻量 liveness只说明 API 进程可响应。
  • GET /api/health/ready:检查 PostgreSQL 和已配置 Redis依赖未就绪时返回 503匿名响应只包含总体状态和检查时间。
  • GET /api/platform-admin/operations/health:需要 platform:operations:view,返回 PostgreSQL、Redis、Worker heartbeat、ClamAV 和对象存储配置状态。
  • GET /api/platform-admin/operations/workers:查询 Worker 心跳、周期循环和 stale 状态。
  • GET /api/platform-admin/operations/job-metrics:查询队列状态、最老 Pending 任务与过期租约。
  • 设置 OpenTelemetry:OtlpEndpoint 后导出 ASP.NET Core、HTTP client 和数据库观测数据。
  • Serilog 输出结构化请求日志;数据库性能拦截器记录慢查询指标。

Readiness 为绿色不等于认证授权、跨租户隔离或后台任务恢复演练已通过,发布仍需执行对应集成测试。

租户归档与导出发布门禁

  • 租户归档是逻辑归档,禁止硬删除。
  • 归档前必须存在 24 小时内成功完成的租户导出,且不能有 Processing 后台任务。
  • 导出包是 tar.gz,包含 manifest、租户、成员、域名和资源元数据明确排除密码哈希、令牌、密钥明文、Data Protection keys 和全局平台数据。
  • 归档会撤销该租户授权域 Session、禁用域名并失效运行时缓存恢复后租户为 Suspended,域名为 Pending,必须重新审核后再激活。
  • Owner 转移目标必须是已有 Active 成员,并在同一事务内同步成员角色和后台角色绑定。
  • 发布前至少演练一次导出可下载、归档阻断条件、归档、恢复和 Owner 转移。

后台任务权威边界

当前运行时不依赖 RabbitMQ也没有消息 inbox/outbox 发布链路。即时、延时、重试和商业任务均以 PostgreSQL 状态为准Redis 不保存任务或商业状态真相。回滚时不得通过恢复旧消息表绕过当前数据库状态机。