跳转至

新增服务 SOP (Standard Operating Procedure)

用途:新服务上线的标准检查清单 适用对象:基础设施维护者


🚀 新服务上线检查清单

1. 代码结构验证

确保新服务目录包含以下文件:

文件 必需 用途
compose.yaml Docker Compose 配置
deploy.py Deployer 类 + invoke tasks
shared_tasks.py status() 健康检查
vault-agent.hcl Vault Agent 配置
secrets.ctmpl Secrets 模板
vault-policy.hcl ⚠️ Vault 策略(可选,有默认)
README.md 服务文档

2. Vault Secrets 配置

# 1. 存储服务所需的密钥
invoke env.set <KEY>=<VALUE> --project=<project> --service=<service>

# 2. 生成 AppRole 凭证(role_id/secret_id)
export VAULT_ROOT_TOKEN=$(op read 'op://Infra2/.../Token')
invoke vault.setup-approle

# 3. 验证 VAULT_ROLE_ID/VAULT_SECRET_ID 已写入 Dokploy
# (setup-approle 会自动注入,检查 Dokploy UI 确认)

3. IaC 集成验证

仅适用于 platform 项目服务 (IaC Runner 管理范围)

# 验证服务被 discover_services() 发现
python -c "
import sys
sys.path.insert(0, 'libs')
from deploy.deployer import discover_services
services = discover_services()
print('Discovered services:')
for k, v in sorted(services.items()):
    print(f'  {k} -> {v}')
"

确保新服务出现在列表中,格式为: - platform/<service><service>.sync (由 IaC Runner 自动同步) - finance_report/<service>fr-<service>.sync (使用应用 CI) - bootstrap/<service><service>.sync (手动部署)

4. 部署验证

# 部署服务
python -m tools.deploy_v2 --service platform/<service> --type staging --iac-ref vX.Y.Z --domain zitian.party

# 验证健康状态
invoke <service>.status

# 检查容器运行状态
ssh root@$VPS_HOST 'docker ps | grep <container-name>'

5. 线上健康检查

# HTTP 健康端点
curl -s https://<subdomain>.zitian.party/health

# 或检查容器健康状态
ssh root@$VPS_HOST 'docker inspect <container> --format "{{.State.Health.Status}}"'

6. Post-Merge CI 验证

仅适用于 platform 项目服务 (IaC Runner 不管理 bootstrap 和应用层)

验证 GitHub Webhook 和 IaC Runner 能正确触发同步:

  1. IaC Runner 健康检查

    curl -s https://iac.zitian.party/health
    # 期望: {"status": "healthy"}
    

  2. 测试 Webhook (platform 服务)

    # 推送一个小变更到 main (e.g., 修改 platform/XX.service/README.md)
    git commit -am "test: trigger iac-runner webhook"
    git push origin main
    
    # 观察 IaC Runner 日志
    ssh root@$VPS_HOST "docker logs iac-runner -f"
    
    # 期望日志:
    # "Webhook received"
    # "Changed files: platform/XX.service/README.md"
    # "Running: invoke <service>.sync"
    # "✓ Config hash unchanged, skipping deploy" (或 "✓ Deployed successfully")
    

  3. 手动同步测试

    # 使用 invoke 直接同步
    invoke <service>.sync
    
    # 期望输出:
    # "Checking config hash..."
    # "✓ Config hash unchanged, skipping deploy" (幂等性验证)
    

  4. 验证 config hash 幂等性

    # 多次运行 sync,应该全部跳过 (no-op)
    invoke <service>.sync
    invoke <service>.sync
    invoke <service>.sync
    

注意事项: - Bootstrap 服务 (vault, 1password, iac-runner) 必须手动部署,不走 IaC Runner - 应用层服务 (finance_report, wealthfolio) 使用各自的 GitHub CI/CD,不走 IaC Runner - Platform 服务 (postgres, redis, authentik, etc.) 才由 IaC Runner 自动同步

7. 文档更新

完成以下文档更新:

  • [ ] 服务 README.md
  • [ ] 如果是新项目,更新 vault.setup-approle 中的 projects 列表
  • [ ] 更新 sync_runner.py 中的 SERVICE_TASK_MAP (如需手动映射)
  • [ ] 更新相关 SSOT 文档

📋 快速模板

deploy.py 模板

import sys
from libs.deploy.deployer import Deployer, make_tasks

shared_tasks = sys.modules.get("platform.XX.new.shared")

class NewDeployer(Deployer):
    service = "new"
    compose_path = "platform/XX.new/compose.yaml"
    data_path = "/data/platform/new"
    secret_key = "password"

    # Domain config (set subdomain = None for SSO-protected services)
    subdomain = "new"
    service_port = 8080
    service_name = "server"

if shared_tasks:
    _tasks = make_tasks(NewDeployer, shared_tasks)
    status = _tasks["status"]
    pre_compose = _tasks["pre_compose"]
    composing = _tasks["composing"]
    post_compose = _tasks["post_compose"]
    setup = _tasks["setup"]
    sync = _tasks["sync"]

shared_tasks.py 模板

from invoke import task
from libs.common import check_service

@task
def status(c):
    return check_service(c, "new", "health-cmd")

vault-agent.hcl 模板

新服务默认使用 AppRole 认证(role_id + secret_id,由 invoke vault.setup-approle 注入为 Dokploy env VAULT_ROLE_ID/VAULT_SECRET_ID,compose entrypoint 落盘到 /vault/role_id/vault/secret_id)。旧的 token_file/VAULT_APP_TOKEN 周期 token 模型 已全面退役(含 IaC Runner,#369;见 docs/ssot/bootstrap.iac_runner.md §6.4)。

vault {
  # VAULT_ADDR 来自容器环境变量;未显式指定 address 时 vault-agent 自动读取 VAULT_ADDR。
}

auto_auth {
  method "approle" {
    config = {
      role_id_file_path                   = "/vault/role_id"
      secret_id_file_path                 = "/vault/secret_id"
      remove_secret_id_file_after_reading = false
    }
  }

  sink {
    type = "file"
    config = {
      path = "/vault/.token"
    }
  }

  exit_on_err = true
}

template_config {
  static_secret_render_interval = "5m"
  exit_on_retry_failure = true
}

template {
  source      = "/etc/vault/secrets.ctmpl"
  destination = "/vault/secrets/.env"
  perms       = 0644
}

🔗 相关文档


Last updated: 2026-01-21