跳转至

基础设施部署

适用于所有环境。完成 Nginx 与网络配置 后执行。

基础设施清单

所有基础设施组件定义在 docker-compose.cloud.yml 中,通过共享的 tfrs-net Docker 网络互联。

组件 镜像 端口 用途
PostgreSQL postgres:16.1 127.0.0.1:5432 业务数据库
Redis redis:7-alpine 127.0.0.1:6379 缓存、会话
VictoriaMetrics victoriametrics/victoria-metrics:v1.108.1 127.0.0.1:8428 时序数据库(计费指标)
Infisical infisical/infisical:latest 127.0.0.1:8443 运行时密钥管理
Infisical PostgreSQL postgres:16-alpine 内部 Infisical 专用数据库
Infisical Redis redis:7-alpine 内部 Infisical 专用缓存

全部使用官方镜像,无需自定义构建。

1. 生成凭证

首次部署时,在服务器上生成所有随机凭证:

cat > /opt/tfrs/.env.infra << EOF
# ===== 业务数据库 =====
DB_USER=tfrs
DB_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')
DB_NAME=tfrs_manager

# ===== Redis =====
REDIS_PASSWORD=$(openssl rand -base64 18 | tr -d '/+=')

# ===== Infisical =====
INFISICAL_ENCRYPTION_KEY=$(openssl rand -hex 16)
INFISICAL_AUTH_SECRET=$(openssl rand -base64 32)
INFISICAL_SITE_URL=https://secret-{env}.turingfocus.cn
INFISICAL_PG_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')
INFISICAL_REDIS_PASSWORD=$(openssl rand -base64 18 | tr -d '/+=')
EOF

chown deploy:deploy /opt/tfrs/.env.infra
cat /opt/tfrs/.env.infra

⚠️ 关键备份: INFISICAL_ENCRYPTION_KEY 是加密所有密钥的主密钥,丢失后 Infisical 中存储的密钥将无法解密。必须离线备份。

同步到 CNB:DB_PASSWORDREDIS_PASSWORDJWT_SECRETSECRET_ENCRYPTION_KEY 的值同步到 CNB 密钥仓库的 tfrsmanager_env.{env}.yml 中,确保应用服务部署时能连接正确的数据库和 Redis。Infisical 服务端的 4 个变量(INFISICAL_ENCRYPTION_KEY 等)不需要放入 CNB,它们只存在于服务器上的 .env.infra 中。

两层配置的关系

配置文件 存放位置 包含内容 管理方式
.env.infra 服务器 /opt/tfrs/ 基础设施凭证(DB密码、Infisical主密钥等) 首次部署手动创建,长期不变
.env.prod CNB 每次部署生成 应用服务配置(业务变量、镜像标签等) CI/CD 自动生成

两者共享 DB_PASSWORDREDIS_PASSWORD 的值(必须一致),但 Infisical 服务端变量只在 .env.infra 中。

2. 启动基础设施

使用 docker-compose.cloud.yml 只启动基础设施层(不含应用服务):

cd /opt/tfrs
docker compose -f docker-compose.cloud.yml --env-file .env.infra up -d \
  postgres redis victoriametrics \
  infisical infisical-postgres infisical-redis

注意: deploy.sh(CI/CD 触发)只会重启应用服务(user-serviceadmin-service),不会动基础设施容器。基础设施一旦启动就长期运行。

3. 验证

# 检查所有容器健康状态
docker ps --format "table {{.Names}}\t{{.Status}}"

# 预期输出:全部 healthy
# tfrs_postgres          Up X minutes (healthy)
# tfrs_redis             Up X minutes (healthy)
# tfrs_victoriametrics   Up X minutes (healthy)
# tfrs_infisical         Up X minutes
# tfrs_infisical_pg      Up X minutes (healthy)
# tfrs_infisical_redis   Up X minutes (healthy)

# 验证数据库连接
docker exec tfrs_postgres pg_isready -U tfrs -d tfrs_manager

# 验证 Redis
docker exec tfrs_redis redis-cli -a ${REDIS_PASSWORD} ping

# 验证 VictoriaMetrics
curl -s http://127.0.0.1:8428/-/healthy

# 验证 Infisical
curl -s http://127.0.0.1:8443/api/status

4. Docker 镜像加速(国内服务器)

如果服务器位于国内,需要配置镜像加速器,否则拉取 Docker Hub 镜像会超时:

cat > /etc/docker/daemon.json << 'EOF'
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  },
  "registry-mirrors": [
    "https://mirror.ccs.tencentyun.com"
  ]
}
EOF
systemctl restart docker

此配置应在 服务器初始化 阶段完成。腾讯云服务器使用腾讯云加速器,阿里云使用阿里云加速器。

5. Infisical 首次初始化

基础设施容器全部运行后,需要初始化 Infisical:

5.1 创建管理员账号

  1. 浏览器访问 https://secret-{env}.turingfocus.cn
  2. 注册管理员账号

5.2 禁用公开注册(安全必须)

⚠️ 关键安全配置: 必须在创建管理员账号后立即执行,防止未授权用户注册。

  1. 进入 Server Console(左侧导航栏或 /admin
  2. GeneralAllow user signups → 选择 Disabled
  3. 点击 Save

禁用后,新用户只能通过管理员邀请加入。所有环境(staging / beta / prod)均须执行此步骤。

5.3 创建项目和 Machine Identity

  1. 创建项目(如 tfrs-{env}
  2. 进入 Organization → Access ControlMachine Identities tab
  3. 点击 Create Organization Machine Identity
  4. 名称:cvm-{env}-tfrs-manager
  5. Role:Member
  6. 进入 Machine Identity 详情页 → Universal AuthAdd Client Secret
  7. 记录 ClientIDClientSecret(Client Secret 仅显示一次)
  8. 在 Machine Identity 详情页底部 Projects 区域 → Add to Project
  9. 选择项目 tfrs-{env}
  10. Role:Admin

5.4 创建必要的文件夹结构

在 Infisical 项目的对应环境(Staging/Production)下,创建以下文件夹:

  1. 进入项目 → 选择环境 tab(如 Staging)
  2. 点击 Add Secret 旁的下拉箭头 → Add Folder
  3. 依次创建以下文件夹并 Save Changes
文件夹 用途
kubeconfig 存储各集群的 kubeconfig 文件
registry 存储镜像仓库认证凭证
metrics 存储 VictoriaMetrics 认证密码

⚠️ 必须创建: 如果缺少 /kubeconfig 文件夹,集群纳管时上传 kubeconfig 会返回 HTTP 500(Folder with path '/kubeconfig' not found)。

5.5 写入运行时密钥

进入对应文件夹,通过 Add Secret 创建密钥:

路径 密钥名 值来源 说明
/registry/ CNB_REGISTRY_USERNAME 固定值 cnb CNB 镜像仓库用户名
/registry/ CNB_REGISTRY_PASSWORD CNB 平台 → 个人设置 → Token CNB 镜像仓库密码
/metrics/ REMOTE_WRITE_PASSWORD openssl rand -base64 24 VictoriaMetrics remote write 认证

操作步骤: 在 Secrets 页面点击对应文件夹进入 → Add Secret → 填写 Key 和 Value → Create Secret。

⚠️ 缺少这些密钥的影响: 集群初始化时 Operator 部署会因无法拉取镜像而失败(ImagePullBackOff)。

5.6 更新 TFRSManager 环境变量

将以下值填入 CNB 密钥仓库的 tfrsmanager_env.{env}.yml

INFISICAL_CLIENT_ID: "{Step 5.2 中获得的 ClientID}"
INFISICAL_CLIENT_SECRET: "{Step 5.2 中获得的 ClientSecret}"
INFISICAL_PROJECT_ID: "{项目 ID,在项目 Settings 页面}"
INFISICAL_ENVIRONMENT: "{env}"
INFISICAL_SITE_URL: "https://secret-{env}.turingfocus.cn"

Infisical 职责说明

当前管理的密钥(仅 3 类)

密钥 路径 使用场景
CNB_REGISTRY_USERNAME /registry/ 集群初始化时创建 K8s ImagePullSecret
CNB_REGISTRY_PASSWORD /registry/ 同上 + Operator 升级
REMOTE_WRITE_PASSWORD /metrics/ 集群初始化时配置 Prometheus remote write

可选功能

  • Kubeconfig 存储/kubeconfig/):加密存储集群 kubeconfig,有本地文件 fallback

为什么这 3 个密钥不放 CNB?

这些密钥在 运行时 通过 API 动态获取(集群初始化时),不是部署时注入环境变量。CNB 是 CI/CD 工具,不提供运行时 API。

故障影响

Infisical 不可用时: - 不影响:已运行的数字员工、用户登录、支付、日常 API - 影响:新集群初始化、Operator 升级 - 降级:kubeconfig 存储回退到本地文件

运维

备份

# 导出 Infisical 数据库
docker exec tfrs_infisical_pg pg_dump -U infisical infisical > infisical_backup.sql

# 导出业务数据库
docker exec tfrs_postgres pg_dump -U tfrs tfrs_manager > tfrs_backup.sql

升级

# 升级单个组件
docker compose -f docker-compose.cloud.yml pull {service}
docker compose -f docker-compose.cloud.yml up -d {service}

常见问题(Staging 部署实录)

Infisical OOM

Infisical 首次启动需要运行 migration,内存需求较高。docker-compose.cloud.yml 中内存限制不得低于 1.5G,否则会被 OOM Killer 杀死(退出码 137)。

# 确认是否 OOM
docker inspect tfrs_infisical --format '{{.State.ExitCode}} {{.State.OOMKilled}}'
# 输出 137 true 即为 OOM

Infisical Migration Lock

如果 Infisical 在 migration 过程中被 OOM 杀死,会残留 migration lock,后续启动报错 Migration table is already locked

# 手动解锁
docker exec tfrs_infisical_pg psql -U infisical -d infisical \
  -c "UPDATE infisical_migrations_lock SET is_locked = 0;"
docker restart tfrs_infisical

日志 Volume 权限

应用服务容器以 UID 65532(nonroot)运行,Docker Volume 默认 owner 是 root,导致 permission denied 写日志失败。

# 修复权限
chown -R 65532:65532 /var/lib/docker/volumes/tfrs_tfrs_user_logs/_data/
chown -R 65532:65532 /var/lib/docker/volumes/tfrs_tfrs_admin_logs/_data/

SECRET_ENCRYPTION_KEY 长度

SECRET_ENCRYPTION_KEY 必须是正好 32 个字符的字符串(不是 64 位 hex)。代码直接用 []byte(keyStr) 不做 hex decode。

# 正确生成方式
openssl rand -base64 24 | head -c 32

Docker + Firewalld 冲突

firewalld 启动后会清除 Docker 的 iptables 规则,导致 docker network create 失败。必须在 firewalld 启动后重启 Docker

systemctl restart docker

完成后进入下一步:后端服务部署