init
Some checks failed
Sync Consul Config / sync (push) Failing after 0s

This commit is contained in:
xiaolipro 2026-09-21 16:17:39 +08:00
parent ff9d97c62a
commit 3cf8dd9ced
6 changed files with 83 additions and 65 deletions

View File

@ -1,15 +1,10 @@
# push 到 main/master → 渲染密钥 → 写入 Consul → 重启相关 API # 复制到配置仓 .gitea/workflows/sync-consul.yml
# 触发方式与 api/front 一致(不做 paths 过滤,避免「推了却不跑」) # push master → prod Consul;push test → test Consul
name: Sync Consul Config name: Sync Consul Config
on: on:
push: push:
branches: [master, main] branches: [master, test]
paths:
- "idwms/**"
- "scripts/**"
- ".gitea/workflows/sync-consul.yml"
workflow_dispatch:
jobs: jobs:
sync: sync:
@ -18,20 +13,37 @@ jobs:
- name: Checkout and sync - name: Checkout and sync
run: | run: |
set -euxo pipefail set -euxo pipefail
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml REF="${{ gitea.ref_name }}"
export NAMESPACE=prod 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="${{ gitea.repository }}"
REPO="${REPO:-${{ github.repository }}}"
SHA="${{ gitea.sha }}" SHA="${{ gitea.sha }}"
SHA="${SHA:-${{ github.sha }}}"
test -n "$REPO" && [[ "$REPO" == */* ]] test -n "$REPO" && [[ "$REPO" == */* ]]
test -n "$SHA" test -n "$SHA"
echo "TARGET=$TARGET REF=$REF NAMESPACE=$NAMESPACE"
GITEA_HTTP="https://git.ideship.com" GITEA_HTTP="https://git.ideship.com"
WORK="/data/ci-build/config" WORK="/data/ci-build/config-${TARGET}"
GITEA_USER="$(kubectl -n prod get secret kaniko-git -o jsonpath='{.data.GITEA_USER}' | base64 -d)" 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 -n prod get secret kaniko-git -o jsonpath='{.data.GIT_TOKEN}' | 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}" GITEA_USER="${GITEA_USER:-gitea}"
rm -rf "$WORK" rm -rf "$WORK"

View File

@ -4,6 +4,15 @@ Gitea 仓保存 `idwms/*.json` → CI 用 K8s Secret 渲染密码 → `PUT` 到
应用仍只读 Consul(`AddConsul("idwms/...")`),不读本仓库。 应用仍只读 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 | | 文件 | Consul KV |
@ -13,26 +22,27 @@ Gitea 仓保存 `idwms/*.json` → CI 用 K8s Secret 渲染密码 → `PUT` 到
| `idwms/itfxapi.json` | `idwms/itfxapi` | | `idwms/itfxapi.json` | `idwms/itfxapi` |
| `idwms/trackapi.json` | `idwms/trackapi` | | `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 里没有) ### 1. JWT(业务 API 用)
在 k3s 节点:
```bash ```bash
# prod
kubectl -n prod create secret generic jwt-secret \ kubectl -n prod create secret generic jwt-secret \
--from-literal=JWT_SECRET_KEY='请换成足够长的随机串' \ --from-literal=JWT_SECRET_KEY='请换成足够长的随机串' \
--dry-run=client -o yaml | kubectl apply -f - --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 ### 2. (可选)Consul ACL Token
若已开 ACL:
```bash ```bash
kubectl -n prod create secret generic consul-acl \ kubectl -n prod create secret generic consul-acl \
--from-literal=CONSUL_HTTP_TOKEN='...' \ --from-literal=CONSUL_HTTP_TOKEN='...' \
@ -43,50 +53,49 @@ kubectl -n prod create secret generic consul-acl \
```bash ```bash
cd d:/my/itfx/config cd d:/my/itfx/config
git remote add origin https://git.ideship.com/<org>/config.git git push -u origin master # → prod Consul
git add -A && git commit -m "chore: initial consul config repo" git push -u origin test # → test Consul
git push -u origin master
``` ```
在 Gitea 启用 Actions,确保 runner 标签含 `k3s-host`(与 API 部署相同)。 Runner 标签需含 `k3s-host`;134 上需有 `/root/.kube/k3s-test.yaml`。
### 4. 与线上对账(推荐先做) ### 4. 与线上对账(推荐先做)
在能 `kubectl` 的机器上:
```bash ```bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
export NAMESPACE=prod
./scripts/export-from-consul.sh ./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 ```bash
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml # prod
./scripts/sync-to-consul.sh # 全部 export KUBECONFIG=/etc/rancher/k3s/k3s.yaml NAMESPACE=prod
RESTART_APIS=1 ./scripts/sync-to-consul.sh admin ./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` | | `${MYSQL_ROOT_PASSWORD}` | `prod-credentials` |
| `${REDIS_PASSWORD}` | `prod-credentials` | | `${REDIS_PASSWORD}` | `prod-credentials` |
| `${RABBITMQ_DEFAULT_PASS}` | `prod-credentials` | | `${RABBITMQ_DEFAULT_PASS}` | `prod-credentials` |
| `${ELASTIC_PASSWORD}` | `prod-credentials` | | `${ELASTIC_PASSWORD}` | `prod-credentials` |
| `${JWT_SECRET_KEY}` | `jwt-secret` 或 `prod-credentials` | | `${JWT_SECRET_KEY}` | `jwt-secret` 或 `prod-credentials` |
与 `k3s/manifests/secrets.yaml` 一致:中间件用 Secret;本仓只存带占位符的业务配置模板。
## 注意 ## 注意
- `App:CorsOrigins` 在启动时打进 CORS 策略,改完必须重启 API(CI 默认会 restart)。 - `App:CorsOrigins` 改完必须重启 API(CI 默认会 restart)。
- 首次用仓库模板前务必 `export-from-consul` 对过现网,或确认 MySQL 库名(`oms` / `itfx` / `track`)正确。 - COS 等共享公网地址可两端相同;库名/中间件 DNS 必须按环境分开。
- Consul 保持 ClusterIP,CI 经节点访问 Service ClusterIP,不暴露公网。 - Consul 保持 ClusterIP,CI 经节点访问 Service ClusterIP。

View File

@ -2,18 +2,15 @@
"App": { "App": {
"Urls": [ "Urls": [
"http://*:5281" "http://*:5281"
],
"CorsOrigins": [
"https://ideship.com"
] ]
}, },
"AllowedHosts": "*", "AllowedHosts": "*",
"ConnectionStrings": { "ConnectionStrings": {
"Default": "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.prod.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": { "Redis": {
"Host": "redis.prod.svc.cluster.local:6379", "Host": "redis.test.svc.cluster.local:6379",
"Password": "itd!@#123", "Password": "itd!@#123",
"MaxPoolSize": 1000, "MaxPoolSize": 1000,
"Database": 0, "Database": 0,
@ -22,7 +19,7 @@
"RabbitMQ": { "RabbitMQ": {
"Connections": { "Connections": {
"Default": { "Default": {
"HostName": "rabbitmq.prod.svc.cluster.local", "HostName": "rabbitmq.test.svc.cluster.local",
"Port": 5672, "Port": 5672,
"UserName": "rabbit", "UserName": "rabbit",
"Password": "itd!@#123", "Password": "itd!@#123",
@ -46,7 +43,7 @@
"Secret": "379f51a89419dc36fbb9167feef6f89a", "Secret": "379f51a89419dc36fbb9167feef6f89a",
"Token": "c6ca74013df823c0e1da0feaaaf8bf66", "Token": "c6ca74013df823c0e1da0feaaaf8bf66",
"EncodingAesKey": "", "EncodingAesKey": "",
"OAuthRedirectBase": "https://ideship.com" "OAuthRedirectBase": "https://app.test.ideship.com"
} }
}, },
"FileStorage": { "FileStorage": {
@ -57,17 +54,17 @@
"Oms": { "Oms": {
"TrackService": { "TrackService": {
"Enabled": true, "Enabled": true,
"BaseUrl": "http://api.ideship.com/track", "BaseUrl": "https://api.test.ideship.com/track",
"AppKey": "W2606001", "AppKey": "W2606001",
"AppSecret": "ziK8UzlQ39m3kdL346XEBg8nljY8os52", "AppSecret": "ziK8UzlQ39m3kdL346XEBg8nljY8os52",
"TimeoutSeconds": 30 "TimeoutSeconds": 30
}, },
"Itfx": { "Itfx": {
"BaseUrl": "http://api.ideship.com/itfx", "BaseUrl": "https://api.test.ideship.com/itfx",
"TimeoutSeconds": 30 "TimeoutSeconds": 30
}, },
"PlatformShop": { "PlatformShop": {
"FrontendBaseUrl": "http://localhost:5173", "FrontendBaseUrl": "https://app.test.ideship.com",
"Lazada": { "Lazada": {
"AppKey": "123631", "AppKey": "123631",
"AppSecret": "7vBz2EaD6rIupeGEfwrgkabsTNsXt2ix", "AppSecret": "7vBz2EaD6rIupeGEfwrgkabsTNsXt2ix",

View File

@ -1,7 +1,7 @@
{ {
"App": { "App": {
"CorsOrigins": [ "CorsOrigins": [
"https://ideship.com" "https://test.ideship.com"
] ]
}, },
"Serilog": { "Serilog": {

View File

@ -19,10 +19,10 @@
"KeyPrefix": "itfx" "KeyPrefix": "itfx"
}, },
"ConnectionStrings": { "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": { "Redis": {
"Host": "redis.prod.svc.cluster.local:6379", "Host": "redis.test.svc.cluster.local:6379",
"Password": "itd!@#123", "Password": "itd!@#123",
"MaxPoolSize": 1000, "MaxPoolSize": 1000,
"Database": 0, "Database": 0,
@ -31,7 +31,7 @@
"RabbitMQ": { "RabbitMQ": {
"Connections": { "Connections": {
"Default": { "Default": {
"HostName": "rabbitmq.prod.svc.cluster.local", "HostName": "rabbitmq.test.svc.cluster.local",
"Port": 5672, "Port": 5672,
"UserName": "rabbit", "UserName": "rabbit",
"Password": "itd!@#123", "Password": "itd!@#123",
@ -40,7 +40,7 @@
} }
}, },
"ElasticSearch": { "ElasticSearch": {
"NodeUrls": [ "http://es.prod.svc.cluster.local:9200" ], "NodeUrls": [ "http://es.test.svc.cluster.local:9200" ],
"LoginName": "elastic", "LoginName": "elastic",
"Password": "itd!@#123", "Password": "itd!@#123",
"ShowLogInfo": false, "ShowLogInfo": false,

View File

@ -10,15 +10,15 @@
"OrderPullStatusScanInterval": 60, "OrderPullStatusScanInterval": 60,
"TrackButtomUpScanInterval":600, "TrackButtomUpScanInterval":600,
"WarningNotifyUrl": "http://xxxx", "WarningNotifyUrl": "http://xxxx",
"ItfxBaseAddress": "http://interfaceforward-api.prod.svc.cluster.local:8888/", "ItfxBaseAddress": "http://interfaceforward-api.test.svc.cluster.local:8888/",
"TrackPullTaskLevel": 0, "TrackPullTaskLevel": 0,
"TrackPullTaskMinuteInterval": 5 "TrackPullTaskMinuteInterval": 5
}, },
"ConnectionStrings": { "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": { "Redis": {
"Host": "redis.prod.svc.cluster.local:6379", "Host": "redis.test.svc.cluster.local:6379",
"Password": "itd!@#123", "Password": "itd!@#123",
"MaxPoolSize": 1000, "MaxPoolSize": 1000,
"Database": 1, "Database": 1,
@ -27,7 +27,7 @@
"RabbitMQ": { "RabbitMQ": {
"Connections": { "Connections": {
"Default": { "Default": {
"HostName": "rabbitmq.prod.svc.cluster.local", "HostName": "rabbitmq.test.svc.cluster.local",
"Port": 5672, "Port": 5672,
"UserName": "rabbit", "UserName": "rabbit",
"Password": "itd!@#123", "Password": "itd!@#123",
@ -36,14 +36,14 @@
} }
}, },
"ElasticSearch": { "ElasticSearch": {
"NodeUrls": [ "http://es.prod.svc.cluster.local:9200" ], "NodeUrls": [ "http://es.test.svc.cluster.local:9200" ],
"LoginName": "elastic", "LoginName": "elastic",
"Password": "itd!@#123", "Password": "itd!@#123",
"ShowLogInfo": false, "ShowLogInfo": false,
"IndexPrefix": "" "IndexPrefix": ""
}, },
"Kafka": { "Kafka": {
"BootstrapServers": "kafka.prod.svc.cluster.local:9092", "BootstrapServers": "kafka.test.svc.cluster.local:9092",
"Consumer": { "Consumer": {
// 会话超时时间ms,超时时间未收到客户端心跳,则会移除该客户端同时触发自平衡 // 会话超时时间ms,超时时间未收到客户端心跳,则会移除该客户端同时触发自平衡
"SessionTimeoutMs": 45000, "SessionTimeoutMs": 45000,