2026-05-26 01:21:39 +08:00
..
2026-05-14 09:57:01 +08:00
2026-05-26 01:21:39 +08:00
2026-05-26 01:21:39 +08:00
2026-05-14 09:57:01 +08:00
2026-05-14 09:57:01 +08:00

腾讯云 TAT 滚动部署方案

本方案只部署本仓库 Go 微服务,不接管同机已有 Java 项目。远端连接使用腾讯云 TAT发布时只操作 hyapp-* systemd unit、hyapp-* Docker 容器和 /etc/hyapp/<service>/docker.env

MySQL、Redis、MQ 都按腾讯云托管资源处理。本方案不会在这些 CVM 上部署、重启或迁移本地 MySQL/Redis/MQ服务配置只需要指向腾讯云托管实例的内网地址。

机器拓扑

deploy 机器是发布控制面,不承载业务流量:

机器 实例 ID 公网 IP 私网 IP 角色
deploy ns-ntmpcd3a 43.164.75.199 10.2.1.3 构建镜像、推送镜像、调用 TAT/CLB API 调度发布

当前机器按截图落到以下服务:

机器 实例 ID 私网 IP 本仓库服务
gateway-1 ins-aeyaoj40 10.2.1.8 gateway-service
gateway-2 ins-irvi5b7u 10.2.2.17 gateway-service
new-app-1 ins-fi5zufpk 10.2.1.4 room-service, user-service
new-app-2 ins-hwhaoe8c 10.2.1.13 room-service, user-service
new-game-1 ins-ir229jtw 10.2.1.10 game-service
new-game-2 ins-460rw7gu 10.2.1.6 game-service
new-app-activity-1 ins-n8wut6n8 10.2.1.11 activity-service, notice-service
new-app-activity-2 ins-d1n303sa 10.2.1.7 activity-service, notice-service
pay-1 ins-ceqfcxd2 10.2.11.14 wallet-service
pay-2 ins-awhb74q6 10.2.12.5 wallet-service

如果 new-app-* 只部署 room-service 或只部署 user-service,直接删掉 inventory 中对应服务的 host 绑定,不要让脚本猜。

部署模式

采用“deploy 服务器调度 + 业务机只运行镜像”的模式:

  1. deploy 服务器拉取本仓库代码,构建 Docker 镜像,推送到 CCR/Harbor。
  2. deploy 服务器调用腾讯云 CLB API 对目标实例摘流。
  3. deploy 服务器通过 TAT 在目标业务机执行 docker pullsystemctl restart hyapp-<service>
  4. 目标业务机只保存 /etc/hyapp/<service>/config.yamldocker.env,不拉代码、不编译、不保存 Git 凭据。

不要让每台业务服务器自己 git pull && build。那会把代码权限、构建环境、版本一致性和回滚都扩散到业务机,且多服务发布时无法统一做 CLB 摘流。

前置条件

  1. 每台目标机已安装腾讯云 TAT agent控制台能执行命令。
  2. 每个 Go 服务已按 deploy/standalone/systemd 安装对应 systemd unit。
  3. 每个 Go 服务已有 /etc/hyapp/<service>/config.yaml/etc/hyapp/<service>/docker.env
  4. 每个服务至少有两台实例CLB 后端都挂实例端口。
  5. room-service 每台机器必须有唯一 node_idadvertise_addr 必须是当前机器私网地址,例如 10.2.1.4:13001,不能写内网 CLB。
  6. 每个 config.yamlmysql_dsnredis_addr、MQ endpoint/topic/group 指向腾讯云托管资源的私网地址。
  7. 发布机安装腾讯云 Python SDK 和 YAML 解析依赖:
python3 -m pip install tencentcloud-sdk-python PyYAML

凭据通过环境变量提供:

export TENCENTCLOUD_SECRET_ID="..."
export TENCENTCLOUD_SECRET_KEY="..."
export TENCENTCLOUD_REGION="me-saudi-arabia"

如果继续沿用 hy-app-monitor,可以把这些变量放在 deploy 机器的 /opt/hy-app-monitor/.env,运行脚本时传 --env-file /opt/hy-app-monitor/.env。本地开发机路径 /Users/hy/Documents/hy/hy-app-monitor/.env 只用于本机调试。

Deploy 服务器初始化

deploy / 10.2.1.3 上安装基础工具:

sudo mkdir -p /opt/deploy/sources /opt/deploy/inventory
sudo yum install -y git docker python3 python3-pip || sudo apt-get update && sudo apt-get install -y git docker.io python3 python3-pip
sudo systemctl enable --now docker
python3 -m pip install --user tencentcloud-sdk-python PyYAML

拉取本仓库:

cd /opt/deploy/sources
git clone <YOUR_GIT_REPO_URL> hyapp-server
cd hyapp-server

准备 inventory

cp deploy/tencent-tat/inventory.prod.example.json /opt/deploy/inventory/hyapp.prod.json
vi /opt/deploy/inventory/hyapp.prod.json

inventory 里的 registry 必须和实际镜像仓库一致。如果使用 hy-app-monitor 里的 Harbor 配置,通常是:

registry = ${HARBOR_REGISTRY}/${HARBOR_PROJECT}

业务配置放到各目标机 /etc/hyapp/<service>/config.yaml。腾讯云 MySQL、Redis、MQ、JWT、IM/RTC/COS 等密钥不要提交到 Git。

配置字段契约以 services/<service>/configs/config.tencent.example.yaml 为准。开发时如果在本地 config.yamlconfig.docker.yaml 新增字段,必须同时补到 config.tencent.example.yaml;生产渲染前运行校验,避免线上漏字段:

python3 deploy/tencent-tat/validate_rendered_configs.py \
  --inventory deploy/tencent-tat/inventory.prod.example.json

如果已经渲染了生产最终配置,还要校验每台机器的最终 YAML

python3 deploy/tencent-tat/validate_rendered_configs.py \
  --inventory deploy/tencent-tat/inventory.prod.example.json \
  --rendered-dir /tmp/hyapp-rendered-prod

该脚本只比较 YAML key不打印配置值避免把生产密钥带到日志里。

构建并推送镜像

deploy 服务器上执行。2 核 2GiB 机器可以作为调度器;如果全量构建 OOM 或太慢,把构建放到 CIdeploy 服务器只负责调度发布。

cd /opt/deploy/sources/hyapp-server
TAG="$(date -u +%Y%m%d%H%M%S)-$(git rev-parse --short HEAD)"
REGISTRY="10.2.1.3:18082/hyapp"

docker build -t "$REGISTRY/gateway-service:$TAG" -f services/gateway-service/Dockerfile .
docker build -t "$REGISTRY/room-service:$TAG" -f services/room-service/Dockerfile .
docker build -t "$REGISTRY/user-service:$TAG" -f services/user-service/Dockerfile .
docker build -t "$REGISTRY/wallet-service:$TAG" -f services/wallet-service/Dockerfile .
docker build -t "$REGISTRY/activity-service:$TAG" -f services/activity-service/Dockerfile .
docker build -t "$REGISTRY/game-service:$TAG" -f services/game-service/Dockerfile .
docker build -t "$REGISTRY/notice-service:$TAG" -f services/notice-service/Dockerfile .

docker push "$REGISTRY/gateway-service:$TAG"
docker push "$REGISTRY/room-service:$TAG"
docker push "$REGISTRY/user-service:$TAG"
docker push "$REGISTRY/wallet-service:$TAG"
docker push "$REGISTRY/activity-service:$TAG"
docker push "$REGISTRY/game-service:$TAG"
docker push "$REGISTRY/notice-service:$TAG"

如果实际用 HarborREGISTRY 换成 ${HARBOR_REGISTRY}/${HARBOR_PROJECT},并先 docker login

配置 inventory

复制模板后填真实 CLB

cp deploy/tencent-tat/inventory.prod.example.json deploy/tencent-tat/inventory.prod.json
vi deploy/tencent-tat/inventory.prod.json

必须替换:

  • gateway-service.clb.load_balancer_id:公网 gateway CLB。
  • gateway-service.clb.listener_ids:公网 HTTP/HTTPS 监听器。
  • 内部服务各自的 load_balancer_idlistener_idsroom/user/wallet/activity/game 内网 CLB。

脚本通过实例 ID、私网 IP、端口三者匹配 CLB target。发布前会把当前实例在相关 listener 下的权重改成 0,服务健康后恢复原权重。

managed_dependencies 只记录部署边界:腾讯云 MySQL/Redis/MQ 是外部托管依赖,不纳入 TAT 发布动作。生产变更这些资源时单独走云数据库、Redis 或 MQ 的变更流程。

当前生产 inventory 已写入真实绑定:

服务 CLB 监听器 对外/内网入口
gateway-service lb-cbiabr1q lbl-ktvz8m6k / rule loc-pwedmsmm https://api.global-interaction.com -> 13000
room-service lb-epvnr4o0 lbl-d2urlzba 10.2.1.16:13001
user-service lb-epvnr4o0 lbl-honi8z3a 10.2.1.16:13005
activity-service lb-epvnr4o0 lbl-j7oqtfhq 10.2.1.16:13006
game-service lb-epvnr4o0 lbl-ku138b4y 10.2.1.16:13008
notice-service lb-epvnr4o0 lbl-aux9xsjq 10.2.1.16:13009
wallet-service lb-4f5xi6p0 lbl-9wi5mvu4 10.2.1.15:13004

Harbor 项目使用 hyapp,当前生产镜像前缀是 10.2.1.3:18082/hyapp。不要使用其他业务项目名前缀。

线上服务配置边界

这些机器上只部署 Go 服务进程:

  • gateway-serviceroom_service_addr/user_service_addr/wallet_service_addr/activity_service_addr/game_service_addr 指向各服务内网 CLB/DNS。
  • room-servicemysql_dsn 指向腾讯云 MySQLredis_addr 指向腾讯云 Redisadvertise_addr 指向本机私网 IP。
  • user-servicemysql_dsn、worker 里引用的 wallet/room MySQL DSN、登录风控 Redis 都指向腾讯云托管实例。
  • wallet-serviceactivity-servicegame-serviceMySQL 和下游 gRPC 地址都使用腾讯云托管资源或内网 CLB/DNS。
  • notice-servicemysql_dsn 指向 hyapp_noticewallet_database 指向 hyapp_wallet;它只读取 wallet outbox 并写自己的投递位点,不修改钱包事实表。
  • MQ 当前只作为 outbox/event bus 方向的外部托管依赖;本脚本不会创建 topic、consumer group 或本地 broker。

腾讯云 MySQL DSN 必须保留 loc=UTC。Redis 使用同一托管实例时,用 redis_db 或 key prefix 区分业务域,不要把 Redis 当恢复事实来源。

常用命令

先看计划,不执行远端动作:

python3 deploy/tencent-tat/hyapp_tat_deploy.py plan \
  --inventory deploy/tencent-tat/inventory.prod.json \
  --services gateway-service,room-service

用 TAT 连接目标机并自动发现真实部署状态和 CLB 绑定:

python3 deploy/tencent-tat/hyapp_tat_deploy.py discover \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services gateway-service,room-service,user-service,wallet-service,activity-service,game-service,notice-service

discover 会读取每台目标机的 hyapp-* systemd unit、/etc/hyapp/*/docker.envhyapp-* 容器和监听端口,并通过 CLB API 按后端私网 IP/端口反查负载均衡绑定。

单服务重启:

python3 deploy/tencent-tat/hyapp_tat_deploy.py restart \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services wallet-service \
  --yes

多服务重启:

python3 deploy/tencent-tat/hyapp_tat_deploy.py restart \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services room-service,user-service,wallet-service,activity-service,game-service,notice-service \
  --yes

单服务更新部署:

python3 deploy/tencent-tat/hyapp_tat_deploy.py deploy \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services gateway-service \
  --tag 20260513-1349 \
  --yes

多服务更新部署:

python3 deploy/tencent-tat/hyapp_tat_deploy.py deploy \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services gateway-service,room-service,user-service,wallet-service,activity-service,game-service,notice-service \
  --tag 20260513-1349 \
  --yes

如果某个服务镜像 tag 不同,可以显式传镜像:

python3 deploy/tencent-tat/hyapp_tat_deploy.py deploy \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services gateway-service,wallet-service \
  --image gateway-service=10.2.1.3:18082/hyapp/gateway-service:gw-20260513 \
  --image wallet-service=10.2.1.3:18082/hyapp/wallet-service:pay-20260513 \
  --yes

只维护某一台机器时使用 --hosts,例如只重启 gateway-1

python3 deploy/tencent-tat/hyapp_tat_deploy.py restart \
  --env-file /opt/hy-app-monitor/.env \
  --inventory /opt/deploy/inventory/hyapp.prod.json \
  --services gateway-service \
  --hosts gateway-1 \
  --yes

无感更新顺序

对每个服务实例,脚本固定执行:

  1. 读取该实例当前 CLB 绑定和原权重。
  2. 将该实例在所有匹配 listener/rule 下的权重改为 0
  3. 等待 drain_seconds,让 CLB 停止分配新请求。
  4. 通过 TAT 在目标机更新 docker.envIMAGE,执行 docker pull
  5. systemctl restart hyapp-<service>Docker 发送 SIGTERM,服务进入 graceful shutdown。
  6. 等待 systemd active 和 Docker health 恢复。
  7. 恢复该实例原 CLB 权重。
  8. 等待 stabilize_seconds 后进入下一台实例。

如果重启或健康检查失败,脚本会停止后续步骤;已经摘流的故障实例保持权重 0,避免坏实例重新接流,需要人工确认后再恢复。

用户无感边界

  • 客户端长连接、房间公屏、单聊仍由腾讯云 IM 承接gateway 重启不会断开 IM。
  • gateway 是 HTTP 入口,摘流后只影响当前实例的新 HTTP 请求;另一台 gateway 继续接流。
  • 内部服务通过各自内网 CLB 摘流滚动gateway 的 gRPC client 已配置短重试,只覆盖瞬时 UNAVAILABLE
  • room-service 已有 owner route/node registry。旧 owner 停机时会释放 lease异常退出时最多等 lease_ttl 到期后其他节点接管。
  • 正在执行的单个 HTTP/gRPC 请求可能返回失败,客户端必须按现有接口幂等键重试;“无感”指发布期间整体入口不断流、房间 IM 不断连。

禁止项

  • 不要使用 --no-clb 做正常发布;它只适合孤立排障。
  • 不要多个 room-service 共用同一个 node_id
  • 不要把 room-service.advertise_addr 写成 CLB 地址。
  • 不要先 systemctl restart 再摘 CLB。
  • 不要在同机 Java compose 目录里执行本仓库部署命令。