From 223f7d0a44920064c6784733942cc612889ef0a7 Mon Sep 17 00:00:00 2001 From: Rodger-Wang <1367893453@qq.com> Date: Sun, 13 Sep 2026 00:26:43 +0800 Subject: [PATCH] =?UTF-8?q?deploy:=20=E7=A7=BB=E9=99=A4=E6=9C=AC=E6=9C=BA?= =?UTF-8?q?=E8=BF=9E=E4=B8=8D=E4=B8=8A=E7=9A=84=206=20=E5=8F=B0=E6=9C=8D?= =?UTF-8?q?=E5=8A=A1=E5=99=A8=EF=BC=8C=E9=A1=BA=E5=B8=A6=E6=B8=85=E6=8E=89?= =?UTF-8?q?=E6=B5=8B=E8=AF=95=E9=87=8C=E5=86=99=E6=AD=BB=E7=9A=84=E4=B8=8B?= =?UTF-8?q?=E7=BA=BF=E6=9C=BA=E5=99=A8=E5=87=AD=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 云雁(yunyan)/灵谱(lingpu) 的部署目标从所有脚本移除,ENVS / PROD_ENVS / REGIONS 现在都只剩 along。那 6 台(云雁测试/上海/日本/新加坡、灵谱测试/正式)的 SSH 私钥路径 指向的是另一台开发机,本机一台都登不上(22 端口通、无可用密钥),留在交互菜单里只会误选。 - 删 deploy/{console,admin,app}/dev-deploy.sh 的 lingpu、yunyan 两段 env_profile - 删 deploy/{console,admin}/prod-deploy.sh 的 yunyan、lingpu 两段 - 删 deploy/app/prod-deploy.sh 的 shanghai/japan/singapore 三段 region_profile - 删 deploy/admin/deploy.sh:早期脚本,只指向灵谱且生产位留空,已被 dev-deploy/prod-deploy 取代(CLAUDE.md 里"要同步两份 deploy.sh"也是错的, console 那份早就不存在) - IP 与私钥路径不再记在文档里,需要时从 git 历史取回 镜像仓库刻意保留:registry.voitrans.net / registry.lingpu.net 都在,prod-build.sh 仍可选 yunyan|lingpu 推镜像(三家仓库本机都能读写,协作者仍从他那台机部署这两家)。 顺带修掉三处把已下线机器地址连明文数据库密码一起写死的测试: - sys/nats/nats_test.go 有个真 bug——`url := "nats://<写死地址>"` 紧接着 `if url == ""`, 常量永远不为空,所谓"默认跳过"从来没生效:每次 go test 都在连那台早已废弃的机器, 白等 4.5 秒超时。现在真正读 NATS_URL 了。 - modules/{api,echomeet}/model_test.go 的 DSN 改走 API_TEST_DSN / ECHOMEET_TEST_DSN 另外给 app/prod-deploy.sh 加了一条明确报错:输入已移除的区域名(如 shanghai)原本会被 is_tag_like 当成版本号,报出"版本指定了两次"这种驴唇不对马嘴的错。 Co-Authored-By: Claude Opus 5 (1M context) --- apps/services/modules/api/model_test.go | 17 +- apps/services/modules/echomeet/model_test.go | 20 +- apps/services/sys/nats/nats_test.go | 9 +- deploy/README.md | 88 ++------- deploy/admin/README.md | 13 +- deploy/admin/deploy.sh | 184 ------------------ deploy/admin/dev-deploy.sh | 27 +-- deploy/admin/prod-deploy.sh | 30 +-- deploy/app/README.md | 16 +- deploy/app/dev-deploy.sh | 27 +-- deploy/app/prod-build.sh | 4 +- deploy/app/prod-deploy.sh | 46 ++--- deploy/console/README.md | 10 +- deploy/console/dev-deploy.sh | 27 +-- deploy/console/prod-deploy.sh | 30 +-- deploy/dev-deploy-all.sh | 9 +- deploy/registry-profiles.sh | 5 +- ...¿�维-容器断网与免费证书排查.md | 2 +- 18 files changed, 138 insertions(+), 426 deletions(-) delete mode 100755 deploy/admin/deploy.sh diff --git a/apps/services/modules/api/model_test.go b/apps/services/modules/api/model_test.go index 17c1a258..bcb3dfb7 100644 --- a/apps/services/modules/api/model_test.go +++ b/apps/services/modules/api/model_test.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "net/http" + "os" "strconv" "strings" "testing" @@ -369,10 +370,22 @@ func Test_GenerateMac(t *testing.T) { fmt.Printf("解析结果: productid=0x%04X, serial=%d\n", parsedProductid, parsedSerial) } + +// Test_DB 连真实库建表/查数据做一次性排查,默认跳过。 +// +// DSN 从环境变量取,未设置即跳过。 +// ⚠️ 原先写死的是云雁上海机的地址**和明文库密码**——那台机 2026-09-13 已从本仓库移除 +// (本机没有它的钥匙),写死的凭据留在 git 里只是风险,跑起来也只会连不上然后静默 return。 +// +// API_TEST_DSN='root:pwd@tcp(host:3306)/admin?charset=utf8mb4&parseTime=True&loc=Local' \ +// go test -v -run Test_DB ./modules/api/ func Test_DB(t *testing.T) { - //jdbc:mysql://139.224.212.237:3307/admin?user=root&password=li13451234&allowPublicKeyRetrieval=true&useSSL=false&serverTimezone=UTC + dsn := os.Getenv("API_TEST_DSN") + if dsn == "" { + t.Skip("未设置 API_TEST_DSN,跳过") + } if sys, err := mysql.NewSys( - mysql.SetMySQLDsn("root:li13451234@tcp(139.224.212.237:3307)/admin?charset=utf8mb4&parseTime=True&loc=Local"), + mysql.SetMySQLDsn(dsn), ); err != nil { fmt.Printf("err:%v", err) return diff --git a/apps/services/modules/echomeet/model_test.go b/apps/services/modules/echomeet/model_test.go index feb77474..4e76eb3b 100644 --- a/apps/services/modules/echomeet/model_test.go +++ b/apps/services/modules/echomeet/model_test.go @@ -1,16 +1,30 @@ package echomeet_test import ( + "os" + + "fmt" + "testing" "yunyan/comm" "yunyan/lego/sys/mysql" "yunyan/pb" - "fmt" - "testing" ) +// Test_InitAuthorizeTable 连真实业务库做一次性排查,默认跳过。 +// +// DSN 从环境变量取,未设置即跳过。 +// ⚠️ 原先写死的是云雁上海机的地址**和明文库密码**——那台机 2026-09-13 已从本仓库移除 +// (本机没有它的钥匙),写死的凭据留在 git 里只是风险,跑起来也只会连不上然后静默 return。 +// +// ECHOMEET_TEST_DSN='root:pwd@tcp(host:3306)/echomeet?charset=utf8mb4&parseTime=True&loc=Local' \ +// go test -v -run Test_InitAuthorizeTable ./modules/echomeet/ func Test_InitAuthorizeTable(t *testing.T) { + dsn := os.Getenv("ECHOMEET_TEST_DSN") + if dsn == "" { + t.Skip("未设置 ECHOMEET_TEST_DSN,跳过") + } if sys, err := mysql.NewSys( - mysql.SetMySQLDsn("root:li13451234@tcp(139.224.212.237:3306)/echomeet?charset=utf8mb4&parseTime=True&loc=Local"), + mysql.SetMySQLDsn(dsn), ); err != nil { fmt.Printf("err:%v", err) return diff --git a/apps/services/sys/nats/nats_test.go b/apps/services/sys/nats/nats_test.go index 2d45faef..0be4ef94 100644 --- a/apps/services/sys/nats/nats_test.go +++ b/apps/services/sys/nats/nats_test.go @@ -1,6 +1,7 @@ package nats import ( + "os" "testing" "time" ) @@ -11,14 +12,16 @@ import ( // // 用法: // -// NATS_URL=nats://47.253.88.66:4222 go test -v -run TestNatsConnect ./sys/nats/ +// NATS_URL=nats://:4222 go test -v -run TestNatsConnect ./sys/nats/ // // 它走和 home 启动时完全一样的路径:OnInit(连接 + 取 JetStream 上下文), // 再用 core 发布 + flush 证明不仅连得上、还能真正把数据发到服务端。 func TestNatsConnect(t *testing.T) { - url := "nats://47.253.88.66:4222" + // ⚠️ 这里原先是 `url := "nats://<写死的地址>"` 紧接着 `if url == ""`——常量永远不为空, + // 于是「默认跳过」从来没生效过:每次 go test 都在连那台早已下线的机器,白等一次超时才算过。 + url := os.Getenv("NATS_URL") if url == "" { - t.Skip("未设置 NATS_URL,跳过。示例: NATS_URL=nats://47.253.88.66:4222 go test -v -run TestNatsConnect ./sys/nats/") + t.Skip("未设置 NATS_URL,跳过。示例: NATS_URL=nats://:4222 go test -v -run TestNatsConnect ./sys/nats/") } t.Logf("→ 连接 %s ...", url) diff --git a/deploy/README.md b/deploy/README.md index efa1151f..ceecc5ce 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -6,89 +6,33 @@ cd deploy ./dev-deploy-all.sh # 交互选公司(环境),按 app → console → admin 全量发布 ./dev-deploy-all.sh along # 全量发到阿龙测试环境 -./dev-deploy-all.sh yunyan app admin # 只发 app 和 admin 到云雁测试环境 +./dev-deploy-all.sh along app admin # 只发 app 和 admin ./dev-deploy-all.sh along -y -k # 免确认;某个服务失败也继续发后面的 ./dev-deploy-all.sh along -n # dry-run,只打印会执行什么 ``` -公司/环境:`lingpu`(灵谱·香港)、`yunyan`(云雁·广州)、`along`(阿龙),与各服务 -`dev-deploy.sh` 的 `ENVS` 同名,脚本启动时会交叉校验,一边加了新环境另一边忘了加会直接报错。 +环境:目前只有 `along`(阿龙),与各服务 `dev-deploy.sh` 的 `ENVS` 同名,脚本启动时会交叉校验, +一边加了新环境另一边忘了加会直接报错。 + +> ⚠️ **2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本仓库的脚本中移除。** +> 移除的只是「往哪台服务器部署」——这些环境的 SSH 私钥路径指向的是另一台开发机,本机没有钥匙, +> 留着只会在菜单里制造误选。**镜像仓库没有动**:`prod-build.sh` 仍可选 `yunyan` / `lingpu` +> 把镜像推到 `registry.voitrans.net` / `registry.lingpu.net`。 +> 要恢复部署目标,从 git 历史里取回对应的 `env_profile` / `region_profile` 段即可(含 IP 与私钥路径)。 它只是按顺序调各服务自己的 `deploy/<服务>/dev-deploy.sh <环境>` 并汇总结果,部署规则仍然 只有一处;单独发某个服务照旧进服务目录跑 `./dev-deploy.sh <环境>`。服务器上还没有真实 `.env` 时子脚本会推完镜像就停下,汇总表里记为「跳过」而不是「成功」。 -> 以下是早期 `deploy.sh [action]` 的说明,与现在的 `dev-deploy.sh` / `prod-build.sh` / -> `prod-deploy.sh` 流程不完全一致,仅供参考。 +## 各服务的脚本 -**每个服务目录各一个 `deploy.sh`**,服务名取自所在目录,指令为 ` [action]`。 -每个服务自带单服务 compose + 环境模板;依赖服务(PostgreSQL / Redis / NATS) -由目标环境**共享提供**,不在 compose 内搭建,只在 env 里填连接地址。 +每个服务目录下三个脚本:`dev-deploy.sh`(测试环境,固定 tag `dev-latest`)、 +`prod-build.sh <版本> [公司]`(构建并推送带版本号的镜像)、`prod-deploy.sh`(只做远端拉取重启)。 +服务器上的 `.env` 与 `confs/*.yaml` 由人工维护,脚本只下发 `*.example` 模板,绝不覆盖。 -## 服务 - `console/` — Go 控制面服务(:8080) - `admin/` — Nuxt 管理前端(:3000,通过 `CONSOLE_BACKEND` 连 console) +- `app/` — Go 业务后端(多应用共用镜像,远端目录/容器名按应用区分,见 `prod-deploy.sh` 的 `APPS`) -## 目录结构 -``` -deploy/ -└── / # console / admin - ├── deploy.sh # 本服务部署脚本(服务名 = 目录名) - ├── docker-compose.yml # 单服务 compose(变量驱动,无依赖服务) - ├── env/ - │ ├── local.env.example - │ ├── dev.env.example - │ ├── prod.env.example - │ └── (复制填写后的 local.env / dev.env / prod.env) - └── (console 额外: confs/console.yaml、log/) -``` -> 两个服务的 `deploy.sh` 内容相同,靠所在目录名区分服务。 - -## 用法 -进入服务目录运行: -```bash -cd deploy/console -./deploy.sh local up # 本机起 console -./deploy.sh dev # 一键发布 console 到开发服务器(动作默认 deploy) -./deploy.sh prod # 一键发布 console 到生产服务器 -./deploy.sh prod logs # 看生产 console 日志 - -cd deploy/admin -./deploy.sh local up # 本机起 admin -./deploy.sh prod # 发布 admin 到生产服务器 -``` - -参数: -- `env`:`local` | `dev` | `prod` -- `action`: - - `local`:up(默认)| down | restart | logs | ps | pull | build - - `dev` / `prod`:deploy(默认,构建推送+同步+远程拉起)| up(仅远程拉起)| build | down | restart | logs | ps | pull - -## 首次配置(dev / prod) -配置分两处:**部署目标/仓库凭据写死在各服务的 `deploy.sh`,运行时配置放 env 文件**。 - -1. 部署目标 + 私有仓库(改各服务 `deploy.sh` 顶部 `deploy_profile`,[console](console/deploy.sh) / [admin](admin/deploy.sh)): - - 按 `dev` / `prod` 段填 `DEPLOY_HOST`(服务器 IP) 和 `REGISTRY_PASS`(仓库密码) - - 通用项已给默认:`REGISTRY` / `REGISTRY_USER` / `DEPLOY_PORT` / `DEPLOY_USER` / `DEPLOY_KEY` - - `DEPLOY_DIR` 自动 = `/opt/yunyan/<服务名>`,无需填 - - 注:两个 `deploy.sh` 各填各的,不共享 -2. 运行时配置(每个服务、每个环境一份 env): - ```bash - cp console/env/dev.env.example console/env/dev.env - cp admin/env/dev.env.example admin/env/dev.env - ``` - 需要填: - - 依赖服务连接(console):`POSTGRES_DSN` / `REDIS_ADDR`+`REDIS_PASSWORD` / `NATS_URL` - - 网络与端口:`DOCKER_NETWORK` / `ADMIN_PORT` / `TAG` -3. 目标机要求:装 docker + docker compose v2、能访问私有镜像仓库、SSH 公钥已授权、依赖服务在 `DOCKER_NETWORK` 网络内可达。 - -## 部署顺序 -依赖服务(DB/Redis/NATS)共享、由环境预先提供。两个应用服务按序: -1. 先 `console`(admin 依赖它) -2. 再 `admin`(同一目标机、同一 `DOCKER_NETWORK`,用容器名 `yunyan-console` 连 console) - -## 注意 -- `env/*.env`(真实)含密钥/DSN,已 `.gitignore` 忽略;仓库只保留 `*.example`。 -- ⚠️ 部署目标/仓库密码写死在各服务 `deploy.sh`,而它们**会进 git**——`DEPLOY_HOST`、`REGISTRY_PASS` 等会随仓库提交(私有仓库内可接受;公开前务必清理两个 `deploy.sh`)。 -- prod 的 `TAG` 用固定版本号便于回滚;`FIELD_ENCRYPT_KEY` / `CONSOLE_TOKEN_KEY` 用强随机值,环境间不复用。 -- 镜像构建复用仓库根目录 `build.sh`(`deploy.sh` 在 deploy/build 动作时自动调用,目标=服务名);当前仓库**尚无 build.sh**,build/deploy 前需先补。 +⚠️ 部署目标与仓库密码写死在脚本里且**会进 git**(私有仓库内可接受;公开前务必清理 +`deploy/registry-profiles.sh` 的 `REGISTRY_PASS` 与各 `*-deploy.sh` 的 `DEPLOY_HOST`)。 diff --git a/deploy/admin/README.md b/deploy/admin/README.md index e505e113..0abf14b7 100644 --- a/deploy/admin/README.md +++ b/deploy/admin/README.md @@ -16,7 +16,7 @@ | `env/env.example` | 运行时环境**模板**(只一份,不分环境);真实 `.env` 被 gitignore | | `dev-deploy.sh` | **开发**:构建 dev 镜像 → 推送 → 远端拉取重启(固定 tag `dev-latest`) | | `prod-build.sh` | **生产①**:构建带版本号镜像并推送(`:版本` + `:latest`),不部署 | -| `prod-deploy.sh` | **生产②**:部署指定版本到指定生产环境(`yunyan`/`lingpu`),支持回滚 | +| `prod-deploy.sh` | **生产②**:部署指定版本到生产环境(目前只有 `along`),支持回滚 | ## 用法 @@ -45,12 +45,12 @@ docker compose up -d # 本机起 starpivot-admin ```bash cd deploy/admin -./dev-deploy.sh lingpu # 开发:发布到灵谱测试环境(构建 dev-latest → 推送 → 远端拉取重启) +./dev-deploy.sh along # 开发:发布到阿龙测试环境(构建 dev-latest → 推送 → 远端拉取重启) ./dev-deploy.sh yunyan # 开发:发布到云雁测试环境 ./dev-deploy.sh # 不带参数 → 交互选择测试环境 ./prod-build.sh 0.1.1 yunyan # 生产①:构建并推送 starpivot-admin:0.1.1 (+latest);第2参数选公司 -./prod-deploy.sh 0.1.1 lingpu # 生产②:部署 0.1.1 到指定生产环境(yunyan|lingpu|along),省略环境则交互选 -./prod-deploy.sh rollback lingpu # 生产回滚到上一版本(与当前版本来回切换) +./prod-deploy.sh 0.2.1 along # 生产②:部署 0.2.1 到生产环境(目前只有 along,省略即用它) +./prod-deploy.sh rollback along # 生产回滚到上一版本(与当前版本来回切换) ``` > 改了服务器上的 `.env` 后,必须经 `up`(脚本里的 `docker compose up -d`)**重建容器**才生效,`restart` 不会重读环境变量。 @@ -58,8 +58,9 @@ cd deploy/admin ## 需要填写 / 提供的东西 -- **部署目标与凭据**:写死在各脚本顶部。`dev-deploy.sh` 的 `env_profile()`(每个测试环境一套 `REGISTRY/DEV_HOST/DEV_KEY/DEV_DIR`,现有 `lingpu`、`yunyan`、`along`;新增环境加一段 case 并写进 `ENVS`)、`prod-deploy.sh` 的 `env_profile()`(每个生产环境一套 `REGISTRY/IMAGE_NAME/DEPLOY_HOST/DEPLOY_KEY/DEPLOY_DIR`,现有 `yunyan`、`lingpu`、`along`;新增环境加一段 case 并写进 `PROD_ENVS`); - 仓库账号 `admin` / 密码已写死;`DEPLOY_KEY` 默认 `/Users/liwei/Documents/key/yunyan-us.pem`(prod)。 +- **部署目标与凭据**:写死在各脚本顶部。`dev-deploy.sh` 的 `env_profile()`(每个测试环境一套 `REGISTRY/DEV_HOST/DEV_KEY/DEV_DIR`,**目前只有 `along`**;新增环境加一段 case 并写进 `ENVS`)、`prod-deploy.sh` 的 `env_profile()`(每个生产环境一套 `REGISTRY/IMAGE_NAME/DEPLOY_HOST/DEPLOY_KEY/DEPLOY_DIR`,**目前只有 `along`**;新增环境加一段 case 并写进 `PROD_ENVS`); + 仓库账号 `admin` / 密码已写死;`DEPLOY_KEY` 默认指向阿龙那把钥匙,可用环境变量覆盖:`DEPLOY_KEY=~/Documents/keys/loginscre.pem ./prod-deploy.sh …`。 + - 2026-09-13 移除了云雁/灵谱的部署目标(私钥在另一台开发机上,本机连不上);**镜像仓库未动**,`prod-build.sh` 仍可选这两家推镜像。 - ⚠️ 本目录脚本纳入 git,**公开仓库前务必清空** `*_HOST` 与 `REGISTRY_PASS`。 - **后端地址**:`.env` 的 `CONSOLE_BACKEND`,须指向同网络的 console 容器,默认 `http://starpivot-console:8080`。 diff --git a/deploy/admin/deploy.sh b/deploy/admin/deploy.sh deleted file mode 100755 index 26307e6b..00000000 --- a/deploy/admin/deploy.sh +++ /dev/null @@ -1,184 +0,0 @@ -#!/usr/bin/env bash -# <服务> 部署脚本(每个服务目录各一份,服务名取自所在目录名) -# -# 用法: ./deploy.sh [action] (在 deploy/<服务>/ 下运行) -# env : local | dev | prod -# action : dev/prod → deploy(默认) | up | build | pull | down | restart | logs | ps -# local → up(默认) | build | pull | down | restart | logs | ps -# -# deploy = 构建推送镜像 + 同步配置 + 远程 pull + up(一键发布,仅 dev/prod) -# up = 远程:仅同步配置 + 远程 pull + up(用已推送镜像);本机:起容器 -# -# 例(在 deploy/console/ 下): -# ./deploy.sh prod # 一键发布生产 console -# ./deploy.sh prod logs # 看生产 console 日志 -# ./deploy.sh local up # 本机起 console -# ./deploy.sh dev build # 只构建推送 dev 镜像 -set -euo pipefail - -SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 本服务部署目录(deploy/<服务>) -SERVICE="$(basename "$SVC_DIR")" # 服务名 = 目录名(console / admin) -REPO_ROOT="$(cd "$SVC_DIR/../.." && pwd)" # 仓库根(deploy/<服务>/../..) - -blue() { printf "\033[34m%s\033[0m\n" "$*"; } -green() { printf "\033[32m%s\033[0m\n" "$*"; } -red() { printf "\033[31m%s\033[0m\n" "$*"; } - -# ╔══════════════════════════════════════════════════════════════════════╗ -# ║ 部署目标 / 私有仓库配置 —— 写死在这里,改这里即可(按环境) ║ -# ║ console、admin 同机不同目录;DEPLOY_DIR 自动 = /opt/yunyan/<服务名> ║ -# ║ 注意:本文件纳入 git,下面的密码/IP 会随仓库提交(私有仓库内可接受) ║ -# ╚══════════════════════════════════════════════════════════════════════╝ -deploy_profile() { - DEPLOY_HOST=""; REGISTRY_PASS="" # 占位,local 用不到;dev/prod 在下面填 - # —— 各环境通用默认 —— - REGISTRY=registry.voitrans.net # 私有镜像仓库地址 - REGISTRY_USER=liwei # 仓库账号 - DEPLOY_PORT=22 # 服务器 SSH 端口 - DEPLOY_USER=root # 服务器 SSH 用户 - DEPLOY_KEY=~/Documents/灵谱/lingpu-hk.pem # 本机访问服务器的 SSH 私钥路径 - case "$ENV_NAME" in - dev) - DEPLOY_HOST="8.217.193.140" # 灵谱香港阿里云(lingpu-hk) - REGISTRY_PASS="li13451234" # 私有仓库密码(liwei 用户) - ;; - prod) - DEPLOY_HOST="" # ← 生产服务器 IP(必填) - REGISTRY_PASS="" # ← 私有仓库密码(必填) - ;; - local) ;; # 本机不走 SSH,无需填 - esac - DEPLOY_DIR="/home/work/starpivot-$SERVICE" # 远程部署目录(与 /home/work 下其余服务一致) -} - -usage() { - cat >&2 < [action] (在 deploy/$SERVICE/ 下运行) - env : local | dev | prod - action : dev/prod → deploy(默认) | up | build | pull | down | restart | logs | ps - local → up(默认) | build | pull | down | restart | logs | ps -例: - ./deploy.sh prod # 一键发布生产 $SERVICE - ./deploy.sh prod logs # 看生产 $SERVICE 日志 - ./deploy.sh local up # 本机起 $SERVICE - ./deploy.sh dev build # 只构建推送 dev 镜像 -EOF - exit 1 -} - -# ── 参数解析与校验 ── -ENV_NAME="${1:-}"; ACTION="${2:-}" -[ -n "$ENV_NAME" ] || usage -[ -f "$SVC_DIR/docker-compose.yml" ] || { red "✗ $SERVICE 目录缺 docker-compose.yml(deploy.sh 须放在服务目录内)"; exit 1; } -case "$ENV_NAME" in - local|dev|prod) ;; - *) red "✗ 未知环境: ${ENV_NAME}(应为 local|dev|prod)"; usage ;; -esac -# 默认动作:远程发布默认 deploy,本机默认 up -[ -n "$ACTION" ] || { [ "$ENV_NAME" = local ] && ACTION=up || ACTION=deploy; } - -# 从 ENV_FILE 安全读取单个变量值(去除可能的外层双引号) -_envget() { - { grep -E "^$1=" "$ENV_FILE" || true; } | head -1 | cut -d= -f2- | sed -e 's/^"//' -e 's/"$//' -} - -# 载入 env/<环境>.env —— 现在只放容器运行时配置(DSN / Redis / NATS / 密钥 / 端口 / TAG / 网络)。 -# 部署目标与仓库凭据已写死在 deploy_profile,不再放 env 文件。脚本只需从这里取 compose 仍要的 TAG/网络。 -load_env() { - ENV_FILE="$SVC_DIR/env/$ENV_NAME.env" - if [ ! -f "$ENV_FILE" ]; then - red "✗ 缺少 $SERVICE/env/$ENV_NAME.env —— 请先从 $SERVICE/env/$ENV_NAME.env.example 复制并填写" - exit 1 - fi - TAG="$(_envget TAG)"; TAG="${TAG:-latest}" - DOCKER_NETWORK="$(_envget DOCKER_NETWORK)"; DOCKER_NETWORK="${DOCKER_NETWORK:-1panel-network}" -} - -# 生成 compose 用 .env = 服务运行时 env 文件 + 注入写死的 REGISTRY(镜像地址替换用) -# 先滤掉源文件里可能残留的 REGISTRY 行,保证唯一、不依赖 compose 的覆盖顺序。 -gen_env() { - { grep -v '^REGISTRY=' "$ENV_FILE" || true; } > "$SVC_DIR/.env" - printf 'REGISTRY=%s\n' "$REGISTRY" >> "$SVC_DIR/.env" -} - -# 构建并推送本服务镜像(复用仓库根目录 build.sh,目标 = 服务名)。 -# local 环境只构建不推送(PUSH=0),dev/prod 构建并推送到私有仓库。 -build_push() { - local push=1; [ "$ENV_NAME" = local ] && push=0 - blue ">>> 构建$([ "$push" = 1 ] && echo 推送) $SERVICE 镜像 (TAG=${TAG:-latest}, PUSH=$push)" - TAG="${TAG:-latest}" REGISTRY="$REGISTRY" PUSH="$push" "$REPO_ROOT/build.sh" "$SERVICE" -} - -ensure_network_local() { - docker network inspect "$DOCKER_NETWORK" >/dev/null 2>&1 || docker network create "$DOCKER_NETWORK" -} - -# 本机 docker compose(gen_env 落为同目录 .env,既做变量替换又做容器 env_file) -compose_local() { - gen_env - ensure_network_local - ( cd "$SVC_DIR" && docker compose --env-file .env "$@" ) -} - -# ── 远程 SSH 基础 ── -_ssh() { ssh -p "${DEPLOY_PORT:-22}" -i "${DEPLOY_KEY/#\~/$HOME}" -o StrictHostKeyChecking=accept-new "${DEPLOY_USER:-root}@${DEPLOY_HOST}" "$@"; } -_scp() { scp -P "${DEPLOY_PORT:-22}" -i "${DEPLOY_KEY/#\~/$HOME}" -o StrictHostKeyChecking=accept-new "$@"; } -_dest() { echo "${DEPLOY_USER:-root}@${DEPLOY_HOST}:$1"; } - -# 远程发布:同步配置 + 远程 login + pull + up -remote_deploy() { - : "${DEPLOY_HOST:?请在 deploy.sh 顶部 deploy_profile 的 $ENV_NAME 段填 DEPLOY_HOST}" - gen_env - - blue ">>> 同步 $SERVICE 配置到 ${DEPLOY_USER:-root}@${DEPLOY_HOST}:${DEPLOY_DIR}" - _ssh "mkdir -p '$DEPLOY_DIR'" - _scp "$SVC_DIR/docker-compose.yml" "$(_dest "$DEPLOY_DIR/docker-compose.yml")" - _scp "$SVC_DIR/.env" "$(_dest "$DEPLOY_DIR/.env")" - # 带 confs/ 的服务(console)一并同步配置并预建 log 目录 - if [ -d "$SVC_DIR/confs" ]; then - _ssh "mkdir -p '$DEPLOY_DIR/confs' '$DEPLOY_DIR/log'" - _scp -r "$SVC_DIR/confs/." "$(_dest "$DEPLOY_DIR/confs/")" - fi - - blue ">>> 远程拉起 $SERVICE" - [ -n "${REGISTRY_PASS:-}" ] && \ - _ssh "docker login '$REGISTRY' -u '${REGISTRY_USER:-admin}' -p '$REGISTRY_PASS'" - _ssh "docker network inspect '$DOCKER_NETWORK' >/dev/null 2>&1 || docker network create '$DOCKER_NETWORK'" - _ssh "cd '$DEPLOY_DIR' && docker compose --env-file .env pull && docker compose --env-file .env up -d --force-recreate" -} - -# 远程运维(down/restart/logs/ps/pull) -remote_compose() { - : "${DEPLOY_HOST:?请在 deploy.sh 顶部 deploy_profile 的 $ENV_NAME 段填 DEPLOY_HOST}" - _ssh "cd '$DEPLOY_DIR' && docker compose --env-file .env $*" -} - -# ── 分发 ── -deploy_profile # 写死的部署目标 / 仓库凭据 -load_env # env 文件里的运行时配置(TAG / 网络) - -if [ "$ENV_NAME" = local ]; then - case "$ACTION" in - up) compose_local up -d --force-recreate ;; - down) compose_local down ;; - restart) compose_local restart ;; - logs) compose_local logs -f --tail=120 ;; - ps) compose_local ps ;; - pull) compose_local pull ;; - build) build_push ;; - *) red "未知操作: ${ACTION}(local 支持 up|down|restart|logs|ps|pull|build)"; exit 1 ;; - esac -else - case "$ACTION" in - deploy) build_push; remote_deploy ;; - up) remote_deploy ;; - build) build_push ;; - pull) remote_compose pull ;; - down) remote_compose down ;; - restart) remote_compose restart ;; - ps) remote_compose ps ;; - logs) remote_compose logs -f --tail=120 ;; - *) red "未知操作: ${ACTION}(dev/prod 支持 deploy|up|build|pull|down|restart|logs|ps)"; exit 1 ;; - esac -fi -green "✓ $SERVICE $ENV_NAME $ACTION 完成" diff --git a/deploy/admin/dev-deploy.sh b/deploy/admin/dev-deploy.sh index 827c329f..8e404e1a 100755 --- a/deploy/admin/dev-deploy.sh +++ b/deploy/admin/dev-deploy.sh @@ -6,13 +6,14 @@ # (照着仓库里的 env/env.example 在服务器上放好真实 .env),本脚本不上传任何真实配置。 # # 用法(在 deploy/admin/ 下): -# ./dev-deploy.sh lingpu # 发布到灵谱测试环境 -# ./dev-deploy.sh yunyan # 发布到云雁测试环境 # ./dev-deploy.sh along # 发布到阿龙测试环境 -# ./dev-deploy.sh # 不带参数 → 交互选择环境(无 TTY 时用默认环境 lingpu) +# ./dev-deploy.sh # 不带参数 → 交互选择环境(目前只有 along 一个,无 TTY 时也用它) # # 开发版镜像始终使用固定 tag dev-latest,每次构建覆盖同一 tag。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # deploy/admin REPO_ROOT="$(cd "$SVC_DIR/../.." && pwd)" # 仓库根 @@ -34,27 +35,13 @@ IMAGE_NAME="starpivot-admin" # 业务镜像名 # ║ ⚠️ 公开仓库前务必清空 DEV_HOST / REGISTRY_PASS ║ # ║ 新增环境:在 env_profile 加一段 case,并把环境名加进 ENVS 数组。 ║ # ╚══════════════════════════════════════════════════════════════════════╝ -ENVS=(lingpu yunyan along) # 可选测试环境(交互菜单按此顺序展示) -DEFAULT_ENV="lingpu" # 无参数且无 TTY(CI/管道)时的默认环境 +ENVS=(along) # 可选测试环境(目前只剩阿龙;云雁/灵谱已于 2026-09-13 移除,见文件头说明) +DEFAULT_ENV="along" # 无参数且无 TTY(CI/管道)时的默认环境 env_profile() { DEV_PORT=22 # 各环境通用默认 DEV_USER=root case "$DEV_ENV" in - lingpu) - ENV_DESC="灵谱测试环境 · 香港阿里云 (lingpu-hk)" - registry_profile lingpu # 镜像仓库:灵谱 - DEV_HOST="8.217.193.140" # ← 灵谱测试服务器 IP - DEV_KEY=/Users/liwei/Documents/灵谱/lingpu-hk.pem # 本机访问该服务器的 SSH 私钥 - DEV_DIR="/home/work/starpivot/admin" # 远端部署目录(其中 docker-compose.yml/.env 由你自己维护) - ;; - yunyan) - ENV_DESC="云雁测试环境 · 广州阿里云" - registry_profile yunyan # 镜像仓库:云雁(registry.voitrans.net,就在这台机上) - DEV_HOST="8.138.86.223" # ← 云雁测试服务器 IP(2026-07 由腾讯云 124.222.232.218 迁来) - DEV_KEY="/Users/liwei1dao/work/密钥/dev-guangzhou.pem" # 本机访问该服务器的 SSH 私钥(2026-08-18 由 ~/.ssh/aliyun_guangzhou.pem 迁到此处) - DEV_DIR="/home/work/starpivot/admin" - ;; along) ENV_DESC="阿龙测试环境 · 阿里云" registry_profile along # 镜像仓库:就在这台机上(registry.ymaikj.com,账号 admin) @@ -73,8 +60,6 @@ usage() { 用法: ./dev-deploy.sh [环境] (在 deploy/admin/ 下运行) 环境 : ${ENVS[*]// /, }(省略则交互选择;无 TTY 时用默认 ${DEFAULT_ENV}) 例: - ./dev-deploy.sh lingpu # 发布到灵谱测试环境 - ./dev-deploy.sh yunyan # 发布到云雁测试环境 ./dev-deploy.sh along # 发布到阿龙测试环境 EOF } diff --git a/deploy/admin/prod-deploy.sh b/deploy/admin/prod-deploy.sh index 9020afe0..72db6623 100755 --- a/deploy/admin/prod-deploy.sh +++ b/deploy/admin/prod-deploy.sh @@ -6,11 +6,14 @@ # (照着仓库里的 env/env.example 在服务器上放好真实 .env),本脚本不上传任何真实配置。 # # 用法(在 deploy/admin/ 下): -# ./prod-deploy.sh [环境] # 部署指定版本,如 ./prod-deploy.sh 0.1.1 lingpu +# ./prod-deploy.sh [环境] # 部署指定版本,如 ./prod-deploy.sh 0.1.1 along # ./prod-deploy.sh rollback [环境] # 回滚到上一次部署版本(与当前版本来回切换) -# 环境 = yunyan(上海)| lingpu(广州)| along(阿龙 47.116.104.181);省略 → 交互选择,无 TTY 时用默认 yunyan。 +# 环境 = along(阿龙 47.116.104.181);省略 → 直接用它。 # ⚠️ 环境必须与 prod-build.sh 构建时所选公司一致,否则拉不到镜像。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -32,30 +35,13 @@ DOCKER_NETWORK="1panel-network" # compose 外部网络名(与服务 # 容器名:必须与 docker-compose.yml 的 container_name 一字不差(本脚本会上传覆盖那份 compose)。 # 仅用于 up 冲突时清理同名遗留容器;不随环境变化。 CONTAINER_NAME="starpivot-admin" -PROD_ENVS=(yunyan lingpu along) # 可选生产环境(交互菜单按此顺序展示) -DEFAULT_PROD_ENV="yunyan" # 无参数且无 TTY(CI/管道)时的默认环境 +PROD_ENVS=(along) # 可选生产环境(目前只剩阿龙;云雁/灵谱已于 2026-09-13 移除,见文件头说明) +DEFAULT_PROD_ENV="along" # 无参数且无 TTY(CI/管道)时的默认环境 env_profile() { DEPLOY_PORT=22 # 各环境通用默认 DEPLOY_USER=root case "$DEPLOY_ENV" in - yunyan) - # 2026-08-05 起 admin 生产目标改为上海机(与业务后端 app 同机)。 - # 旧目标:美国机 47.253.88.66,其上 yunyan-admin:0.1.1 容器仍在跑,待新环境验证后再停; - # 需要临时回连那台时,把下面三行换成 47.253.88.66 / yunyan-us.pem / /home/work/yunyan-admin。 - ENV_DESC="云雁生产环境 · 上海阿里云" - registry_profile yunyan || return 1 # 镜像仓库:云雁 - DEPLOY_HOST="139.224.212.237" # ← 云雁生产服务器 IP(上海) - DEPLOY_KEY="/Users/liwei1dao/work/密钥/release_shanghai.pem" - DEPLOY_DIR="/home/work/starpivot/admin" # 远端部署目录(其中 docker-compose.yml/.env 由你自己维护) - ;; - lingpu) - ENV_DESC="灵谱生产环境 · 广州阿里云 (lingpu-gz)" - registry_profile lingpu || return 1 # 镜像仓库:灵谱(registry.lingpu.net,实体在香港机) - DEPLOY_HOST="8.166.114.65" # ← 灵谱生产服务器 IP - DEPLOY_KEY=~/.ssh/lingpu-gz.pem # 私钥放 ~/.ssh:~/Documents 会被 macOS TCC 挡住读不出来 - DEPLOY_DIR="/home/work/starpivot/admin" - ;; along) ENV_DESC="阿龙生产环境 · 阿里云" registry_profile along || return 1 # 镜像仓库:registry.ymaikj.com(实体在阿龙测试机 8.133.166.29,账号 admin) @@ -72,7 +58,7 @@ env_host_of() { ( DEPLOY_ENV="$1" env_profile >/dev/null 2>&1; printf '%s' "${DE # ── 参数: [环境] ── ARG1="${1:-}" -[ -n "$ARG1" ] || { red "用法: ./prod-deploy.sh [环境](如 0.1.1 lingpu)"; exit 1; } +[ -n "$ARG1" ] || { red "用法: ./prod-deploy.sh [环境](如 0.1.1 along)"; exit 1; } if [ "$ARG1" = "rollback" ]; then MODE="rollback"; NEW_TAG=""; else MODE="deploy"; NEW_TAG="$ARG1"; fi DEPLOY_ENV="${2:-}" diff --git a/deploy/app/README.md b/deploy/app/README.md index 343b4a31..52f150a2 100644 --- a/deploy/app/README.md +++ b/deploy/app/README.md @@ -36,7 +36,9 @@ └── confs/ 附属文件 # 见下「需要提供的东西」 ``` -dev 部署目录默认 `/home/work/voitrans-a11`,prod 默认 `/opt/yunyan/voitrans`(见脚本)。 +dev 部署目录默认 `/home/work/starpivot/app`;prod 按**应用**取自 `prod-deploy.sh` 的 `APPS` 表(如 `ym` → `/home/work/ym-a11`)。 + +> 2026-09-13:prod 的可选区域只剩 `along`(云雁的 shanghai/japan/singapore 已移除,私钥在另一台开发机上)。 ### 二、部署 @@ -44,7 +46,7 @@ dev 部署目录默认 `/home/work/voitrans-a11`,prod 默认 `/opt/yunyan/voit ```bash cd deploy/voitrans -./dev-deploy.sh lingpu # 发布到灵谱测试环境(构建 dev-latest → 推送 → 远端拉取重启) +./dev-deploy.sh along # 发布到阿龙测试环境(构建 dev-latest → 推送 → 远端拉取重启) ./dev-deploy.sh yunyan # 发布到云雁测试环境 ./dev-deploy.sh # 不带参数 → 交互选择测试环境 ``` @@ -53,11 +55,9 @@ cd deploy/voitrans ```bash ./prod-build.sh 0.1.1 # 构建并推送 starpivot-app:0.1.1 (+latest) -./prod-deploy.sh shanghai 0.1.1 # 部署 0.1.1 到上海 -./prod-deploy.sh japan 0.1.1 # 部署到日本 -./prod-deploy.sh singapore 0.1.1 # 部署到新加坡 +./prod-deploy.sh ym along 0.2.1 # 部署应用 ym 的 0.2.1 到阿龙生产 ./prod-deploy.sh ym along 0.1.4 # 部署 ym 到阿龙正式机(目录 /home/work/ym-a11,容器 ym-a11;镜像走阿龙仓库,需先 ./prod-build.sh 0.1.4 along) -./prod-deploy.sh shanghai rollback # 上海回滚到上一版本(与当前版本来回切换) +./prod-deploy.sh ym along rollback # 回滚到上一版本(与当前版本来回切换) ./prod-deploy.sh # 不带参数 → 交互引导:选应用 / 区域 / 版本 ``` @@ -75,8 +75,8 @@ cd deploy/voitrans ## 需要填写 / 提供的东西 - **部署目标与凭据**:写死在各脚本顶部。 - - `dev-deploy.sh`:`env_profile()` 里各测试环境(`lingpu` / `yunyan` / `along`)的 `REGISTRY/DEV_HOST/DEV_KEY/DEV_DIR`。 - - `prod-deploy.sh`:`region_profile()` 里各区域(`shanghai` / `japan` / `singapore` / `along`)的 `DEPLOY_HOST`; + - `dev-deploy.sh`:`env_profile()` 里各测试环境(**目前只有 `along`**)的 `REGISTRY/DEV_HOST/DEV_KEY/DEV_DIR`。 + - `prod-deploy.sh`:`region_profile()` 里各区域(**目前只有 `along`**)的 `DEPLOY_HOST`; 另有 `REGION_COMPANY`(该区域拉哪个公司的仓库,可用环境变量 `COMPANY` 覆盖)。 远端目录只由 `APPS` 表决定(`ym` → `/home/work/ym-a11`),区域里**不再覆盖目录**;容器名由应用 key 推导为 `<应用>-a11`, 部署时以 `CONTAINER_NAME` 注入 compose 并写回服务器 `.env`,所以同一台机可以并存多个应用。 diff --git a/deploy/app/dev-deploy.sh b/deploy/app/dev-deploy.sh index 51f379d5..30b47096 100755 --- a/deploy/app/dev-deploy.sh +++ b/deploy/app/dev-deploy.sh @@ -6,13 +6,14 @@ # (照着仓库里的 env/env.example、confs/*.yaml.example 在服务器上放好真实文件),本脚本不上传任何配置。 # # 用法(在 deploy/app/ 下): -# ./dev-deploy.sh lingpu # 发布到灵谱测试环境 -# ./dev-deploy.sh yunyan # 发布到云雁测试环境 # ./dev-deploy.sh along # 发布到阿龙测试环境 -# ./dev-deploy.sh # 不带参数 → 交互选择环境(无 TTY 时用默认环境 lingpu) +# ./dev-deploy.sh # 不带参数 → 交互选择环境(目前只有 along 一个,无 TTY 时也用它) # # 参数只用于选环境;开发版镜像始终使用固定 tag dev-latest,每次构建覆盖同一 tag。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # deploy/app REPO_ROOT="$(cd "$SVC_DIR/../.." && pwd)" # 仓库根 @@ -34,27 +35,13 @@ IMAGE_NAME="starpivot-app" # 业务单镜像名 # ║ ⚠️ 公开仓库前务必清空 DEV_HOST / REGISTRY_PASS ║ # ║ 新增环境:在 env_profile 加一段 case,并把环境名加进 ENVS 数组。 ║ # ╚══════════════════════════════════════════════════════════════════════╝ -ENVS=(lingpu yunyan along) # 可选测试环境(交互菜单按此顺序展示) -DEFAULT_ENV="lingpu" # 无参数且无 TTY(CI/管道)时的默认环境 +ENVS=(along) # 可选测试环境(目前只剩阿龙;云雁/灵谱已于 2026-09-13 移除,见文件头说明) +DEFAULT_ENV="along" # 无参数且无 TTY(CI/管道)时的默认环境 env_profile() { DEV_PORT=22 # 各环境通用默认 DEV_USER=root case "$DEV_ENV" in - lingpu) - ENV_DESC="灵谱 · 香港阿里云 (lingpu-hk)" - registry_profile lingpu # 镜像仓库:灵谱 - DEV_HOST="8.217.193.140" # ← 灵谱测试服务器 IP - DEV_KEY=/Users/liwei/Documents/灵谱/lingpu-hk.pem # 本机访问该服务器的 SSH 私钥 - DEV_DIR="/home/work/starpivot/app" # 远端部署目录(其中 docker-compose.yml/.env/confs 由你自己维护) - ;; - yunyan) - ENV_DESC="云雁测试环境 · 广州阿里云" - registry_profile yunyan # 镜像仓库:云雁(registry.voitrans.net,就在这台机上) - DEV_HOST="8.138.86.223" # ← 云雁测试服务器 IP(2026-07 由腾讯云 124.222.232.218 迁来) - DEV_KEY="/Users/liwei1dao/work/密钥/dev-guangzhou.pem" # 本机访问该服务器的 SSH 私钥(2026-08-18 由 ~/.ssh/aliyun_guangzhou.pem 迁到此处) - DEV_DIR="/home/work/starpivot/app" - ;; along) ENV_DESC="阿龙测试环境 · 阿里云" registry_profile along # 镜像仓库:就在这台机上(registry.ymaikj.com,账号 admin) @@ -73,8 +60,6 @@ usage() { 用法: ./dev-deploy.sh [环境] (在 deploy/app/ 下运行) 环境 : ${ENVS[*]// /, }(省略则交互选择;无 TTY 时用默认 ${DEFAULT_ENV}) 例: - ./dev-deploy.sh lingpu # 发布到灵谱测试环境 - ./dev-deploy.sh yunyan # 发布到云雁测试环境 ./dev-deploy.sh along # 发布到阿龙测试环境 EOF } diff --git a/deploy/app/prod-build.sh b/deploy/app/prod-build.sh index 0c70e6b2..46990543 100755 --- a/deploy/app/prod-build.sh +++ b/deploy/app/prod-build.sh @@ -50,5 +50,5 @@ docker push "$IMG_VER" docker push "$IMG_LATEST" green "✓ 已推送 $IMG_VER 与 $IMG_LATEST" -echo " 部署:./prod-deploy.sh <应用> $VERSION" -echo " 例:./prod-deploy.sh voitrans shanghai $VERSION" +echo " 部署:./prod-deploy.sh <应用> along $VERSION" +echo " 例:./prod-deploy.sh ym along $VERSION" diff --git a/deploy/app/prod-deploy.sh b/deploy/app/prod-deploy.sh index e4adfb89..0cddeda3 100755 --- a/deploy/app/prod-deploy.sh +++ b/deploy/app/prod-deploy.sh @@ -13,13 +13,16 @@ # # 用法(在 deploy/voitrans/ 下): # ./prod-deploy.sh # 不带参数 → 交互式引导:逐步选「应用 / 区域 / 版本」,部署前确认 -# ./prod-deploy.sh <应用> <区域> # 直接部署,如 ./prod-deploy.sh voitrans shanghai 0.1.1 +# ./prod-deploy.sh <应用> <区域> # 直接部署,如 ./prod-deploy.sh ym along 0.2.1 # ./prod-deploy.sh <应用> <区域> rollback # 回滚到上一次部署版本(与当前版本来回切换) # ./prod-deploy.sh <区域> # 省略应用 → 默认首个应用(兼容旧写法) # ./prod-deploy.sh -h # 查看用法 -# 应用: 见 APPS(默认 voitrans) 区域: shanghai | japan | singapore | along -# 镜像仓库跟区域走:shanghai/japan/singapore → 云雁仓库,along → 阿龙仓库;需与 prod-build.sh 所选公司一致。 +# 应用: 见 APPS(默认 voitrans) 区域: along +# 镜像仓库跟区域走:along → 阿龙仓库 registry.ymaikj.com;需与 prod-build.sh 所选公司一致。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -33,8 +36,8 @@ red() { printf "\033[31m%s\033[0m\n" "$*"; } yellow(){ printf "\033[33m%s\033[0m\n" "$*"; } # ── 私有仓库凭据(写死;公开仓库前清空 REGISTRY_PASS)── -# 镜像仓库按「区域所属公司」自动选(见 region_profile 里的 REGION_COMPANY:三个云雁区域走 yunyan, -# 阿龙区域走 along 自己的 registry.ymaikj.com),也可用环境变量强制指定:COMPANY=lingpu ./prod-deploy.sh … +# 镜像仓库按「区域所属公司」自动选(见 region_profile 里的 REGION_COMPANY:along 走自己的 +# registry.ymaikj.com),也可用环境变量强制指定:COMPANY=lingpu ./prod-deploy.sh … # 所选公司必须与 prod-build.sh 构建时所选公司一致,否则拉不到镜像。 COMPANY_OVERRIDE="${COMPANY:-}" # 环境变量显式指定的公司;留空 = 跟区域走 # 共用镜像:所有应用都用这一个。名字走 prod_image_name(),与 prod-build.sh 同源,防漂移。 @@ -79,29 +82,11 @@ DEFAULT_APP="${APPS[0]%%|*}" # 省略应用时的默认(首个) # ║ 写死在此(本文件纳入 git)。公开仓库前清空 HOST/KEY。 ║ # ║ 新增区域:在 region_profile 加一段 case,并把区域名加进 REGIONS 数组。 ║ # ╚══════════════════════════════════════════════════════════════════════╝ -REGIONS=(shanghai japan singapore along) # 可选环境/区域(交互菜单按此顺序展示) +REGIONS=(along) # 可选环境/区域(目前只剩阿龙;云雁三地已于 2026-09-13 移除,见文件头说明) region_profile() { # 远端部署目录/容器名由「应用」决定(见 APPS),此处只管各区域服务器连接信息 - REGION_COMPANY="$DEFAULT_COMPANY" # 该区域镜像仓库所属公司(默认云雁;可被环境变量 COMPANY 覆盖) + REGION_COMPANY="$DEFAULT_COMPANY" # 该区域镜像仓库所属公司(可被环境变量 COMPANY 覆盖;along 段下面会改写成 along) case "$REGION" in - shanghai) - DEPLOY_HOST="139.224.212.237" # ← 上海生产服务器 IP(必填) - DEPLOY_PORT=22 - DEPLOY_USER=root - DEPLOY_KEY="/Users/liwei1dao/work/密钥/release_shanghai.pem" # ← 上海服务器 SSH 私钥(各区域不同) - ;; - japan) - DEPLOY_HOST="8.216.34.101" # ← 日本生产服务器 IP(必填) - DEPLOY_PORT=22 - DEPLOY_USER=root - DEPLOY_KEY=/Users/liwei/Documents/key/aliyun_japan.pem # ← 日本服务器 SSH 私钥(各区域不同) - ;; - singapore) - DEPLOY_HOST="47.84.198.24" # ← 新加坡生产服务器 IP(必填) - DEPLOY_PORT=22 - DEPLOY_USER=root - DEPLOY_KEY=/Users/liwei/Documents/key/alibaba_singapore.pem # ← 新加坡服务器 SSH 私钥(各区域不同) - ;; along) DEPLOY_HOST="47.116.104.181" # ← 阿龙生产服务器 IP DEPLOY_PORT=22 @@ -135,7 +120,7 @@ usage() { ./prod-deploy.sh 0.1.4 # 只给版本 → 交互里选应用、区域 ./prod-deploy.sh ym along # 给应用+区域 → 交互里选版本(会列出仓库里已有的 tag) ./prod-deploy.sh ym along rollback # ym 阿龙回滚到上一版本 - ./prod-deploy.sh shanghai 0.1.1 # 省略应用 → 默认首个应用(${DEFAULT_APP:-?}) + ./prod-deploy.sh along 0.2.1 # 省略应用 → 默认首个应用(${DEFAULT_APP:-?}) 提示: 不带参数(或参数不全)运行将进入交互式引导,逐步选择应用 / 环境 / 版本。 EOF @@ -148,6 +133,9 @@ EOF case "${1:-}" in -h|--help|help) usage; exit 0 ;; esac is_region() { local r; for r in "${REGIONS[@]}"; do [ "$r" = "$1" ] && return 0; done; return 1; } +# 2026-09-13 移除的区域名:它们是普通串,会被 is_tag_like 当成 tag 吃掉, +# 报出「版本指定了两次」这种驴唇不对马嘴的错。这里当场点明,省得对着参数解析找半天。 +is_removed_region() { case "$1" in shanghai|japan|singapore) return 0 ;; *) return 1 ;; esac; } is_tag_like() { case "$1" in ''|*[!A-Za-z0-9._-]*) return 1 ;; *) return 0 ;; esac; } APP_KEY=""; REGION=""; TAG_ARG=""; MODE=""; INTERACTIVE=0 @@ -155,6 +143,12 @@ for a in "$@"; do if is_app "$a"; then [ -z "$APP_KEY" ] || { red "✗ 应用指定了两次: $APP_KEY / $a"; exit 1; } APP_KEY="$a" + elif is_removed_region "$a"; then + # ⚠️ 变量名必须写成 ${a} 而不是 $a:紧跟其后的是多字节的「」,在非 UTF-8 locale 下 + # bash 会把它的首字节并进变量名,报出 `a?: unbound variable`(set -u)。 + red "✗ 区域「${a}」已于 2026-09-13 从本脚本移除(云雁三地的 SSH 私钥在另一台开发机上,本机连不上)。" + red " 现可用区域: ${REGIONS[*]}。需要恢复请从 git 历史取回 region_profile 对应段。" + exit 1 elif is_region "$a"; then [ -z "$REGION" ] || { red "✗ 区域指定了两次: $REGION / $a"; exit 1; } REGION="$a" diff --git a/deploy/console/README.md b/deploy/console/README.md index 08bfc1df..a4713fd5 100644 --- a/deploy/console/README.md +++ b/deploy/console/README.md @@ -18,7 +18,7 @@ | `env/env.example` | 运行时环境**模板**(只一份,不分环境);真实 `.env` 被 gitignore | | `dev-deploy.sh` | **开发**:构建 dev 镜像 → 推送 → 远端拉取重启(固定 tag `dev-latest`) | | `prod-build.sh` | **生产①**:构建带版本号镜像并推送(`:版本` + `:latest`),不部署 | -| `prod-deploy.sh` | **生产②**:部署指定版本到指定生产环境(`yunyan`/`lingpu`),支持回滚 | +| `prod-deploy.sh` | **生产②**:部署指定版本到生产环境(目前只有 `along`),支持回滚 | ## 用法 @@ -51,12 +51,12 @@ docker compose --env-file .env up -d # 本机起 starpivot-console ```bash cd deploy/console -./dev-deploy.sh lingpu # 开发:发布到灵谱测试环境(构建 dev-latest → 推送 → 远端拉取重启) +./dev-deploy.sh along # 开发:发布到阿龙测试环境(构建 dev-latest → 推送 → 远端拉取重启) ./dev-deploy.sh yunyan # 开发:发布到云雁测试环境 ./dev-deploy.sh # 不带参数 → 交互选择测试环境 ./prod-build.sh 0.1.1 yunyan # 生产①:构建并推送 starpivot-console:0.1.1 (+latest);第2参数选公司 -./prod-deploy.sh 0.1.1 lingpu # 生产②:部署 0.1.1 到指定生产环境(yunyan|lingpu|along),省略环境则交互选 -./prod-deploy.sh rollback lingpu # 生产回滚到上一版本(与当前版本来回切换) +./prod-deploy.sh 0.2.1 along # 生产②:部署 0.2.1 到生产环境(目前只有 along,省略即用它) +./prod-deploy.sh rollback along # 生产回滚到上一版本(与当前版本来回切换) ``` > 改了服务器上的 `.env` 后,必须经 `up`(脚本里的 `docker compose up -d`)**重建容器**才生效,`restart` 不会重读环境变量。 @@ -64,7 +64,7 @@ cd deploy/console ## 需要填写 / 提供的东西 -- **部署目标与凭据**:写死在各脚本顶部。`dev-deploy.sh` 的 `env_profile()`(每个测试环境一套 `REGISTRY/DEV_HOST/DEV_KEY/DEV_DIR`,现有 `lingpu`、`yunyan`、`along`;新增环境加一段 case 并写进 `ENVS`)、`prod-deploy.sh` 的 `env_profile()`(每个生产环境一套 `REGISTRY/IMAGE_NAME/DEPLOY_HOST/DEPLOY_KEY/DEPLOY_DIR`,现有 `yunyan`、`lingpu`、`along`;新增环境加一段 case 并写进 `PROD_ENVS`); +- **部署目标与凭据**:写死在各脚本顶部。`dev-deploy.sh` 的 `env_profile()`(每个测试环境一套 `REGISTRY/DEV_HOST/DEV_KEY/DEV_DIR`,**目前只有 `along`**;新增环境加一段 case 并写进 `ENVS`)、`prod-deploy.sh` 的 `env_profile()`(每个生产环境一套 `REGISTRY/IMAGE_NAME/DEPLOY_HOST/DEPLOY_KEY/DEPLOY_DIR`,**目前只有 `along`**;新增环境加一段 case 并写进 `PROD_ENVS`); 仓库账号 `admin` / 密码已写死;`DEPLOY_KEY` 默认 `~/.ssh/id_rsa`。 - ⚠️ 本目录脚本纳入 git,**公开仓库前务必清空** `*_HOST` 与 `REGISTRY_PASS`。 - **依赖端点**:填服务器 `.env` 的 `POSTGRES_DSN / REDIS_* / NATS_URL`,以及 `CONSOLE_TOKEN_KEY`、 diff --git a/deploy/console/dev-deploy.sh b/deploy/console/dev-deploy.sh index 21cb83d7..45840d35 100755 --- a/deploy/console/dev-deploy.sh +++ b/deploy/console/dev-deploy.sh @@ -6,13 +6,14 @@ # (照着仓库里的 env/env.example、confs/console.yaml.example 在服务器上放好真实文件),本脚本不上传任何配置。 # # 用法(在 deploy/console/ 下): -# ./dev-deploy.sh lingpu # 发布到灵谱测试环境 -# ./dev-deploy.sh yunyan # 发布到云雁测试环境 # ./dev-deploy.sh along # 发布到阿龙测试环境 -# ./dev-deploy.sh # 不带参数 → 交互选择环境(无 TTY 时用默认环境 lingpu) +# ./dev-deploy.sh # 不带参数 → 交互选择环境(目前只有 along 一个,无 TTY 时也用它) # # 开发版镜像始终使用固定 tag dev-latest,每次构建覆盖同一 tag。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # deploy/console REPO_ROOT="$(cd "$SVC_DIR/../.." && pwd)" # 仓库根 @@ -34,27 +35,13 @@ IMAGE_NAME="starpivot-console" # 业务镜像名 # ║ ⚠️ 公开仓库前务必清空 DEV_HOST / REGISTRY_PASS ║ # ║ 新增环境:在 env_profile 加一段 case,并把环境名加进 ENVS 数组。 ║ # ╚══════════════════════════════════════════════════════════════════════╝ -ENVS=(lingpu yunyan along) # 可选测试环境(交互菜单按此顺序展示) -DEFAULT_ENV="lingpu" # 无参数且无 TTY(CI/管道)时的默认环境 +ENVS=(along) # 可选测试环境(目前只剩阿龙;云雁/灵谱已于 2026-09-13 移除,见文件头说明) +DEFAULT_ENV="along" # 无参数且无 TTY(CI/管道)时的默认环境 env_profile() { DEV_PORT=22 # 各环境通用默认 DEV_USER=root case "$DEV_ENV" in - lingpu) - ENV_DESC="灵谱 · 香港阿里云 (lingpu-hk)" - registry_profile lingpu # 镜像仓库:灵谱 - DEV_HOST="8.217.193.140" # ← 灵谱测试服务器 IP - DEV_KEY=/Users/liwei/Documents/灵谱/lingpu-hk.pem # 本机访问该服务器的 SSH 私钥 - DEV_DIR="/home/work/starpivot/console" # 远端部署目录(其中 docker-compose.yml/.env/confs 由你自己维护) - ;; - yunyan) - ENV_DESC="云雁测试环境 · 广州阿里云" - registry_profile yunyan # 镜像仓库:云雁(registry.voitrans.net,就在这台机上) - DEV_HOST="8.138.86.223" # ← 云雁测试服务器 IP(2026-07 由腾讯云 124.222.232.218 迁来) - DEV_KEY="/Users/liwei1dao/work/密钥/dev-guangzhou.pem" # 本机访问该服务器的 SSH 私钥(2026-08-18 由 ~/.ssh/aliyun_guangzhou.pem 迁到此处) - DEV_DIR="/home/work/starpivot/console" - ;; along) ENV_DESC="阿龙测试环境 · 阿里云" registry_profile along # 镜像仓库:就在这台机上(registry.ymaikj.com,账号 admin) @@ -73,8 +60,6 @@ usage() { 用法: ./dev-deploy.sh [环境] (在 deploy/console/ 下运行) 环境 : ${ENVS[*]// /, }(省略则交互选择;无 TTY 时用默认 ${DEFAULT_ENV}) 例: - ./dev-deploy.sh lingpu # 发布到灵谱测试环境 - ./dev-deploy.sh yunyan # 发布到云雁测试环境 ./dev-deploy.sh along # 发布到阿龙测试环境 EOF } diff --git a/deploy/console/prod-deploy.sh b/deploy/console/prod-deploy.sh index cc49ad3b..3d65e534 100755 --- a/deploy/console/prod-deploy.sh +++ b/deploy/console/prod-deploy.sh @@ -6,11 +6,14 @@ # (照着仓库里的 env/env.example、confs/console.yaml.example 在服务器上放好真实文件),本脚本不上传任何配置。 # # 用法(在 deploy/console/ 下): -# ./prod-deploy.sh [环境] # 部署指定版本,如 ./prod-deploy.sh 0.1.1 lingpu +# ./prod-deploy.sh [环境] # 部署指定版本,如 ./prod-deploy.sh 0.1.1 along # ./prod-deploy.sh rollback [环境] # 回滚到上一次部署版本(与当前版本来回切换) -# 环境 = yunyan(上海)| lingpu(广州)| along(阿龙 47.116.104.181);省略 → 交互选择,无 TTY 时用默认 yunyan。 +# 环境 = along(阿龙 47.116.104.181);省略 → 直接用它。 # ⚠️ 环境必须与 prod-build.sh 构建时所选公司一致,否则拉不到镜像。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 SVC_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" @@ -32,30 +35,13 @@ DOCKER_NETWORK="1panel-network" # compose 外部网络名(与服务 # 容器名:必须与 docker-compose.yml 的 container_name 一字不差(本脚本会上传覆盖那份 compose)。 # 仅用于 up 冲突时清理同名遗留容器;不随环境变化。 CONTAINER_NAME="starpivot-console" -PROD_ENVS=(yunyan lingpu along) # 可选生产环境(交互菜单按此顺序展示) -DEFAULT_PROD_ENV="yunyan" # 无参数且无 TTY(CI/管道)时的默认环境 +PROD_ENVS=(along) # 可选生产环境(目前只剩阿龙;云雁/灵谱已于 2026-09-13 移除,见文件头说明) +DEFAULT_PROD_ENV="along" # 无参数且无 TTY(CI/管道)时的默认环境 env_profile() { DEPLOY_PORT=22 # 各环境通用默认 DEPLOY_USER=root case "$DEPLOY_ENV" in - yunyan) - # 2026-08-05 起 console 生产目标改为上海机(与业务后端 app 同机)。 - # 旧目标:美国机 47.253.88.66,其上 console-a11:0.1.1 容器仍在跑,待新环境验证后再停; - # 需要临时回连那台时,把下面三行换成 47.253.88.66 / yunyan-us.pem / /home/work/console-a11。 - ENV_DESC="云雁生产环境 · 上海阿里云" - registry_profile yunyan || return 1 # 镜像仓库:云雁 - DEPLOY_HOST="139.224.212.237" # ← 云雁生产服务器 IP(上海) - DEPLOY_KEY="/Users/liwei1dao/work/密钥/release_shanghai.pem" - DEPLOY_DIR="/home/work/starpivot/console" # 远端部署目录(其中 docker-compose.yml/.env/confs 由你自己维护) - ;; - lingpu) - ENV_DESC="灵谱生产环境 · 广州阿里云 (lingpu-gz)" - registry_profile lingpu || return 1 # 镜像仓库:灵谱(registry.lingpu.net,实体在香港机) - DEPLOY_HOST="8.166.114.65" # ← 灵谱生产服务器 IP - DEPLOY_KEY=~/.ssh/lingpu-gz.pem # 私钥放 ~/.ssh:~/Documents 会被 macOS TCC 挡住读不出来 - DEPLOY_DIR="/home/work/starpivot/console" - ;; along) ENV_DESC="阿龙生产环境 · 阿里云" registry_profile along || return 1 # 镜像仓库:registry.ymaikj.com(实体在阿龙测试机 8.133.166.29,账号 admin) @@ -72,7 +58,7 @@ env_host_of() { ( DEPLOY_ENV="$1" env_profile >/dev/null 2>&1; printf '%s' "${DE # ── 参数: [环境] ── ARG1="${1:-}" -[ -n "$ARG1" ] || { red "用法: ./prod-deploy.sh [环境](如 0.1.1 lingpu)"; exit 1; } +[ -n "$ARG1" ] || { red "用法: ./prod-deploy.sh [环境](如 0.1.1 along)"; exit 1; } if [ "$ARG1" = "rollback" ]; then MODE="rollback"; NEW_TAG=""; else MODE="deploy"; NEW_TAG="$ARG1"; fi DEPLOY_ENV="${2:-}" diff --git a/deploy/dev-deploy-all.sh b/deploy/dev-deploy-all.sh index ee66d1fa..0b7b9a2e 100755 --- a/deploy/dev-deploy-all.sh +++ b/deploy/dev-deploy-all.sh @@ -8,7 +8,6 @@ # 用法(在 deploy/ 下): # ./dev-deploy-all.sh # 交互选公司(环境),发布全部三个服务 # ./dev-deploy-all.sh along # 发布全部服务到阿龙测试环境 -# ./dev-deploy-all.sh yunyan app admin # 只发 app 和 admin 到云雁测试环境 # ./dev-deploy-all.sh along -y -k # 不确认、失败也继续发后面的服务 # # 发布顺序固定 app → console → admin:admin 的页面要连 console,console 又依赖业务库, @@ -17,6 +16,9 @@ # ⚠️ macOS 自带 bash 3.2 不认多字节字符边界,`"$rc)"` 会被当成变量名 `rc)` 而在 set -u 下 # 报 unbound variable。所以本文件里凡是变量后面紧跟中文标点的,一律写成 ${rc}。 set -euo pipefail +# ⚠️ 2026-09-13:云雁(yunyan)/灵谱(lingpu) 的部署目标已从本脚本移除——本仓库的部署目标只剩阿龙。 +# 移除的是「往哪台服务器部署」,**镜像仓库没动**:prod-build.sh 仍可选 yunyan/lingpu 推镜像。 +# 要恢复:git log 里找回对应的 env_profile/region_profile 段即可(含 IP 与各自的 SSH 私钥路径)。 DEPLOY_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 仓库的 deploy/ source "$DEPLOY_ROOT/registry-profiles.sh" # 公司 → 仓库地址/账号 @@ -28,8 +30,8 @@ red() { printf "\033[31m%s\033[0m\n" "$*"; } # 可选公司(测试环境)。名字与各服务 dev-deploy.sh 的 ENVS 一致,脚本启动时会交叉校验, # 一边加了新环境另一边忘了加时会直接报错,不会发到一半才炸。 -ENVS=(lingpu yunyan along) -DEFAULT_ENV="lingpu" # 无参数且无 TTY(CI/管道)时用它 +ENVS=(along) +DEFAULT_ENV="along" # 无参数且无 TTY(CI/管道)时用它 ALL_SVCS=(app console admin) # 默认发布顺序 usage() { @@ -47,7 +49,6 @@ usage() { 例: ./dev-deploy-all.sh along # 全量发到阿龙测试环境 - ./dev-deploy-all.sh yunyan console # 只把 console 发到云雁测试环境 EOF } diff --git a/deploy/registry-profiles.sh b/deploy/registry-profiles.sh index 74e80536..8d79544b 100644 --- a/deploy/registry-profiles.sh +++ b/deploy/registry-profiles.sh @@ -21,13 +21,13 @@ registry_profile() { case "${1:-}" in yunyan) COMPANY_DESC="云雁" - REGISTRY="registry.voitrans.net" # 仓库实体在广州机 8.138.86.223(1Panel OpenResty 反代 → docker-registry:5000) + REGISTRY="registry.voitrans.net" # 云雁自有仓库(1Panel OpenResty 反代 → docker-registry:5000) REGISTRY_USER="liwei" REGISTRY_PASS="li13451234" ;; lingpu) COMPANY_DESC="灵谱" - REGISTRY="registry.lingpu.net" # 仓库实体在灵谱香港机 8.217.193.140 + REGISTRY="registry.lingpu.net" # 灵谱自有仓库 REGISTRY_USER="liwei" REGISTRY_PASS="li13451234" ;; @@ -50,7 +50,6 @@ registry_profile() { # # admin/console:各公司都用 starpivot-* 新命名,与 docker-compose.yml 里写死的 image/container_name # 一致。云雁的 admin/console 生产目标已于 2026-08-05 迁到上海机(那台没有历史容器), -# 旧名 yunyan-admin / console-a11 只留在待下线的美国机 47.253.88.66 上,不再由脚本部署。 # app:2026-08-10 起统一为 starpivot-app。旧名 voitrans-a11 已废弃——仓库里的旧 tag 不再更新, # 首次用新名部署需先 ./prod-build.sh 推一版(旧 tag 不会自动搬过来)。 # diff --git a/docs/运维-容器断网与免费证书排查.md b/docs/运维-容器断网与免费证书排查.md index 3308525e..3e18416a 100644 --- a/docs/运维-容器断网与免费证书排查.md +++ b/docs/运维-容器断网与免费证书排查.md @@ -1,6 +1,6 @@ # 运维排查记录:容器无法访问外网 + NPM 免费证书签发 -> 场景:阿里云 ECS(lingpu-hk 8.217.193.140),Nginx Proxy Manager(NPM)容器化部署, +> 场景:阿里云 ECS,Nginx Proxy Manager(NPM)容器化部署, > 给 starpivot-dev.lingpu.net 申请 Let's Encrypt 证书(阿里云 DNS challenge)。 > 记录于 2026-07-22。