Add lucky gift deployment support
This commit is contained in:
parent
35bc2696f4
commit
f441fd49c0
@ -4,6 +4,6 @@ dist
|
||||
.DS_Store
|
||||
*.tsbuildinfo
|
||||
npm-debug.log*
|
||||
deploy/tencent-tat/inventory.prod.json
|
||||
deploy/tencent-tat/deploy-platform.inventory.prod.json
|
||||
deploy/tencent-tat/hyapp-services.inventory.prod.json
|
||||
deploy/tencent_tat/inventory.prod.json
|
||||
deploy/tencent_tat/deploy-platform.inventory.prod.json
|
||||
deploy/tencent_tat/hyapp-services.inventory.prod.json
|
||||
|
||||
22
AGENTS.md
22
AGENTS.md
@ -36,14 +36,20 @@
|
||||
|
||||
## 生产特殊服务
|
||||
|
||||
1. `admin-server` 不在标准 prod inventory 的滚动服务清单里;它部署在 Saudi 机器 `43.164.70.49` / `10.2.1.2`,实例 `ins-p11begwe`。
|
||||
2. `admin-server` 的 systemd 是 `hyapp-admin-server`,容器是 `hyapp-admin-server`,镜像是 `10.2.1.3:18082/hyapp/admin-server:<tag>`,配置是 `/etc/hyapp/admin-server/config.yaml`,Docker env 是 `/etc/hyapp/admin-server/docker.env`,监听 `10.2.1.2:13100`。
|
||||
3. 更新 `admin-server` 时,由 deploy 机器 `43.164.75.199` 在 `/opt/deploy/sources/hyapp-server` 拉取 Gitea `git@gitea.haiyihy.com:hy/hyapp-server.git` 的 `origin/main`,构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`,再通过 Tencent TAT 到 `ins-p11begwe` 修改 docker env 的 `IMAGE` 后重启 `hyapp-admin-server`。线上只允许发布 `origin/main`;发布后必须验证容器镜像 tag、systemd `active`、`13100` 监听和 `healthz/readyz`。`hyapp_admin_server_deploy.py` 是旧广州机器二进制发布脚本,不适用于当前生产 `admin-server`。
|
||||
4. HyApp `cron-service` 当前部署在 Saudi 主服务机器 `new-app-1`,实例 `ins-fi5zufpk`,内网 `10.2.1.4`。
|
||||
5. `cron-service` 的 systemd 是 `hyapp-cron-service`,容器是 `hyapp-cron-service`,配置是 `/etc/hyapp/cron-service/config.yaml`,Docker env 是 `/etc/hyapp/cron-service/docker.env`,监听 `13007`。
|
||||
6. `cron-service` 当前不在标准 prod inventory 的 `services` 清单里;更新时构建并推送 `10.2.1.3:18082/hyapp/cron-service:<tag>`,通过 Tencent TAT 到 `new-app-1` 修改 docker env 的 `IMAGE` 后重启 `hyapp-cron-service`。
|
||||
7. 更新 `cron-service` 后必须验证镜像 tag、Docker health、systemd `active` 和 `13007` 监听。
|
||||
8. 腾讯云 `ap-singapore` 的实例名 `cron` 机器是 `ins-nt6bsay0` / `10.3.1.14`;当前没有 HyApp `hyapp-cron-service`,不要把它当成 HyApp `cron-service` 发布目标。
|
||||
1. `admin-server` 不在标准 prod inventory 的滚动服务清单里;它部署在 Saudi `admin-platform` 机器 `ins-p11begwe`,公网 `43.164.70.49`,内网 `10.2.1.2`。
|
||||
2. `admin-server` 的 systemd 是 `hyapp-admin-server`,容器是 `hyapp-admin-server`,配置是 `/etc/hyapp/admin-server/config.yaml`,Docker env 是 `/etc/hyapp/admin-server/docker.env`,migration 目录是 `/opt/hyapp/admin-server/migrations`,监听 `10.2.1.2:13100`。
|
||||
3. 更新 `admin-server` 必须只发布 `origin/main`:deploy 机从 Gitea 拉取 `git@gitea.haiyihy.com:hy/hyapp-server.git` 的 `origin/main`,构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`,再通过 Tencent TAT 到 `ins-p11begwe` 修改 `/etc/hyapp/admin-server/docker.env` 的 `IMAGE` 后重启 `hyapp-admin-server`。
|
||||
4. `admin-platform` 机器已经配置 Docker 直拉内网 Harbor:`/etc/docker/daemon.json` 包含 insecure registry `10.2.1.3:18082`,`/root/.docker/config.json` 包含 Harbor 登录凭据;如果 `docker pull 10.2.1.3:18082/...` 失败,优先检查这两处。
|
||||
5. 更新 `admin-server` 后必须验证:`systemctl is-active hyapp-admin-server`、容器镜像 tag/digest、`ss -lntp | grep 13100`、`curl http://10.2.1.2:13100/healthz`、`curl http://10.2.1.2:13100/readyz`、Caddy 容器 `yumi-admin-caddy` 运行、公网 `https://admin-acc.global-interaction.com/` 返回 `200`、未登录 `https://admin-acc.global-interaction.com/api/v1/auth/me` 返回 `401`。
|
||||
6. Saudi `admin-platform` 机器同时承接两个 5 秒轮询的前端 watcher:`chatapp3-admin-watch.service` 和 `hyapp-admin-platform-watch.service`。它们只在远端 commit 变化或静态目录缺失时构建,不应每 5 秒重复 build。
|
||||
7. `chatapp3-admin-watch.service` 使用 `/opt/chatapp3-admin/bin/watch-build.sh`,部署脚本是 `/opt/chatapp3-admin/bin/deploy-once.sh`,仓库是 `git@gitea.haiyihy.com:hy/chatapp3-admin.git` 的 `main`,构建后写入 `/opt/yumi-admin/frontend-admin/site/yumiadmin-acc`,公网入口是 `https://yumiadmin-acc.global-interaction.com`。前端 API 配置必须是 `https://yumiadmin-acc.global-interaction.com/console`,Caddy 的 `/console/*` 通过 Saudi 内网 CLB `https://10.2.1.12` 回源,并保持上游 Host/SNI 为 `jvapi.haiyihy.com`。
|
||||
8. `hyapp-admin-platform-watch.service` 使用 `/opt/hyapp-admin-platform/bin/watch-build.sh`,部署脚本是 `/opt/hyapp-admin-platform/bin/deploy-once.sh`,仓库是 `https://gitea.haiyihy.com/hy/hyapp-admin-platform.git` 的 `main`,构建后写入 `/opt/yumi-admin/frontend-admin/site/hyapp-admin-platform`,公网入口是 `https://admin-acc.global-interaction.com`。前端 API 配置必须保持同源 `/api`,Caddy 的 `/api/*` 回源到 `10.2.1.2:13100`。
|
||||
9. 更新或排查这两个 Saudi 前端 watcher 后必须验证:`systemctl is-active chatapp3-admin-watch hyapp-admin-platform-watch`、对应 `.last_built_commit` / `.deployed_commit`、`journalctl -u ...` 或 `/opt/*/logs/deploy.log`,以及公网首页 `200`、未登录 API `401`。
|
||||
10. HyApp `cron-service` 当前部署在 Saudi 主服务机器 `new-app-1`,实例 `ins-fi5zufpk`,内网 `10.2.1.4`。
|
||||
11. `cron-service` 的 systemd 是 `hyapp-cron-service`,容器是 `hyapp-cron-service`,配置是 `/etc/hyapp/cron-service/config.yaml`,Docker env 是 `/etc/hyapp/cron-service/docker.env`,监听 `13007`。
|
||||
12. `cron-service` 当前不在标准 prod inventory 的 `services` 清单里;更新时构建并推送 `10.2.1.3:18082/hyapp/cron-service:<tag>`,通过 Tencent TAT 到 `new-app-1` 修改 docker env 的 `IMAGE` 后重启 `hyapp-cron-service`。
|
||||
13. 更新 `cron-service` 后必须验证镜像 tag、Docker health、systemd `active` 和 `13007` 监听。
|
||||
14. 腾讯云 `ap-singapore` 的实例名 `cron` 机器是 `ins-nt6bsay0` / `10.3.1.14`;当前没有 HyApp `hyapp-cron-service`,不要把它当成 HyApp `cron-service` 发布目标。
|
||||
|
||||
## 测试 server / testbox
|
||||
|
||||
|
||||
71
README.md
71
README.md
@ -68,7 +68,7 @@ make up
|
||||
- API:`POST /deploy/api/edgeone/purge-url`
|
||||
- 类型:当前只开放 EdgeOne URL 刷新
|
||||
- 默认站点:`global-interaction.com` / `zone-3qwew52ihaj2`
|
||||
- 默认允许域名:`h5.global-interaction.com`
|
||||
- 默认允许域名:`h5.global-interaction.com`、`vivagames.global-interaction.com`、`asset.global-interaction.com`
|
||||
- 参数:`urls`、`confirmed=true`
|
||||
- 验证:接口等待 EdgeOne 任务结束后返回 `jobId`、`status`、`tasks`
|
||||
- 禁止:页面刷新任意未配置域名;需要新增域名时先改 `EDGEONE_ALLOWED_HOSTS`
|
||||
@ -79,21 +79,74 @@ make up
|
||||
|
||||
### admin-server
|
||||
|
||||
- 机器:公网 `43.164.70.49`,内网 `10.2.1.2`
|
||||
- 腾讯云实例:`ins-p11begwe`
|
||||
- 区域:`me-saudi-arabia`
|
||||
- 机器:Saudi `admin-platform`,CVM `ins-p11begwe`,公网 `43.164.70.49`,内网 `10.2.1.2`
|
||||
- systemd:`hyapp-admin-server`
|
||||
- 容器:`hyapp-admin-server`
|
||||
- 镜像:`10.2.1.3:18082/hyapp/admin-server:<tag>`
|
||||
- 配置:`/etc/hyapp/admin-server/config.yaml`
|
||||
- Docker env:`/etc/hyapp/admin-server/docker.env`
|
||||
- migrations:`/opt/hyapp/admin-server/migrations`
|
||||
- migration 目录:`/opt/hyapp/admin-server/migrations`
|
||||
- 镜像仓库:`10.2.1.3:18082/hyapp/admin-server:<tag>`
|
||||
- 监听:`10.2.1.2:13100`
|
||||
- 验证:`systemctl is-active hyapp-admin-server`、`docker inspect hyapp-admin-server --format '{{.Config.Image}}'`、`ss -lntp | grep 13100`、`curl -fsS http://10.2.1.2:13100/healthz`、`curl -fsS http://10.2.1.2:13100/readyz`
|
||||
- 验证:`systemctl is-active hyapp-admin-server`、`docker ps --filter name=hyapp-admin-server`、`ss -lntp | grep 13100`、`curl http://10.2.1.2:13100/healthz`、`curl http://10.2.1.2:13100/readyz`
|
||||
|
||||
`admin-server` 当前不是二进制直传部署,而是和其他 HyApp 后端一样通过内网 Harbor 镜像发布。发布时先在 deploy 机器 `43.164.75.199` 的 `/opt/deploy/sources/hyapp-server` 拉取 Gitea `git@gitea.haiyihy.com:hy/hyapp-server.git` 的 `origin/main`,构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`,再通过 Tencent TAT 到 `ins-p11begwe` 修改 `/etc/hyapp/admin-server/docker.env` 中的 `IMAGE` 并重启 `hyapp-admin-server`。线上只允许发布 `origin/main`;发布后必须确认容器镜像 tag、systemd `active`、端口监听、`healthz/readyz` 正常。
|
||||
`admin-server` 更新只允许发布 `origin/main`。deploy 机拉取 Gitea `git@gitea.haiyihy.com:hy/hyapp-server.git` 的 `origin/main`,构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`;然后通过 Tencent TAT 到 `ins-p11begwe` 修改 `/etc/hyapp/admin-server/docker.env` 的 `IMAGE`,执行 `systemctl restart hyapp-admin-server`。`admin-platform` 已配置 Docker 直拉内网 Harbor:`/etc/docker/daemon.json` 包含 insecure registry `10.2.1.3:18082`,`/root/.docker/config.json` 包含 Harbor 登录凭据。
|
||||
|
||||
注意:`deploy/tencent_tat/hyapp_admin_server_deploy.py` 是旧广州机器 `134.175.160.86 / 172.16.0.6` 的二进制发布链路,不适用于当前 Saudi `admin-server`。除非先更新脚本目标和部署模型,否则不要用它发布生产 `admin-server`。
|
||||
发布后必须确认:systemd `active`、容器镜像 tag/digest 正确、`10.2.1.2:13100` 监听、`healthz/readyz` 正常、Caddy 容器 `yumi-admin-caddy` 运行、`https://admin-acc.global-interaction.com/` 返回 `200`、未登录 `https://admin-acc.global-interaction.com/api/v1/auth/me` 返回 `401`。
|
||||
|
||||
### Saudi admin-platform 前端
|
||||
|
||||
- 机器:公网 `43.164.70.49`,内网 `10.2.1.2`
|
||||
- CVM:`ins-p11begwe`
|
||||
- 区域:`me-saudi-arabia`
|
||||
- Caddy 容器:`yumi-admin-caddy`
|
||||
- Caddy 宿主机目录:`/opt/yumi-admin/frontend-admin`
|
||||
- 静态根目录:`/opt/yumi-admin/frontend-admin/site`
|
||||
- Node 运行时:`/opt/node-v22.18.0-linux-x64`
|
||||
|
||||
这台机器承接两个加速后台前端,都是本机拉 Gitea、构建、替换 Caddy 静态目录:
|
||||
|
||||
| 入口 | watcher | 仓库 | 静态目录 | API 回源 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `https://yumiadmin-acc.global-interaction.com` | `chatapp3-admin-watch.service` | `git@gitea.haiyihy.com:hy/chatapp3-admin.git` `main` | `/opt/yumi-admin/frontend-admin/site/yumiadmin-acc` | `/console/*` -> Saudi 内网 CLB `https://10.2.1.12`,Host/SNI `jvapi.haiyihy.com` |
|
||||
| `https://admin-acc.global-interaction.com` | `hyapp-admin-platform-watch.service` | `https://gitea.haiyihy.com/hy/hyapp-admin-platform.git` `main` | `/opt/yumi-admin/frontend-admin/site/hyapp-admin-platform` | `/api/*` -> `http://10.2.1.2:13100` |
|
||||
|
||||
两个 watcher 都是 5 秒循环,入口脚本分别是:
|
||||
|
||||
```bash
|
||||
/opt/chatapp3-admin/bin/watch-build.sh
|
||||
/opt/hyapp-admin-platform/bin/watch-build.sh
|
||||
```
|
||||
|
||||
实际部署脚本分别是:
|
||||
|
||||
```bash
|
||||
/opt/chatapp3-admin/bin/deploy-once.sh
|
||||
/opt/hyapp-admin-platform/bin/deploy-once.sh
|
||||
```
|
||||
|
||||
部署完成标记:
|
||||
|
||||
```bash
|
||||
/opt/chatapp3-admin/.last_built_commit
|
||||
/opt/hyapp-admin-platform/.deployed_commit
|
||||
```
|
||||
|
||||
排查或变更后必须验证:
|
||||
|
||||
```bash
|
||||
systemctl is-active chatapp3-admin-watch.service hyapp-admin-platform-watch.service
|
||||
tail -n 100 /opt/chatapp3-admin/logs/deploy.log
|
||||
tail -n 100 /opt/hyapp-admin-platform/logs/deploy.log
|
||||
curl -I https://yumiadmin-acc.global-interaction.com/
|
||||
curl -I https://admin-acc.global-interaction.com/
|
||||
```
|
||||
|
||||
未登录 API 返回 `401` 是正常结果,用来证明反代已经打到后端鉴权层:
|
||||
|
||||
```bash
|
||||
curl -sS https://yumiadmin-acc.global-interaction.com/console/
|
||||
curl -sS https://admin-acc.global-interaction.com/api/v1/admin/apps
|
||||
```
|
||||
|
||||
### cron-service
|
||||
|
||||
|
||||
@ -42,14 +42,14 @@ npm run deploy:serve
|
||||
真实接口:
|
||||
|
||||
- `GET /deploy/api/health`:只返回凭据是否存在,不返回密钥明文。
|
||||
- `POST /deploy/api/edgeone/purge-url`:提交 EdgeOne URL 刷新任务,必须带 `confirmed=true`;只允许 `EDGEONE_ALLOWED_HOSTS` 中的域名,默认 `h5.global-interaction.com`。
|
||||
- `POST /deploy/api/edgeone/purge-url`:提交 EdgeOne URL 刷新任务,必须带 `confirmed=true`;只允许 `EDGEONE_ALLOWED_HOSTS` 中的域名,默认 `h5.global-interaction.com`、`vivagames.global-interaction.com`、`asset.global-interaction.com`。
|
||||
- `GET /deploy/api/hyapp/inventory`:读取 HyApp 生产 inventory。
|
||||
- `GET /deploy/api/hyapp/plan?services=gateway-service,room-service`:生成发布计划,不执行远端动作。
|
||||
- `GET /deploy/api/hyapp/discover?services=user-service&remote=1`:通过 Tencent TAT 连接 deploy 机器 `43.164.75.199`,再由 deploy 机器 SSH 到业务机器读取真实实例、systemd、Docker、镜像、资源、端口和 CLB 权重。
|
||||
- `GET /deploy/api/hyapp/discover?services=user-service&remote=1&includeConfig=1`:读取详情 YAML,密钥字段脱敏。
|
||||
- `GET /deploy/api/hyapp/resources?remote=1`:数据资源状态。链路:TAT -> deploy;业务服务器配置 SSH 失败后 TAT 兜底。
|
||||
- `POST /deploy/api/hyapp/deploy`:真实发布,必须带 `confirmed=true`;测试时使用 `dryRun=true`。
|
||||
- `POST /deploy/api/hyapp/admin-server/deploy`:历史二进制发布入口,目标是旧广州机器 `134.175.160.86 / 172.16.0.6`,不适用于当前生产 `admin-server`。当前生产 `admin-server` 在 `43.164.70.49 / 10.2.1.2`(实例 `ins-p11begwe`)以 Docker 方式运行,应构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`,再通过 TAT 更新 `/etc/hyapp/admin-server/docker.env` 的 `IMAGE` 并重启 `hyapp-admin-server`。
|
||||
- `POST /deploy/api/hyapp/admin-server/deploy`:生产 `admin-server` 固定发布入口,必须带 `confirmed=true`;发布只允许 `origin/main`,deploy 机构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`,再通过 Tencent TAT 到 Saudi `admin-platform` 实例 `ins-p11begwe` 更新 `/etc/hyapp/admin-server/docker.env` 的 `IMAGE` 并重启 `hyapp-admin-server`,最后验证 `10.2.1.2:13100` 的 `healthz/readyz`、Caddy 和公网入口。
|
||||
- `POST /deploy/api/hyapp/restart`:真实重启,必须带 `confirmed=true`;测试时使用 `dryRun=true`。
|
||||
- `GET /deploy/api/hyapp/testbox/status`:读取测试机 test 分支、timer 和 Compose/systemd 服务状态。
|
||||
- `POST /deploy/api/hyapp/testbox/service`:测试机服务 `update/start/stop/restart`,必须带 `confirmed=true`。
|
||||
|
||||
@ -12,6 +12,7 @@ GRANT ALL PRIVILEGES ON hyapp_admin.* TO 'hyapp'@'%';
|
||||
GRANT ALL PRIVILEGES ON hyapp_cron.* TO 'hyapp'@'%';
|
||||
GRANT ALL PRIVILEGES ON hyapp_game.* TO 'hyapp'@'%';
|
||||
GRANT ALL PRIVILEGES ON hyapp_notice.* TO 'hyapp'@'%';
|
||||
GRANT ALL PRIVILEGES ON hyapp_robot.* TO 'hyapp'@'%';
|
||||
GRANT ALL PRIVILEGES ON hyapp_statistics.* TO 'hyapp'@'%';
|
||||
|
||||
FLUSH PRIVILEGES;
|
||||
|
||||
@ -6,4 +6,7 @@ fileReservedTime = 48
|
||||
brokerRole = ASYNC_MASTER
|
||||
flushDiskType = ASYNC_FLUSH
|
||||
autoCreateTopicEnable = true
|
||||
# Docker Desktop 上宿主机二进制通过 NameServer 拿到 broker 地址后不能访问容器内网 IP;
|
||||
# 本地调试默认跑宿主机 Go 服务,所以广播 compose 映射到宿主机的 broker 端口。
|
||||
brokerIP1 = 127.0.0.1
|
||||
listenPort = 10911
|
||||
|
||||
@ -27,7 +27,8 @@ const tencentEnvFile = process.env.TENCENT_ENV_FILE || "";
|
||||
const credentialFile = resolve(process.env.TENCENT_CREDENTIALS_FILE || join(rootDir, ".env"));
|
||||
const deployEnv = { ...process.env };
|
||||
const edgeoneConfig = {
|
||||
allowedHosts: process.env.EDGEONE_ALLOWED_HOSTS || "h5.global-interaction.com",
|
||||
allowedHosts:
|
||||
process.env.EDGEONE_ALLOWED_HOSTS || "h5.global-interaction.com,vivagames.global-interaction.com,asset.global-interaction.com",
|
||||
zoneId: process.env.EDGEONE_ZONE_ID || "zone-3qwew52ihaj2",
|
||||
zoneName: process.env.EDGEONE_ZONE_NAME || "global-interaction.com",
|
||||
};
|
||||
|
||||
@ -3,7 +3,7 @@ CONTAINER_NAME=hyapp-deploy-platform
|
||||
STOP_TIMEOUT_SEC=15
|
||||
EDGEONE_ZONE_ID=zone-3qwew52ihaj2
|
||||
EDGEONE_ZONE_NAME=global-interaction.com
|
||||
EDGEONE_ALLOWED_HOSTS=h5.global-interaction.com
|
||||
EDGEONE_ALLOWED_HOSTS=h5.global-interaction.com,vivagames.global-interaction.com,asset.global-interaction.com
|
||||
DEPLOY_ADMIN_SERVER_COMMAND_TIMEOUT_MS=1800000
|
||||
|
||||
# Tencent Cloud credentials are required for remote TAT queries and EdgeOne refresh.
|
||||
|
||||
7
deploy/standalone/docker/luck-gateway.env.example
Normal file
7
deploy/standalone/docker/luck-gateway.env.example
Normal file
@ -0,0 +1,7 @@
|
||||
# luck-gateway is intentionally env-only: it exposes the simplified external lucky gift HTTP entry and delegates all rules to lucky-gift-service.
|
||||
IMAGE=10.2.1.3:18082/hyapp/luck-gateway:REPLACE_WITH_RELEASE_TAG
|
||||
CONTAINER_NAME=hyapp-luck-gateway
|
||||
STOP_TIMEOUT_SEC=60
|
||||
LUCK_GATEWAY_HTTP_ADDR=:13014
|
||||
LUCKY_GIFT_GRPC_ADDR=lucky-gift-service.internal:13013
|
||||
LUCK_GATEWAY_ALLOWED_APPS=aslan,yumi
|
||||
5
deploy/standalone/docker/lucky-gift-service.env.example
Normal file
5
deploy/standalone/docker/lucky-gift-service.env.example
Normal file
@ -0,0 +1,5 @@
|
||||
# Image is immutable per release; TAT deploy rewrites only IMAGE before restarting systemd.
|
||||
IMAGE=10.2.1.3:18082/hyapp/lucky-gift-service:REPLACE_WITH_RELEASE_TAG
|
||||
CONTAINER_NAME=hyapp-lucky-gift-service
|
||||
CONFIG_PATH=/etc/hyapp/lucky-gift-service/config.yaml
|
||||
STOP_TIMEOUT_SEC=90
|
||||
4
deploy/standalone/docker/robot-service.env.example
Normal file
4
deploy/standalone/docker/robot-service.env.example
Normal file
@ -0,0 +1,4 @@
|
||||
IMAGE=10.2.1.3:18082/hyapp/robot-service:REPLACE_WITH_RELEASE_TAG
|
||||
CONTAINER_NAME=hyapp-robot-service
|
||||
CONFIG_PATH=/etc/hyapp/robot-service/config.yaml
|
||||
STOP_TIMEOUT_SEC=60
|
||||
23
deploy/standalone/systemd/hyapp-luck-gateway.service
Normal file
23
deploy/standalone/systemd/hyapp-luck-gateway.service
Normal file
@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Hyapp luck-gateway container
|
||||
Requires=docker.service
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
StartLimitIntervalSec=120
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/hyapp/luck-gateway/docker.env
|
||||
ExecStartPre=-/usr/bin/env docker rm -f ${CONTAINER_NAME}
|
||||
ExecStart=/usr/bin/env docker run --name=${CONTAINER_NAME} --rm --network=host --init --pull=never --stop-signal=SIGTERM --stop-timeout=${STOP_TIMEOUT_SEC} --env-file=/etc/hyapp/luck-gateway/docker.env --env=TZ=UTC --log-driver=json-file --log-opt=max-size=100m --log-opt=max-file=5 --health-cmd="wget -q -O - http://127.0.0.1:13014/healthz/ready >/dev/null" --health-interval=5s --health-timeout=3s --health-retries=6 --health-start-period=10s ${IMAGE}
|
||||
ExecStop=/usr/bin/env docker stop --time=${STOP_TIMEOUT_SEC} ${CONTAINER_NAME}
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
TimeoutStartSec=60
|
||||
TimeoutStopSec=90
|
||||
KillMode=none
|
||||
LimitNOFILE=1048576
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
23
deploy/standalone/systemd/hyapp-lucky-gift-service.service
Normal file
23
deploy/standalone/systemd/hyapp-lucky-gift-service.service
Normal file
@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Hyapp lucky-gift-service container
|
||||
Requires=docker.service
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
StartLimitIntervalSec=120
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/hyapp/lucky-gift-service/docker.env
|
||||
ExecStartPre=-/usr/bin/env docker rm -f ${CONTAINER_NAME}
|
||||
ExecStart=/usr/bin/env docker run --name=${CONTAINER_NAME} --rm --network=host --init --pull=never --stop-signal=SIGTERM --stop-timeout=${STOP_TIMEOUT_SEC} --env=TZ=UTC --log-driver=json-file --log-opt=max-size=100m --log-opt=max-file=5 --mount=type=bind,src=${CONFIG_PATH},dst=/app/config.yaml,readonly --health-cmd="/app/grpc-health-probe -addr=127.0.0.1:13013 -service=lucky-gift-service" --health-interval=5s --health-timeout=3s --health-retries=6 --health-start-period=10s ${IMAGE}
|
||||
ExecStop=/usr/bin/env docker stop --time=${STOP_TIMEOUT_SEC} ${CONTAINER_NAME}
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
TimeoutStartSec=60
|
||||
TimeoutStopSec=120
|
||||
KillMode=none
|
||||
LimitNOFILE=1048576
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
23
deploy/standalone/systemd/hyapp-robot-service.service
Normal file
23
deploy/standalone/systemd/hyapp-robot-service.service
Normal file
@ -0,0 +1,23 @@
|
||||
[Unit]
|
||||
Description=Hyapp robot-service container
|
||||
Requires=docker.service
|
||||
After=network-online.target docker.service
|
||||
Wants=network-online.target
|
||||
StartLimitIntervalSec=120
|
||||
StartLimitBurst=3
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
EnvironmentFile=/etc/hyapp/robot-service/docker.env
|
||||
ExecStartPre=-/usr/bin/env docker rm -f ${CONTAINER_NAME}
|
||||
ExecStart=/usr/bin/env docker run --name=${CONTAINER_NAME} --rm --network=host --init --pull=never --stop-signal=SIGTERM --stop-timeout=${STOP_TIMEOUT_SEC} --env=TZ=UTC --log-driver=json-file --log-opt=max-size=100m --log-opt=max-file=5 --mount=type=bind,src=${CONFIG_PATH},dst=/app/config.yaml,readonly --health-cmd="wget -q -O - http://127.0.0.1:13111/healthz/ready >/dev/null" --health-interval=5s --health-timeout=3s --health-retries=6 --health-start-period=10s ${IMAGE}
|
||||
ExecStop=/usr/bin/env docker stop --time=${STOP_TIMEOUT_SEC} ${CONTAINER_NAME}
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
TimeoutStartSec=60
|
||||
TimeoutStopSec=90
|
||||
KillMode=none
|
||||
LimitNOFILE=1048576
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -148,18 +148,17 @@ python3 deploy/tencent_tat/hyapp_data_resources.py resources \
|
||||
--inventory deploy/tencent_tat/hyapp-services.inventory.prod.json
|
||||
```
|
||||
|
||||
生产 `admin-server` 当前运行在 Saudi 机器 `43.164.70.49 / 10.2.1.2`(实例 `ins-p11begwe`),以 Docker 容器 `hyapp-admin-server` 运行:
|
||||
生产 `admin-server` 固定从 Gitea `origin/main` 发布,当前运行在 Saudi `admin-platform` 机器 `ins-p11begwe` / `10.2.1.2`,不是广州独立机。发布链路是 deploy 机本机构建镜像并推送 Harbor,然后用 Tencent TAT 到 `ins-p11begwe` 更新 Docker env:
|
||||
|
||||
- systemd:`hyapp-admin-server`
|
||||
- 镜像:`10.2.1.3:18082/hyapp/admin-server:<tag>`
|
||||
- Docker env:`/etc/hyapp/admin-server/docker.env`
|
||||
- 配置:`/etc/hyapp/admin-server/config.yaml`
|
||||
- migrations:`/opt/hyapp/admin-server/migrations`
|
||||
- 监听:`10.2.1.2:13100`
|
||||
```bash
|
||||
docker build -f server/admin/Dockerfile \
|
||||
-t 10.2.1.3:18082/hyapp/admin-server:<tag> .
|
||||
docker push 10.2.1.3:18082/hyapp/admin-server:<tag>
|
||||
```
|
||||
|
||||
发布时先在 deploy 机器 `/opt/deploy/sources/hyapp-server` 拉取 `git@gitea.haiyihy.com:hy/hyapp-server.git` 的 `origin/main`,构建并推送 `10.2.1.3:18082/hyapp/admin-server:<tag>`,再通过 TAT 到 `ins-p11begwe` 修改 `/etc/hyapp/admin-server/docker.env` 中的 `IMAGE` 并重启 `hyapp-admin-server`。生产不允许切换到其他分支;发布后必须验证 `systemctl is-active hyapp-admin-server`、容器镜像 tag、`10.2.1.2:13100` 监听、`/healthz` 和 `/readyz`。
|
||||
`admin-platform` 机器已配置 Docker 直拉内网 Harbor:`/etc/docker/daemon.json` 包含 insecure registry `10.2.1.3:18082`,`/root/.docker/config.json` 包含 Harbor 登录凭据。TAT 到 `ins-p11begwe` 后只更新 `/etc/hyapp/admin-server/docker.env` 的 `IMAGE`,再执行 `systemctl restart hyapp-admin-server`。
|
||||
|
||||
注意:`hyapp_admin_server_deploy.py` 是旧广州机器 `134.175.160.86 / 172.16.0.6` 的二进制发布脚本,不适用于当前生产 `admin-server`。除非先更新脚本目标和部署模型,否则不要用它发布生产 `admin-server`。
|
||||
发布后必须验证 `systemctl is-active hyapp-admin-server`、容器镜像 tag/digest、`10.2.1.2:13100` 的 `/healthz` 和 `/readyz`、`yumi-admin-caddy` 容器运行、公网 `https://admin-acc.global-interaction.com/` 返回 `200`、未登录 `https://admin-acc.global-interaction.com/api/v1/auth/me` 返回 `401`。生产不允许切换到其他分支。
|
||||
|
||||
规则:
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ from urllib.parse import urlparse, urlunparse
|
||||
|
||||
DEFAULT_EDGEONE_ZONE_ID = "zone-3qwew52ihaj2"
|
||||
DEFAULT_EDGEONE_ZONE_NAME = "global-interaction.com"
|
||||
DEFAULT_EDGEONE_ALLOWED_HOSTS = "h5.global-interaction.com"
|
||||
DEFAULT_EDGEONE_ALLOWED_HOSTS = "h5.global-interaction.com,vivagames.global-interaction.com,asset.global-interaction.com"
|
||||
TERMINAL_STATUSES = {"success", "failed", "timeout", "canceled"}
|
||||
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@
|
||||
"wallet-service",
|
||||
"user-service",
|
||||
"activity-service",
|
||||
"lucky-gift-service",
|
||||
"cron-service",
|
||||
"game-service",
|
||||
"notice-service",
|
||||
@ -38,6 +39,7 @@
|
||||
"owner": "后端平台",
|
||||
"related_services": [
|
||||
"gateway-service",
|
||||
"luck-gateway",
|
||||
"room-service",
|
||||
"user-service"
|
||||
]
|
||||
@ -200,6 +202,37 @@
|
||||
"drain_seconds": 5
|
||||
}
|
||||
},
|
||||
"lucky-gift-service": {
|
||||
"unit": "hyapp-lucky-gift-service",
|
||||
"container": "hyapp-lucky-gift-service",
|
||||
"env_file": "/etc/hyapp/lucky-gift-service/docker.env",
|
||||
"image_template": "${REGISTRY}/lucky-gift-service:${TAG}",
|
||||
"target_port": 13013,
|
||||
"hosts": [
|
||||
"new-app-activity-1",
|
||||
"new-app-activity-2"
|
||||
],
|
||||
"clb": {
|
||||
"enabled": false,
|
||||
"drain_seconds": 0
|
||||
}
|
||||
},
|
||||
"luck-gateway": {
|
||||
"unit": "hyapp-luck-gateway",
|
||||
"container": "hyapp-luck-gateway",
|
||||
"env_file": "/etc/hyapp/luck-gateway/docker.env",
|
||||
"config_required": false,
|
||||
"image_template": "${REGISTRY}/luck-gateway:${TAG}",
|
||||
"target_port": 13014,
|
||||
"hosts": [
|
||||
"gateway-1",
|
||||
"gateway-2"
|
||||
],
|
||||
"clb": {
|
||||
"enabled": false,
|
||||
"drain_seconds": 0
|
||||
}
|
||||
},
|
||||
"notice-service": {
|
||||
"unit": "hyapp-notice-service",
|
||||
"container": "hyapp-notice-service",
|
||||
@ -238,6 +271,26 @@
|
||||
"drain_seconds": 5
|
||||
}
|
||||
},
|
||||
"robot-service": {
|
||||
"unit": "hyapp-robot-service",
|
||||
"container": "hyapp-robot-service",
|
||||
"env_file": "/etc/hyapp/robot-service/docker.env",
|
||||
"config_path": "/etc/hyapp/robot-service/config.yaml",
|
||||
"image_template": "${REGISTRY}/robot-service:${TAG}",
|
||||
"target_port": 13011,
|
||||
"hosts": [
|
||||
"new-app-1",
|
||||
"new-app-2"
|
||||
],
|
||||
"clb": {
|
||||
"enabled": true,
|
||||
"load_balancer_id": "lb-epvnr4o0",
|
||||
"listener_ids": [
|
||||
"lbl-pd35q9go"
|
||||
],
|
||||
"drain_seconds": 5
|
||||
}
|
||||
},
|
||||
"statistics-service": {
|
||||
"unit": "hyapp-statistics-service",
|
||||
"container": "hyapp-statistics-service",
|
||||
|
||||
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import shlex
|
||||
import sys
|
||||
from pathlib import Path
|
||||
@ -15,33 +16,15 @@ from deploy.tencent_tat.hyapp_tat_deploy import build_tat_client, load_env_file,
|
||||
DEFAULT_REPO_URL = "git@gitea.haiyihy.com:hy/hyapp-server.git"
|
||||
DEFAULT_SOURCE_DIR = "/opt/deploy/sources/hyapp-server"
|
||||
DEFAULT_BRANCH = "main"
|
||||
DEFAULT_ADMIN_REGION = "ap-guangzhou"
|
||||
DEFAULT_ADMIN_INSTANCE_ID = "ins-0x5mjwmc"
|
||||
DEFAULT_ADMIN_HOST = "134.175.160.86"
|
||||
DEFAULT_ADMIN_BIND_ADDR = "172.16.0.6"
|
||||
DEFAULT_ADMIN_PORT = 13100
|
||||
|
||||
|
||||
def shell_join(items: list[str]) -> str:
|
||||
return " ".join(shlex.quote(item) for item in items)
|
||||
|
||||
|
||||
def admin_endpoint(host: str, user: str) -> str:
|
||||
return f"{user}@{host}" if user else host
|
||||
|
||||
|
||||
def build_remote_script(args: argparse.Namespace) -> str:
|
||||
endpoint = admin_endpoint(args.admin_host, args.admin_user)
|
||||
dry_run = "1" if args.dry_run else "0"
|
||||
ssh_option_args = [
|
||||
"-o",
|
||||
"BatchMode=yes",
|
||||
"-o",
|
||||
"StrictHostKeyChecking=accept-new",
|
||||
"-o",
|
||||
f"ConnectTimeout={args.ssh_connect_timeout}",
|
||||
]
|
||||
ssh_opts = ["ssh", *ssh_option_args]
|
||||
scp_cmd = shell_join(["timeout", str(args.transfer_timeout_seconds), "scp", *ssh_option_args])
|
||||
admin_ssh = shell_join([*ssh_opts, endpoint])
|
||||
|
||||
return f"""#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
@ -50,35 +33,45 @@ REPO_URL={shlex.quote(args.repo_url)}
|
||||
SOURCE_DIR={shlex.quote(args.source_dir)}
|
||||
BRANCH={shlex.quote(args.branch)}
|
||||
DRY_RUN={dry_run}
|
||||
ADMIN_ENDPOINT={shlex.quote(endpoint)}
|
||||
ADMIN_BIND_ADDR={shlex.quote(args.admin_bind_addr)}
|
||||
ADMIN_PORT={shlex.quote(str(args.admin_port))}
|
||||
ADMIN_SSH={shlex.quote(admin_ssh)}
|
||||
|
||||
export GIT_SSH_COMMAND="ssh -o BatchMode=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=15"
|
||||
export GOPROXY="${{GOPROXY:-https://goproxy.cn|https://proxy.golang.org|direct}}"
|
||||
export GOSUMDB="${{GOSUMDB:-sum.golang.org}}"
|
||||
|
||||
echo "admin_host=$(hostname)"
|
||||
echo "repo=$REPO_URL"
|
||||
echo "source_dir=$SOURCE_DIR"
|
||||
echo "branch=$BRANCH"
|
||||
echo "admin_endpoint=$ADMIN_ENDPOINT"
|
||||
|
||||
if [ "$DRY_RUN" = "1" ]; then
|
||||
echo "git=$(git --version 2>/dev/null || true)"
|
||||
echo "go=$(go version 2>/dev/null || true)"
|
||||
target_commit="$(git ls-remote "$REPO_URL" "refs/heads/$BRANCH" | awk '{{print $1}}')"
|
||||
if [ -z "$target_commit" ]; then
|
||||
echo "cannot resolve origin/$BRANCH" >&2
|
||||
exit 12
|
||||
fi
|
||||
echo "target_commit=$target_commit"
|
||||
$ADMIN_SSH "ADMIN_BIND_ADDR='$ADMIN_BIND_ADDR' ADMIN_PORT='$ADMIN_PORT' bash -s" <<'REMOTE'
|
||||
set -e
|
||||
echo "admin_active=$(systemctl is-active hyapp-admin-server || true)"
|
||||
ss -lntp | grep "$ADMIN_PORT" || true
|
||||
curl -fsS -m 3 "http://$ADMIN_BIND_ADDR:$ADMIN_PORT/healthz" || true
|
||||
echo
|
||||
REMOTE
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ! command -v git >/dev/null 2>&1 || ! command -v go >/dev/null 2>&1; then
|
||||
if command -v dnf >/dev/null 2>&1; then
|
||||
dnf install -y git golang
|
||||
elif command -v yum >/dev/null 2>&1; then
|
||||
yum install -y git golang
|
||||
else
|
||||
echo "git/go missing and no supported package manager found" >&2
|
||||
exit 13
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ -d "$SOURCE_DIR/.git" ]; then
|
||||
cd "$SOURCE_DIR"
|
||||
git remote set-url origin "$REPO_URL"
|
||||
@ -95,42 +88,25 @@ git clean -fd
|
||||
|
||||
commit="$(git rev-parse HEAD)"
|
||||
short_commit="$(git rev-parse --short HEAD)"
|
||||
build_id="$(date +%Y%m%d%H%M%S)-$short_commit"
|
||||
build_image="hyapp/admin-server-build:$build_id"
|
||||
local_binary="/tmp/admin-server-$build_id"
|
||||
remote_binary="/tmp/admin-server-$build_id"
|
||||
build_binary="/tmp/admin-server-$short_commit"
|
||||
|
||||
echo "commit=$commit"
|
||||
echo "build_id=$build_id"
|
||||
echo "go=$(go version)"
|
||||
|
||||
docker build -t "$build_image" -f server/admin/Dockerfile .
|
||||
container_id="$(docker create "$build_image")"
|
||||
trap 'docker rm -f "$container_id" >/dev/null 2>&1 || true' EXIT
|
||||
docker cp "$container_id:/app/server" "$local_binary"
|
||||
docker rm "$container_id" >/dev/null
|
||||
trap - EXIT
|
||||
chmod 0755 "$local_binary"
|
||||
binary_sha="$(sha256sum "$local_binary" | awk '{{print $1}}')"
|
||||
binary_size="$(stat -c %s "$local_binary")"
|
||||
cd "$SOURCE_DIR/server/admin"
|
||||
GOWORK=off go mod download
|
||||
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o "$build_binary" ./cmd/server
|
||||
chmod 0755 "$build_binary"
|
||||
binary_sha="$(sha256sum "$build_binary" | awk '{{print $1}}')"
|
||||
binary_size="$(stat -c %s "$build_binary")"
|
||||
echo "binary_sha=$binary_sha"
|
||||
echo "binary_size=$binary_size"
|
||||
|
||||
{scp_cmd} "$local_binary" "$ADMIN_ENDPOINT:$remote_binary"
|
||||
|
||||
$ADMIN_SSH "REMOTE_BINARY='$remote_binary' EXPECTED_SHA='$binary_sha' ADMIN_BIND_ADDR='$ADMIN_BIND_ADDR' ADMIN_PORT='$ADMIN_PORT' COMMIT='$commit' bash -s" <<'REMOTE'
|
||||
set -euo pipefail
|
||||
|
||||
BIN=/opt/hyapp/admin-server/admin-server
|
||||
BACKUP="$BIN.bak.$(date +%Y%m%d%H%M%S)"
|
||||
|
||||
actual_sha="$(sha256sum "$REMOTE_BINARY" | awk '{{print $1}}')"
|
||||
if [ "$actual_sha" != "$EXPECTED_SHA" ]; then
|
||||
echo "uploaded binary sha mismatch: $actual_sha != $EXPECTED_SHA" >&2
|
||||
exit 21
|
||||
fi
|
||||
|
||||
cp "$BIN" "$BACKUP"
|
||||
install -o root -g root -m 0755 "$REMOTE_BINARY" "$BIN.new"
|
||||
install -o root -g root -m 0755 "$build_binary" "$BIN.new"
|
||||
mv "$BIN.new" "$BIN"
|
||||
systemctl restart hyapp-admin-server
|
||||
|
||||
@ -160,17 +136,41 @@ echo "installed_sha=$(sha256sum "$BIN" | awk '{{print $1}}')"
|
||||
echo "listener=$(ss -lntp | grep "$ADMIN_BIND_ADDR:$ADMIN_PORT" || true)"
|
||||
echo "healthz=$(cat /tmp/hyapp-admin-healthz.out)"
|
||||
echo "readyz=$(cat /tmp/hyapp-admin-readyz.out)"
|
||||
REMOTE
|
||||
"""
|
||||
|
||||
|
||||
def run_deploy(args: argparse.Namespace) -> dict[str, Any]:
|
||||
inventory = load_inventory(args.inventory)
|
||||
client = build_tat_client(inventory)
|
||||
admin_inventory = {
|
||||
"region": args.admin_region,
|
||||
"deploy_server": {"instance_id": args.admin_instance_id},
|
||||
"hosts": {"admin-server": {"instance_id": args.admin_instance_id, "private_ip": args.admin_bind_addr}},
|
||||
"services": {
|
||||
"admin-server": {
|
||||
"unit": "hyapp-admin-server",
|
||||
"container": "hyapp-admin-server",
|
||||
"env_file": "/etc/hyapp/admin-server/config.yaml",
|
||||
"target_port": args.admin_port,
|
||||
"hosts": ["admin-server"],
|
||||
}
|
||||
},
|
||||
}
|
||||
previous_region = None
|
||||
region_was_set = "TENCENTCLOUD_REGION" in os.environ
|
||||
if region_was_set:
|
||||
previous_region = os.environ["TENCENTCLOUD_REGION"]
|
||||
os.environ["TENCENTCLOUD_REGION"] = args.admin_region
|
||||
try:
|
||||
client = build_tat_client(admin_inventory)
|
||||
finally:
|
||||
if region_was_set and previous_region is not None:
|
||||
os.environ["TENCENTCLOUD_REGION"] = previous_region
|
||||
elif not region_was_set:
|
||||
os.environ.pop("TENCENTCLOUD_REGION", None)
|
||||
script = build_remote_script(args)
|
||||
result = run_tat_shell(
|
||||
client,
|
||||
instance_id=inventory["deploy_server"]["instance_id"],
|
||||
instance_id=args.admin_instance_id,
|
||||
script=script,
|
||||
command_name="hyapp-admin-server-deploy",
|
||||
timeout_seconds=args.timeout_seconds,
|
||||
@ -179,29 +179,30 @@ def run_deploy(args: argparse.Namespace) -> dict[str, Any]:
|
||||
output = str(result.get("output") or "")
|
||||
return {
|
||||
"adminHost": args.admin_host,
|
||||
"adminInstanceId": args.admin_instance_id,
|
||||
"adminRegion": args.admin_region,
|
||||
"dryRun": args.dry_run,
|
||||
"ok": result.get("status") == "SUCCESS",
|
||||
"output": output[-12000:],
|
||||
"sourceDir": args.source_dir,
|
||||
"status": result.get("status"),
|
||||
"target": inventory.get("deploy_server") or {},
|
||||
"target": admin_inventory.get("deploy_server") or {},
|
||||
}
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(description="Deploy production admin-server from Gitea origin/main through the deploy host.")
|
||||
parser = argparse.ArgumentParser(description="Deploy production admin-server by pulling Gitea origin/main on the Guangzhou admin host.")
|
||||
parser.add_argument("action", choices=["deploy"])
|
||||
parser.add_argument("--env-file", default="")
|
||||
parser.add_argument("--inventory", default="deploy/tencent_tat/hyapp-services.inventory.prod.example.json")
|
||||
parser.add_argument("--repo-url", default=DEFAULT_REPO_URL)
|
||||
parser.add_argument("--source-dir", default=DEFAULT_SOURCE_DIR)
|
||||
parser.add_argument("--branch", default=DEFAULT_BRANCH)
|
||||
parser.add_argument("--admin-region", default=DEFAULT_ADMIN_REGION)
|
||||
parser.add_argument("--admin-instance-id", default=DEFAULT_ADMIN_INSTANCE_ID)
|
||||
parser.add_argument("--admin-host", default=DEFAULT_ADMIN_HOST)
|
||||
parser.add_argument("--admin-user", default="")
|
||||
parser.add_argument("--admin-bind-addr", default=DEFAULT_ADMIN_BIND_ADDR)
|
||||
parser.add_argument("--admin-port", type=int, default=DEFAULT_ADMIN_PORT)
|
||||
parser.add_argument("--ssh-connect-timeout", type=int, default=15)
|
||||
parser.add_argument("--transfer-timeout-seconds", type=int, default=300)
|
||||
parser.add_argument("--timeout-seconds", type=int, default=1800)
|
||||
parser.add_argument("--dry-run", action="store_true")
|
||||
parser.add_argument("--yes", action="store_true")
|
||||
|
||||
@ -15,21 +15,26 @@ class AdminServerDeployScriptTests(unittest.TestCase):
|
||||
args = argparse.Namespace(
|
||||
admin_bind_addr="172.16.0.6",
|
||||
admin_host="134.175.160.86",
|
||||
admin_instance_id="ins-0x5mjwmc",
|
||||
admin_port=13100,
|
||||
admin_user="",
|
||||
admin_region="ap-guangzhou",
|
||||
branch="main",
|
||||
dry_run=False,
|
||||
repo_url="git@gitea.haiyihy.com:hy/hyapp-server.git",
|
||||
source_dir="/opt/deploy/sources/hyapp-server",
|
||||
ssh_connect_timeout=15,
|
||||
transfer_timeout_seconds=300,
|
||||
)
|
||||
script = admin_deploy.build_remote_script(args)
|
||||
|
||||
self.assertIn("git fetch --prune origin \"$BRANCH\"", script)
|
||||
self.assertIn("git checkout -B \"$BRANCH\" \"origin/$BRANCH\"", script)
|
||||
self.assertIn("docker build -t \"$build_image\" -f server/admin/Dockerfile .", script)
|
||||
self.assertIn("timeout 300 scp", script)
|
||||
self.assertIn("git clone \"$REPO_URL\" \"$SOURCE_DIR\"", script)
|
||||
self.assertIn("GOWORK=off go mod download", script)
|
||||
self.assertIn("GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o \"$build_binary\" ./cmd/server", script)
|
||||
self.assertNotIn("docker build", script)
|
||||
self.assertNotIn("docker push", script)
|
||||
self.assertNotIn("docker pull", script)
|
||||
self.assertNotIn("10.2.1.3:18082", script)
|
||||
self.assertNotIn("timeout 300 scp", script)
|
||||
self.assertNotIn("rsync -az --partial", script)
|
||||
self.assertIn("systemctl restart hyapp-admin-server", script)
|
||||
self.assertIn("http://$ADMIN_BIND_ADDR:$ADMIN_PORT/healthz", script)
|
||||
|
||||
@ -72,7 +72,15 @@ def selected_hosts(service: dict[str, Any], raw_hosts: str) -> list[str]:
|
||||
return requested
|
||||
|
||||
|
||||
def validate_service_templates(hyapp_root: Path, service_name: str) -> list[str]:
|
||||
def service_config_required(service: dict[str, Any]) -> bool:
|
||||
# 少数边缘入口是 env-only 进程,例如 luck-gateway 只承载 HTTP 转发边界;
|
||||
# inventory 显式标记后跳过 YAML contract 校验,避免为了校验脚本伪造无效 config。
|
||||
return bool(service.get("config_required", True))
|
||||
|
||||
|
||||
def validate_service_templates(hyapp_root: Path, service_name: str, service: dict[str, Any]) -> list[str]:
|
||||
if not service_config_required(service):
|
||||
return []
|
||||
errors: list[str] = []
|
||||
config_dir = hyapp_root / "services" / service_name / "configs"
|
||||
configs = {name: load_yaml(config_dir / name) for name in CONFIG_FILENAMES}
|
||||
@ -87,7 +95,9 @@ def validate_service_templates(hyapp_root: Path, service_name: str) -> list[str]
|
||||
return errors
|
||||
|
||||
|
||||
def validate_rendered_config(hyapp_root: Path, service_name: str, host_name: str, rendered_dir: Path) -> list[str]:
|
||||
def validate_rendered_config(hyapp_root: Path, service_name: str, service: dict[str, Any], host_name: str, rendered_dir: Path) -> list[str]:
|
||||
if not service_config_required(service):
|
||||
return []
|
||||
contract = load_yaml(hyapp_root / "services" / service_name / "configs" / "config.tencent.example.yaml")
|
||||
rendered_path = rendered_dir / host_name / service_name / "config.yaml"
|
||||
rendered = load_yaml(rendered_path)
|
||||
@ -117,11 +127,12 @@ def main(argv: list[str]) -> int:
|
||||
rendered_dir = Path(args.rendered_dir).expanduser().resolve() if args.rendered_dir else None
|
||||
errors: list[str] = []
|
||||
for service_name in selected_service_names(inventory, args.services):
|
||||
errors.extend(validate_service_templates(hyapp_root, service_name))
|
||||
service = inventory["services"][service_name]
|
||||
errors.extend(validate_service_templates(hyapp_root, service_name, service))
|
||||
if rendered_dir is None:
|
||||
continue
|
||||
for host_name in selected_hosts(inventory["services"][service_name], args.hosts):
|
||||
errors.extend(validate_rendered_config(hyapp_root, service_name, host_name, rendered_dir))
|
||||
for host_name in selected_hosts(service, args.hosts):
|
||||
errors.extend(validate_rendered_config(hyapp_root, service_name, service, host_name, rendered_dir))
|
||||
if errors:
|
||||
print(json.dumps({"ok": False, "errors": errors}, ensure_ascii=False, indent=2), file=sys.stderr)
|
||||
return 1
|
||||
|
||||
@ -7,7 +7,7 @@ import { Button } from "../../shared/ui/Button";
|
||||
import { StatusBadge, type StatusBadgeStatus } from "../../shared/ui/StatusBadge";
|
||||
import styles from "./CdnRefreshPage.module.css";
|
||||
|
||||
const defaultUrlText = "https://h5.global-interaction.com/";
|
||||
const defaultUrlText = "https://vivagames.global-interaction.com/";
|
||||
|
||||
function parseUrls(text: string) {
|
||||
return Array.from(
|
||||
@ -148,7 +148,7 @@ export function CdnRefreshPage() {
|
||||
<CloudLightning size={18} />
|
||||
<div>
|
||||
<strong>EdgeOne</strong>
|
||||
<span>h5.global-interaction.com</span>
|
||||
<span>h5.global-interaction.com, vivagames.global-interaction.com, asset.global-interaction.com</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user