diff --git a/.gitea/workflows/sync-consul.yml b/.gitea/workflows/sync-consul.yml index c0f64fc..7df673d 100644 --- a/.gitea/workflows/sync-consul.yml +++ b/.gitea/workflows/sync-consul.yml @@ -1,15 +1,10 @@ -# push 到 main/master → 渲染密钥 → 写入 Consul → 重启相关 API -# 触发方式与 api/front 一致(不做 paths 过滤,避免「推了却不跑」) +# 复制到配置仓 .gitea/workflows/sync-consul.yml +# push master → prod Consul;push test → test Consul name: Sync Consul Config on: push: - branches: [master, main] - paths: - - "idwms/**" - - "scripts/**" - - ".gitea/workflows/sync-consul.yml" - workflow_dispatch: + branches: [master, test] jobs: sync: @@ -18,20 +13,37 @@ jobs: - name: Checkout and sync run: | set -euxo pipefail - export KUBECONFIG=/etc/rancher/k3s/k3s.yaml - export NAMESPACE=prod + REF="${{ gitea.ref_name }}" + case "$REF" in + test) TARGET=test ;; + master) TARGET=prod ;; + *) echo "unsupported branch: $REF"; exit 1 ;; + esac + + case "$TARGET" in + test) + export KUBECONFIG=/root/.kube/k3s-test.yaml + export NAMESPACE=test + ;; + *) + export KUBECONFIG=/etc/rancher/k3s/k3s.yaml + export NAMESPACE=prod + ;; + esac + test -f "$KUBECONFIG" + export RESTART_APIS=1 REPO="${{ gitea.repository }}" - REPO="${REPO:-${{ github.repository }}}" SHA="${{ gitea.sha }}" - SHA="${SHA:-${{ github.sha }}}" test -n "$REPO" && [[ "$REPO" == */* ]] test -n "$SHA" + echo "TARGET=$TARGET REF=$REF NAMESPACE=$NAMESPACE" + GITEA_HTTP="https://git.ideship.com" - WORK="/data/ci-build/config" - GITEA_USER="$(kubectl -n prod get secret kaniko-git -o jsonpath='{.data.GITEA_USER}' | base64 -d)" - GIT_TOKEN="$(kubectl -n prod get secret kaniko-git -o jsonpath='{.data.GIT_TOKEN}' | base64 -d)" + WORK="/data/ci-build/config-${TARGET}" + GITEA_USER="$(kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml -n prod get secret kaniko-git -o jsonpath='{.data.GITEA_USER}' | base64 -d)" + GIT_TOKEN="$(kubectl --kubeconfig=/etc/rancher/k3s/k3s.yaml -n prod get secret kaniko-git -o jsonpath='{.data.GIT_TOKEN}' | base64 -d)" GITEA_USER="${GITEA_USER:-gitea}" rm -rf "$WORK" diff --git a/README.md b/README.md index 6f1005e..95c8989 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,15 @@ Gitea 仓保存 `idwms/*.json` → CI 用 K8s Secret 渲染密码 → `PUT` 到 应用仍只读 Consul(`AddConsul("idwms/...")`),不读本仓库。 +## 分支 → 环境 + +| 分支 | 集群 | Namespace | 前端 CORS | +|------|------|-----------|-----------| +| `master` | prod(134) | `prod` | `https://ideship.com` | +| `test` | test(13) | `test` | `https://app.test.ideship.com` | + +`test` 分支里中间件地址应为 `*.test.svc.cluster.local`;`master` 为 `*.prod.svc.cluster.local`。 + ## 目录 | 文件 | Consul KV | @@ -13,26 +22,27 @@ Gitea 仓保存 `idwms/*.json` → CI 用 K8s Secret 渲染密码 → `PUT` 到 | `idwms/itfxapi.json` | `idwms/itfxapi` | | `idwms/trackapi.json` | `idwms/trackapi` | -JSON 里敏感字段用占位符,例如 `${MYSQL_ROOT_PASSWORD}`。同步时从 `prod-credentials` / `jwt-secret` 注入,**明文密码不进 git**。 +JSON 里敏感字段用占位符,例如 `${MYSQL_ROOT_PASSWORD}`。同步时从对应 namespace 的 `prod-credentials` / `jwt-secret` 注入,**明文密码不进 git**。 ## 一次性准备 -### 1. JWT(业务 API 用,中间件 Secret 里没有) - -在 k3s 节点: +### 1. JWT(业务 API 用) ```bash +# prod kubectl -n prod create secret generic jwt-secret \ --from-literal=JWT_SECRET_KEY='请换成足够长的随机串' \ --dry-run=client -o yaml | kubectl apply -f - + +# test(也可用 secrets.yaml 里 prod-credentials 的 JWT_SECRET_KEY) +kubectl --kubeconfig=/root/.kube/k3s-test.yaml -n test \ + create secret generic jwt-secret \ + --from-literal=JWT_SECRET_KEY='ideship-jwt-secret-test-change-me' \ + --dry-run=client -o yaml | kubectl apply -f - ``` -也可把 `JWT_SECRET_KEY` 加进现有 `manifests/secrets.yaml` 的 `prod-credentials`。 - ### 2. (可选)Consul ACL Token -若已开 ACL: - ```bash kubectl -n prod create secret generic consul-acl \ --from-literal=CONSUL_HTTP_TOKEN='...' \ @@ -43,50 +53,49 @@ kubectl -n prod create secret generic consul-acl \ ```bash cd d:/my/itfx/config -git remote add origin https://git.ideship.com//config.git -git add -A && git commit -m "chore: initial consul config repo" -git push -u origin master +git push -u origin master # → prod Consul +git push -u origin test # → test Consul ``` -在 Gitea 启用 Actions,确保 runner 标签含 `k3s-host`(与 API 部署相同)。 +Runner 标签需含 `k3s-host`;134 上需有 `/root/.kube/k3s-test.yaml`。 ### 4. 与线上对账(推荐先做) -在能 `kubectl` 的机器上: - ```bash +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml +export NAMESPACE=prod ./scripts/export-from-consul.sh -# 把导出文件里的密码改回 ${MYSQL_ROOT_PASSWORD} 等占位符后再提交 +# 把导出文件里的密码改回 ${MYSQL_ROOT_PASSWORD} 等占位符后再提交到 master ``` -避免模板库名/字段和现网不一致,第一次同步把线上冲掉。 - ## 日常 -改 JSON → push `main`/`master` → workflow `Sync Consul Config` 自动同步并 `rollout restart` 对应 API。 +改 JSON → push `master` / `test` → workflow 按分支写入对应 Consul 并 `rollout restart`。 手动: ```bash -export KUBECONFIG=/etc/rancher/k3s/k3s.yaml -./scripts/sync-to-consul.sh # 全部 -RESTART_APIS=1 ./scripts/sync-to-consul.sh admin +# prod +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml NAMESPACE=prod +./scripts/sync-to-consul.sh + +# test +export KUBECONFIG=/root/.kube/k3s-test.yaml NAMESPACE=test +./scripts/sync-to-consul.sh ``` ## 密钥来源 -| 占位符 | Secret | -|--------|--------| +| 占位符 | Secret(在目标 NAMESPACE 内) | +|--------|------------------------------| | `${MYSQL_ROOT_PASSWORD}` | `prod-credentials` | | `${REDIS_PASSWORD}` | `prod-credentials` | | `${RABBITMQ_DEFAULT_PASS}` | `prod-credentials` | | `${ELASTIC_PASSWORD}` | `prod-credentials` | | `${JWT_SECRET_KEY}` | `jwt-secret` 或 `prod-credentials` | -与 `k3s/manifests/secrets.yaml` 一致:中间件用 Secret;本仓只存带占位符的业务配置模板。 - ## 注意 -- `App:CorsOrigins` 在启动时打进 CORS 策略,改完必须重启 API(CI 默认会 restart)。 -- 首次用仓库模板前务必 `export-from-consul` 对过现网,或确认 MySQL 库名(`oms` / `itfx` / `track`)正确。 -- Consul 保持 ClusterIP,CI 经节点访问 Service ClusterIP,不暴露公网。 +- `App:CorsOrigins` 改完必须重启 API(CI 默认会 restart)。 +- COS 等共享公网地址可两端相同;库名/中间件 DNS 必须按环境分开。 +- Consul 保持 ClusterIP,CI 经节点访问 Service ClusterIP。 diff --git a/idwms/admin.json b/idwms/admin.json index 070a84d..28da580 100644 --- a/idwms/admin.json +++ b/idwms/admin.json @@ -2,18 +2,15 @@ "App": { "Urls": [ "http://*:5281" - ], - "CorsOrigins": [ - "https://ideship.com" ] }, "AllowedHosts": "*", "ConnectionStrings": { - "Default": "server=mysql.prod.svc.cluster.local;database=fake_simple_admin;uid=dev;pwd=itd!@#123;charset=utf8mb4;", - "Rbac": "server=mysql.prod.svc.cluster.local;database=fake_simple_admin;uid=dev;pwd=itd!@#123;charset=utf8mb4;" + "Default": "server=mysql.test.svc.cluster.local;database=fake_simple_admin;uid=dev;pwd=itd!@#123;charset=utf8mb4;", + "Rbac": "server=mysql.test.svc.cluster.local;database=fake_simple_admin;uid=dev;pwd=itd!@#123;charset=utf8mb4;" }, "Redis": { - "Host": "redis.prod.svc.cluster.local:6379", + "Host": "redis.test.svc.cluster.local:6379", "Password": "itd!@#123", "MaxPoolSize": 1000, "Database": 0, @@ -22,7 +19,7 @@ "RabbitMQ": { "Connections": { "Default": { - "HostName": "rabbitmq.prod.svc.cluster.local", + "HostName": "rabbitmq.test.svc.cluster.local", "Port": 5672, "UserName": "rabbit", "Password": "itd!@#123", @@ -46,7 +43,7 @@ "Secret": "379f51a89419dc36fbb9167feef6f89a", "Token": "c6ca74013df823c0e1da0feaaaf8bf66", "EncodingAesKey": "", - "OAuthRedirectBase": "https://ideship.com" + "OAuthRedirectBase": "https://app.test.ideship.com" } }, "FileStorage": { @@ -57,17 +54,17 @@ "Oms": { "TrackService": { "Enabled": true, - "BaseUrl": "http://api.ideship.com/track", + "BaseUrl": "https://api.test.ideship.com/track", "AppKey": "W2606001", "AppSecret": "ziK8UzlQ39m3kdL346XEBg8nljY8os52", "TimeoutSeconds": 30 }, "Itfx": { - "BaseUrl": "http://api.ideship.com/itfx", + "BaseUrl": "https://api.test.ideship.com/itfx", "TimeoutSeconds": 30 }, "PlatformShop": { - "FrontendBaseUrl": "http://localhost:5173", + "FrontendBaseUrl": "https://app.test.ideship.com", "Lazada": { "AppKey": "123631", "AppSecret": "7vBz2EaD6rIupeGEfwrgkabsTNsXt2ix", diff --git a/idwms/common.json b/idwms/common.json index b97fd2d..4280165 100644 --- a/idwms/common.json +++ b/idwms/common.json @@ -1,7 +1,7 @@ { "App": { "CorsOrigins": [ - "https://ideship.com" + "https://test.ideship.com" ] }, "Serilog": { diff --git a/idwms/itfxapi.json b/idwms/itfxapi.json index 9482904..bd54a89 100644 --- a/idwms/itfxapi.json +++ b/idwms/itfxapi.json @@ -19,10 +19,10 @@ "KeyPrefix": "itfx" }, "ConnectionStrings": { - "Default": "server=mysql.prod.svc.cluster.local;database=interface_forward;uid=dev;pwd=itd!@#123;charset=utf8mb4;" + "Default": "server=mysql.test.svc.cluster.local;database=interface_forward;uid=dev;pwd=itd!@#123;charset=utf8mb4;" }, "Redis": { - "Host": "redis.prod.svc.cluster.local:6379", + "Host": "redis.test.svc.cluster.local:6379", "Password": "itd!@#123", "MaxPoolSize": 1000, "Database": 0, @@ -31,7 +31,7 @@ "RabbitMQ": { "Connections": { "Default": { - "HostName": "rabbitmq.prod.svc.cluster.local", + "HostName": "rabbitmq.test.svc.cluster.local", "Port": 5672, "UserName": "rabbit", "Password": "itd!@#123", @@ -40,7 +40,7 @@ } }, "ElasticSearch": { - "NodeUrls": [ "http://es.prod.svc.cluster.local:9200" ], + "NodeUrls": [ "http://es.test.svc.cluster.local:9200" ], "LoginName": "elastic", "Password": "itd!@#123", "ShowLogInfo": false, diff --git a/idwms/trackapi.json b/idwms/trackapi.json index 24452fa..33e9d3b 100644 --- a/idwms/trackapi.json +++ b/idwms/trackapi.json @@ -10,15 +10,15 @@ "OrderPullStatusScanInterval": 60, "TrackButtomUpScanInterval":600, "WarningNotifyUrl": "http://xxxx", - "ItfxBaseAddress": "http://interfaceforward-api.prod.svc.cluster.local:8888/", + "ItfxBaseAddress": "http://interfaceforward-api.test.svc.cluster.local:8888/", "TrackPullTaskLevel": 0, "TrackPullTaskMinuteInterval": 5 }, "ConnectionStrings": { - "Default": "server=mysql.prod.svc.cluster.local;database=track_center;uid=dev;pwd=itd!@#123;charset=utf8mb4;" + "Default": "server=mysql.test.svc.cluster.local;database=track_center;uid=dev;pwd=itd!@#123;charset=utf8mb4;" }, "Redis": { - "Host": "redis.prod.svc.cluster.local:6379", + "Host": "redis.test.svc.cluster.local:6379", "Password": "itd!@#123", "MaxPoolSize": 1000, "Database": 1, @@ -27,7 +27,7 @@ "RabbitMQ": { "Connections": { "Default": { - "HostName": "rabbitmq.prod.svc.cluster.local", + "HostName": "rabbitmq.test.svc.cluster.local", "Port": 5672, "UserName": "rabbit", "Password": "itd!@#123", @@ -36,14 +36,14 @@ } }, "ElasticSearch": { - "NodeUrls": [ "http://es.prod.svc.cluster.local:9200" ], + "NodeUrls": [ "http://es.test.svc.cluster.local:9200" ], "LoginName": "elastic", "Password": "itd!@#123", "ShowLogInfo": false, "IndexPrefix": "" }, "Kafka": { - "BootstrapServers": "kafka.prod.svc.cluster.local:9092", + "BootstrapServers": "kafka.test.svc.cluster.local:9092", "Consumer": { // 会话超时时间ms,超时时间未收到客户端心跳,则会移除该客户端同时触发自平衡 "SessionTimeoutMs": 45000,