Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eb6612a7ea | |||
| bedd3a862e | |||
| eb4d9bb64b | |||
| 7df974a59a | |||
| f156204e1e | |||
| e7227e0df0 | |||
| a67ef63eeb | |||
| f9b6b93064 | |||
| aae640d675 | |||
| e19ebab1e6 | |||
| 3cf8dd9ced |
@ -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,46 @@ 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=/etc/rancher/k3s/k3s-test.yaml
|
||||||
|
export NAMESPACE=test
|
||||||
|
# 内网 NodePort(consul-ci);安全组仅 42→13:30850
|
||||||
|
export CONSUL_HTTP_ADDR="${TEST_CONSUL_HTTP_ADDR:-http://172.16.16.13:30850}"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
||||||
|
export NAMESPACE=prod
|
||||||
|
unset CONSUL_HTTP_ADDR
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [[ ! -f "$KUBECONFIG" ]]; then
|
||||||
|
echo "FAIL: missing KUBECONFIG=$KUBECONFIG host=$(hostname) uid=$(id -u)"
|
||||||
|
ls -la /etc/rancher/k3s/ /root/.kube/ 2>/dev/null || true
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# 暂时关闭改配置后自动重启 API
|
||||||
|
# export RESTART_APIS=1
|
||||||
|
export RESTART_APIS=0
|
||||||
|
|
||||||
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"
|
||||||
|
|||||||
85
README.md
85
README.md
@ -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://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=/etc/rancher/k3s/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,59 @@ 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 上需有 `/etc/rancher/k3s/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`。
|
||||||
|
|
||||||
手动:
|
手动(在 runner 机上):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
|
# prod(ClusterIP,本机可达)
|
||||||
./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(内网 NodePort consul-ci;安全组仅 runner→13:30850)
|
||||||
|
export KUBECONFIG=/etc/rancher/k3s/k3s-test.yaml NAMESPACE=test
|
||||||
|
export CONSUL_HTTP_ADDR=http://172.16.16.13:30850
|
||||||
|
./scripts/sync-to-consul.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Consul **不要**走公网 Ingress;集群内业务仍用 `consul.test.svc:8500`。
|
||||||
|
|
||||||
## 密钥来源
|
## 密钥来源
|
||||||
|
|
||||||
| 占位符 | Secret |
|
| 占位符 | Secret(在目标 NAMESPACE 内 `prod-credentials`) |
|
||||||
|--------|--------|
|
|--------|--------------------------------------------------|
|
||||||
| `${MYSQL_ROOT_PASSWORD}` | `prod-credentials` |
|
| `${MYSQL_ROOT_PASSWORD}` | MYSQL_ROOT_PASSWORD |
|
||||||
| `${REDIS_PASSWORD}` | `prod-credentials` |
|
| `${REDIS_PASSWORD}` | REDIS_PASSWORD |
|
||||||
| `${RABBITMQ_DEFAULT_PASS}` | `prod-credentials` |
|
| `${RABBITMQ_DEFAULT_PASS}` | RABBITMQ_DEFAULT_PASS |
|
||||||
| `${ELASTIC_PASSWORD}` | `prod-credentials` |
|
| `${ELASTIC_PASSWORD}` | ELASTIC_PASSWORD |
|
||||||
| `${JWT_SECRET_KEY}` | `jwt-secret` 或 `prod-credentials` |
|
| `${JWT_SECRET_KEY}` | JWT_SECRET_KEY(或单独 `jwt-secret`) |
|
||||||
|
| `${COS_SECRET_ID}` / `${COS_SECRET_KEY}` | COS_* |
|
||||||
|
| `${FEISHU_WEBHOOK}` | FEISHU_WEBHOOK |
|
||||||
|
| `${WECHAT_MP_*}` | WECHAT_MP_APP_ID / SECRET / TOKEN |
|
||||||
|
| `${OMS_TRACK_*}` | OMS_TRACK_APP_KEY / SECRET |
|
||||||
|
| `${LAZADA_*}` `${SHOPEE_*}` `${TIKTOK_*}` `${TEMU_*}` | 对应平台密钥 |
|
||||||
|
|
||||||
与 `k3s/manifests/secrets.yaml` 一致:中间件用 Secret;本仓只存带占位符的业务配置模板。
|
同步后 **默认不再** `rollout restart`(已暂时关闭);需要时手动 restart 或恢复脚本里注释块。
|
||||||
|
|
||||||
## 注意
|
## 注意
|
||||||
|
|
||||||
- `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。
|
||||||
|
|||||||
@ -2,19 +2,16 @@
|
|||||||
"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=${MYSQL_ROOT_PASSWORD};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=${MYSQL_ROOT_PASSWORD};charset=utf8mb4;"
|
||||||
},
|
},
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"Host": "redis.prod.svc.cluster.local:6379",
|
"Host": "redis.test.svc.cluster.local:6379",
|
||||||
"Password": "itd!@#123",
|
"Password": "${REDIS_PASSWORD}",
|
||||||
"MaxPoolSize": 1000,
|
"MaxPoolSize": 1000,
|
||||||
"Database": 0,
|
"Database": 0,
|
||||||
"Prefix": ""
|
"Prefix": ""
|
||||||
@ -22,10 +19,10 @@
|
|||||||
"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": "${RABBITMQ_DEFAULT_PASS}",
|
||||||
"DispatchConsumersAsync": true
|
"DispatchConsumersAsync": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -42,53 +39,51 @@
|
|||||||
},
|
},
|
||||||
"WeChat": {
|
"WeChat": {
|
||||||
"Mp": {
|
"Mp": {
|
||||||
"AppId": "wxd5141ba46c856e1f",
|
"AppId": "${WECHAT_MP_APP_ID}",
|
||||||
"Secret": "379f51a89419dc36fbb9167feef6f89a",
|
"Secret": "${WECHAT_MP_SECRET}",
|
||||||
"Token": "c6ca74013df823c0e1da0feaaaf8bf66",
|
"Token": "${WECHAT_MP_TOKEN}",
|
||||||
"EncodingAesKey": "",
|
"EncodingAesKey": "",
|
||||||
"OAuthRedirectBase": "https://ideship.com"
|
"OAuthRedirectBase": "https://test.ideship.com"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"FileStorage": {
|
"ObjectStorage": {
|
||||||
"Cos": {
|
"KeyPrefix": "admin/"
|
||||||
"KeyPrefix": "admin/"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"Oms": {
|
"Oms": {
|
||||||
"TrackService": {
|
"TrackService": {
|
||||||
"Enabled": true,
|
"Enabled": true,
|
||||||
"BaseUrl": "http://api.ideship.com/track",
|
"BaseUrl": "https://api.test.ideship.com/track",
|
||||||
"AppKey": "W2606001",
|
"AppKey": "${OMS_TRACK_APP_KEY}",
|
||||||
"AppSecret": "ziK8UzlQ39m3kdL346XEBg8nljY8os52",
|
"AppSecret": "${OMS_TRACK_APP_SECRET}",
|
||||||
"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://test.ideship.com",
|
||||||
"Lazada": {
|
"Lazada": {
|
||||||
"AppKey": "123631",
|
"AppKey": "${LAZADA_APP_KEY}",
|
||||||
"AppSecret": "7vBz2EaD6rIupeGEfwrgkabsTNsXt2ix",
|
"AppSecret": "${LAZADA_APP_SECRET}",
|
||||||
"AuthorizeUrl": "https://auth.lazada.com/oauth/authorize",
|
"AuthorizeUrl": "https://auth.lazada.com/oauth/authorize",
|
||||||
"AccessTokenUrl": "https://auth.lazada.com/rest"
|
"AccessTokenUrl": "https://auth.lazada.com/rest"
|
||||||
},
|
},
|
||||||
"Shopee": {
|
"Shopee": {
|
||||||
"PartnerId": 2004112,
|
"PartnerId": ${SHOPEE_PARTNER_ID},
|
||||||
"PartnerKey": "2f385d7ea38b087d5d71f7292e06a09c9f19022ca6c3f60ec0110a8214ef7d65",
|
"PartnerKey": "${SHOPEE_PARTNER_KEY}",
|
||||||
"HostUrl": "https://openplatform.shopee.cn",
|
"HostUrl": "https://openplatform.shopee.cn",
|
||||||
"HostAuthUrl": "https://partner.shopeemobile.com"
|
"HostAuthUrl": "https://partner.shopeemobile.com"
|
||||||
},
|
},
|
||||||
"Tiktok": {
|
"Tiktok": {
|
||||||
"AppKey": "6hc64lc6vl312",
|
"AppKey": "${TIKTOK_APP_KEY}",
|
||||||
"AppSecret": "5a691a96ee6d844534769bab5c21de1f848fb678",
|
"AppSecret": "${TIKTOK_APP_SECRET}",
|
||||||
"HostAuth": "https://auth.tiktok-shops.com",
|
"HostAuth": "https://auth.tiktok-shops.com",
|
||||||
"HostApi": "https://open-api.tiktokglobalshop.com"
|
"HostApi": "https://open-api.tiktokglobalshop.com"
|
||||||
},
|
},
|
||||||
"Temu": {
|
"Temu": {
|
||||||
"AppKey": "4ebbc9190ae410443d65b4c2faca981f",
|
"AppKey": "${TEMU_APP_KEY}",
|
||||||
"AppSecret": "4782d2d827276688bf4758bed55dbdd4bbe79a79",
|
"AppSecret": "${TEMU_APP_SECRET}",
|
||||||
"HostAuthUrl": "https://openapi-b-us.temu.com/openapi/router"
|
"HostAuthUrl": "https://openapi-b-us.temu.com/openapi/router"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"App": {
|
"App": {
|
||||||
"CorsOrigins": [
|
"CorsOrigins": [
|
||||||
"https://ideship.com"
|
"https://test.ideship.com"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"Serilog": {
|
"Serilog": {
|
||||||
@ -42,47 +42,36 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"FeiShuNotice": {
|
"FeiShuNotice": {
|
||||||
"Webhook": "https://open.feishu.cn/open-apis/bot/v2/hook/94e24bce-619d-4b3b-936c-e206353ce802",
|
"Webhook": "${FEISHU_WEBHOOK}",
|
||||||
"BatchSize": 10,
|
"BatchSize": 10,
|
||||||
"BatchIntervalSeconds": 10,
|
"BatchIntervalSeconds": 10,
|
||||||
"EnableFeiShuExceptionSubscribe": true,
|
"EnableFeiShuExceptionSubscribe": true,
|
||||||
"Skip40X": false,
|
"Skip40X": true,
|
||||||
"WriteBody": true,
|
"WriteBody": true,
|
||||||
"WriteStack": true,
|
"WriteStack": true,
|
||||||
"MaxLength": 3000
|
"MaxLength": 3000
|
||||||
},
|
},
|
||||||
"JwtSettings": {
|
"JwtSettings": {
|
||||||
"SecretKey": "YourSuperSecretKeyThatIsAtLeast32CharactersLong!",
|
"SecretKey": "${JWT_SECRET_KEY}",
|
||||||
"Issuer": "SimpleAdmin",
|
"Issuer": "SimpleAdmin",
|
||||||
"Audience": "SimpleAdminClient",
|
"Audience": "SimpleAdminClient",
|
||||||
"ExpiryInMinutes": 600,
|
"ExpiryInMinutes": 600,
|
||||||
"RefreshExpiryInDays": 7
|
"RefreshExpiryInDays": 7
|
||||||
},
|
},
|
||||||
"FileStorage": {
|
|
||||||
"Provider": "Cos",
|
|
||||||
"Cos": {
|
|
||||||
"SecretId": "AKIDdOxIOGuKVSAetteBTbZLtCG6i5D6k9JE",
|
|
||||||
"SecretKey": "kEWbWDPPAhz2qQq4FF5kBOXTAcpnkY8U",
|
|
||||||
"Region": "ap-guangzhou",
|
|
||||||
"Bucket": "ideship-1308574410",
|
|
||||||
"BaseUrl": "https://cos.ideship.com",
|
|
||||||
"DurationSecond": 3600,
|
|
||||||
"UploadDurationSecond": 600,
|
|
||||||
"SignUrls": true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"ObjectStorage": {
|
"ObjectStorage": {
|
||||||
"Provider": "TencentCos",
|
"Provider": "TencentCos",
|
||||||
"SignUrlsByDefault": true,
|
"SignUrlsByDefault": true,
|
||||||
"DefaultSignedUrlExpiresSeconds": 900,
|
"DefaultSignedUrlExpiresSeconds": 3600,
|
||||||
|
"DefaultUploadExpiresSeconds": 600,
|
||||||
"TencentCos": {
|
"TencentCos": {
|
||||||
"SecretId": "AKIDdOxIOGuKVSAetteBTbZLtCG6i5D6k9JE",
|
"SecretId": "${COS_SECRET_ID}",
|
||||||
"SecretKey": "kEWbWDPPAhz2qQq4FF5kBOXTAcpnkY8U",
|
"SecretKey": "${COS_SECRET_KEY}",
|
||||||
"Region": "ap-guangzhou",
|
"Region": "ap-guangzhou",
|
||||||
"Bucket": "ideship-1308574410",
|
"Bucket": "test-1308574410",
|
||||||
"BaseUrl": "https://cos.ideship.com",
|
"BaseUrl": "https://cos.ideship.com",
|
||||||
"UseHttps": true,
|
"UseHttps": true,
|
||||||
"SignUrls": true
|
"SignUrls": true,
|
||||||
|
"DurationSecond": 600
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -19,11 +19,11 @@
|
|||||||
"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=${MYSQL_ROOT_PASSWORD};charset=utf8mb4;"
|
||||||
},
|
},
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"Host": "redis.prod.svc.cluster.local:6379",
|
"Host": "redis.test.svc.cluster.local:6379",
|
||||||
"Password": "itd!@#123",
|
"Password": "${REDIS_PASSWORD}",
|
||||||
"MaxPoolSize": 1000,
|
"MaxPoolSize": 1000,
|
||||||
"Database": 0,
|
"Database": 0,
|
||||||
"Prefix": ""
|
"Prefix": ""
|
||||||
@ -31,18 +31,18 @@
|
|||||||
"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": "${RABBITMQ_DEFAULT_PASS}",
|
||||||
"DispatchConsumersAsync": true
|
"DispatchConsumersAsync": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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": "${ELASTIC_PASSWORD}",
|
||||||
"ShowLogInfo": false,
|
"ShowLogInfo": false,
|
||||||
"IndexPrefix": ""
|
"IndexPrefix": ""
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,16 +10,19 @@
|
|||||||
"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
|
||||||
},
|
},
|
||||||
|
"ObjectStorage": {
|
||||||
|
"KeyPrefix": "track/"
|
||||||
|
},
|
||||||
"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=${MYSQL_ROOT_PASSWORD};charset=utf8mb4;"
|
||||||
},
|
},
|
||||||
"Redis": {
|
"Redis": {
|
||||||
"Host": "redis.prod.svc.cluster.local:6379",
|
"Host": "redis.test.svc.cluster.local:6379",
|
||||||
"Password": "itd!@#123",
|
"Password": "${REDIS_PASSWORD}",
|
||||||
"MaxPoolSize": 1000,
|
"MaxPoolSize": 1000,
|
||||||
"Database": 1,
|
"Database": 1,
|
||||||
"Prefix": ""
|
"Prefix": ""
|
||||||
@ -27,23 +30,23 @@
|
|||||||
"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": "${RABBITMQ_DEFAULT_PASS}",
|
||||||
"DispatchConsumersAsync": true
|
"DispatchConsumersAsync": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"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": "${ELASTIC_PASSWORD}",
|
||||||
"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,
|
||||||
|
|||||||
@ -36,9 +36,14 @@ json_ok_str() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
if [[ -z "${CONSUL_HTTP_ADDR:-}" ]]; then
|
if [[ -z "${CONSUL_HTTP_ADDR:-}" ]]; then
|
||||||
CIP="$(kubectl -n "$NS" get svc consul -o jsonpath='{.spec.clusterIP}')"
|
if [[ "$NS" == "test" ]]; then
|
||||||
CONSUL_HTTP_ADDR="http://${CIP}:8500"
|
CONSUL_HTTP_ADDR="${TEST_CONSUL_HTTP_ADDR:-http://172.16.16.13:30850}"
|
||||||
|
else
|
||||||
|
CIP="$(kubectl -n "$NS" get svc consul -o jsonpath='{.spec.clusterIP}')"
|
||||||
|
CONSUL_HTTP_ADDR="http://${CIP}:8500"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
echo "==> Consul ${CONSUL_HTTP_ADDR}"
|
||||||
|
|
||||||
if [[ -z "${CONSUL_HTTP_TOKEN:-}" ]]; then
|
if [[ -z "${CONSUL_HTTP_TOKEN:-}" ]]; then
|
||||||
raw="$(kubectl -n "$NS" get secret consul-acl -o jsonpath='{.data.CONSUL_HTTP_TOKEN}' 2>/dev/null || true)"
|
raw="$(kubectl -n "$NS" get secret consul-acl -o jsonpath='{.data.CONSUL_HTTP_TOKEN}' 2>/dev/null || true)"
|
||||||
|
|||||||
@ -125,24 +125,68 @@ load_secret() {
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
echo "==> 加载密钥(K8s Secret / env)"
|
echo "==> 加载密钥(K8s Secret / env) ns=${NS} kubeconfig=${KUBECONFIG}"
|
||||||
|
if ! kubectl -n "$NS" get secret prod-credentials >/dev/null 2>&1; then
|
||||||
|
echo "FAIL: 找不到 secret/${NS}/prod-credentials"
|
||||||
|
echo " 当前: KUBECONFIG=${KUBECONFIG}"
|
||||||
|
echo " test 集群请先: kubectl --kubeconfig=/etc/rancher/k3s/k3s-test.yaml apply -f /data/k3s-test/manifests/secrets.yaml"
|
||||||
|
echo " 或: kubectl -n ${NS} get secret"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
load_secret MYSQL_ROOT_PASSWORD prod-credentials MYSQL_ROOT_PASSWORD
|
load_secret MYSQL_ROOT_PASSWORD prod-credentials MYSQL_ROOT_PASSWORD
|
||||||
load_secret REDIS_PASSWORD prod-credentials REDIS_PASSWORD
|
load_secret REDIS_PASSWORD prod-credentials REDIS_PASSWORD
|
||||||
load_secret RABBITMQ_DEFAULT_PASS prod-credentials RABBITMQ_DEFAULT_PASS
|
load_secret RABBITMQ_DEFAULT_PASS prod-credentials RABBITMQ_DEFAULT_PASS
|
||||||
load_secret ELASTIC_PASSWORD prod-credentials ELASTIC_PASSWORD
|
load_secret ELASTIC_PASSWORD prod-credentials ELASTIC_PASSWORD
|
||||||
load_secret JWT_SECRET_KEY jwt-secret JWT_SECRET_KEY
|
load_secret JWT_SECRET_KEY jwt-secret JWT_SECRET_KEY
|
||||||
# 兼容:JWT 也放在 prod-credentials
|
|
||||||
load_secret JWT_SECRET_KEY prod-credentials JWT_SECRET_KEY
|
load_secret JWT_SECRET_KEY prod-credentials JWT_SECRET_KEY
|
||||||
|
load_secret COS_SECRET_ID prod-credentials COS_SECRET_ID
|
||||||
|
load_secret COS_SECRET_KEY prod-credentials COS_SECRET_KEY
|
||||||
|
load_secret FEISHU_WEBHOOK prod-credentials FEISHU_WEBHOOK
|
||||||
|
load_secret WECHAT_MP_APP_ID prod-credentials WECHAT_MP_APP_ID
|
||||||
|
load_secret WECHAT_MP_SECRET prod-credentials WECHAT_MP_SECRET
|
||||||
|
load_secret WECHAT_MP_TOKEN prod-credentials WECHAT_MP_TOKEN
|
||||||
|
load_secret OMS_TRACK_APP_KEY prod-credentials OMS_TRACK_APP_KEY
|
||||||
|
load_secret OMS_TRACK_APP_SECRET prod-credentials OMS_TRACK_APP_SECRET
|
||||||
|
load_secret LAZADA_APP_KEY prod-credentials LAZADA_APP_KEY
|
||||||
|
load_secret LAZADA_APP_SECRET prod-credentials LAZADA_APP_SECRET
|
||||||
|
load_secret SHOPEE_PARTNER_ID prod-credentials SHOPEE_PARTNER_ID
|
||||||
|
load_secret SHOPEE_PARTNER_KEY prod-credentials SHOPEE_PARTNER_KEY
|
||||||
|
load_secret TIKTOK_APP_KEY prod-credentials TIKTOK_APP_KEY
|
||||||
|
load_secret TIKTOK_APP_SECRET prod-credentials TIKTOK_APP_SECRET
|
||||||
|
load_secret TEMU_APP_KEY prod-credentials TEMU_APP_KEY
|
||||||
|
load_secret TEMU_APP_SECRET prod-credentials TEMU_APP_SECRET
|
||||||
|
|
||||||
: "${MYSQL_ROOT_PASSWORD:?缺少 MYSQL_ROOT_PASSWORD(env 或 secret/prod-credentials)}"
|
: "${MYSQL_ROOT_PASSWORD:?缺少 MYSQL_ROOT_PASSWORD(env 或 secret/${NS}/prod-credentials)}"
|
||||||
: "${REDIS_PASSWORD:?缺少 REDIS_PASSWORD}"
|
: "${REDIS_PASSWORD:?缺少 REDIS_PASSWORD}"
|
||||||
: "${RABBITMQ_DEFAULT_PASS:?缺少 RABBITMQ_DEFAULT_PASS}"
|
: "${RABBITMQ_DEFAULT_PASS:?缺少 RABBITMQ_DEFAULT_PASS}"
|
||||||
: "${ELASTIC_PASSWORD:?缺少 ELASTIC_PASSWORD}"
|
: "${ELASTIC_PASSWORD:?缺少 ELASTIC_PASSWORD}"
|
||||||
: "${JWT_SECRET_KEY:?缺少 JWT_SECRET_KEY(请创建 secret/jwt-secret 或写入 prod-credentials)}"
|
: "${JWT_SECRET_KEY:?缺少 JWT_SECRET_KEY(请创建 secret/jwt-secret 或写入 prod-credentials)}"
|
||||||
|
: "${COS_SECRET_ID:?缺少 COS_SECRET_ID}"
|
||||||
|
: "${COS_SECRET_KEY:?缺少 COS_SECRET_KEY}"
|
||||||
|
: "${FEISHU_WEBHOOK:?缺少 FEISHU_WEBHOOK}"
|
||||||
|
: "${WECHAT_MP_APP_ID:?缺少 WECHAT_MP_APP_ID}"
|
||||||
|
: "${WECHAT_MP_SECRET:?缺少 WECHAT_MP_SECRET}"
|
||||||
|
: "${WECHAT_MP_TOKEN:?缺少 WECHAT_MP_TOKEN}"
|
||||||
|
: "${OMS_TRACK_APP_KEY:?缺少 OMS_TRACK_APP_KEY}"
|
||||||
|
: "${OMS_TRACK_APP_SECRET:?缺少 OMS_TRACK_APP_SECRET}"
|
||||||
|
: "${LAZADA_APP_KEY:?缺少 LAZADA_APP_KEY}"
|
||||||
|
: "${LAZADA_APP_SECRET:?缺少 LAZADA_APP_SECRET}"
|
||||||
|
: "${SHOPEE_PARTNER_ID:?缺少 SHOPEE_PARTNER_ID}"
|
||||||
|
: "${SHOPEE_PARTNER_KEY:?缺少 SHOPEE_PARTNER_KEY}"
|
||||||
|
: "${TIKTOK_APP_KEY:?缺少 TIKTOK_APP_KEY}"
|
||||||
|
: "${TIKTOK_APP_SECRET:?缺少 TIKTOK_APP_SECRET}"
|
||||||
|
: "${TEMU_APP_KEY:?缺少 TEMU_APP_KEY}"
|
||||||
|
: "${TEMU_APP_SECRET:?缺少 TEMU_APP_SECRET}"
|
||||||
|
|
||||||
|
# Consul:prod 用 ClusterIP(runner 在簇内);test 用内网 NodePort(见 consul-ci / TEST_CONSUL_HTTP_ADDR)
|
||||||
if [[ -z "$CONSUL_HTTP_ADDR" ]]; then
|
if [[ -z "$CONSUL_HTTP_ADDR" ]]; then
|
||||||
CIP="$(kubectl -n "$NS" get svc consul -o jsonpath='{.spec.clusterIP}')"
|
if [[ "$NS" == "test" ]]; then
|
||||||
CONSUL_HTTP_ADDR="http://${CIP}:8500"
|
# 安全组:仅放行 CI 机内网 → 测试机 30850;勿对公网开放
|
||||||
|
CONSUL_HTTP_ADDR="${TEST_CONSUL_HTTP_ADDR:-http://172.16.16.13:30850}"
|
||||||
|
else
|
||||||
|
CIP="$(kubectl -n "$NS" get svc consul -o jsonpath='{.spec.clusterIP}')"
|
||||||
|
CONSUL_HTTP_ADDR="http://${CIP}:8500"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
echo "==> Consul ${CONSUL_HTTP_ADDR}"
|
echo "==> Consul ${CONSUL_HTTP_ADDR}"
|
||||||
|
|
||||||
@ -195,8 +239,15 @@ for name in "${TARGETS[@]}"; do
|
|||||||
[[ -f "$src" ]] || { echo "FAIL: 无 ${src}"; exit 1; }
|
[[ -f "$src" ]] || { echo "FAIL: 无 ${src}"; exit 1; }
|
||||||
|
|
||||||
# 仅替换已知占位符,避免 JSON 里其它 $ 被误伤
|
# 仅替换已知占位符,避免 JSON 里其它 $ 被误伤
|
||||||
export MYSQL_ROOT_PASSWORD REDIS_PASSWORD RABBITMQ_DEFAULT_PASS ELASTIC_PASSWORD JWT_SECRET_KEY
|
export MYSQL_ROOT_PASSWORD REDIS_PASSWORD RABBITMQ_DEFAULT_PASS ELASTIC_PASSWORD JWT_SECRET_KEY \
|
||||||
envsubst '${MYSQL_ROOT_PASSWORD} ${REDIS_PASSWORD} ${RABBITMQ_DEFAULT_PASS} ${ELASTIC_PASSWORD} ${JWT_SECRET_KEY}' \
|
COS_SECRET_ID COS_SECRET_KEY FEISHU_WEBHOOK \
|
||||||
|
WECHAT_MP_APP_ID WECHAT_MP_SECRET WECHAT_MP_TOKEN \
|
||||||
|
OMS_TRACK_APP_KEY OMS_TRACK_APP_SECRET \
|
||||||
|
LAZADA_APP_KEY LAZADA_APP_SECRET \
|
||||||
|
SHOPEE_PARTNER_ID SHOPEE_PARTNER_KEY \
|
||||||
|
TIKTOK_APP_KEY TIKTOK_APP_SECRET \
|
||||||
|
TEMU_APP_KEY TEMU_APP_SECRET
|
||||||
|
envsubst '${MYSQL_ROOT_PASSWORD} ${REDIS_PASSWORD} ${RABBITMQ_DEFAULT_PASS} ${ELASTIC_PASSWORD} ${JWT_SECRET_KEY} ${COS_SECRET_ID} ${COS_SECRET_KEY} ${FEISHU_WEBHOOK} ${WECHAT_MP_APP_ID} ${WECHAT_MP_SECRET} ${WECHAT_MP_TOKEN} ${OMS_TRACK_APP_KEY} ${OMS_TRACK_APP_SECRET} ${LAZADA_APP_KEY} ${LAZADA_APP_SECRET} ${SHOPEE_PARTNER_ID} ${SHOPEE_PARTNER_KEY} ${TIKTOK_APP_KEY} ${TIKTOK_APP_SECRET} ${TEMU_APP_KEY} ${TEMU_APP_SECRET}' \
|
||||||
<"$src" >"${TMP}/${name}.json"
|
<"$src" >"${TMP}/${name}.json"
|
||||||
|
|
||||||
# 禁止未替换的占位符漏网(注释里的 ${...} 也会拦)
|
# 禁止未替换的占位符漏网(注释里的 ${...} 也会拦)
|
||||||
@ -223,19 +274,22 @@ for name in "${TARGETS[@]}"; do
|
|||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
|
||||||
|
# 暂时关闭:改配置后自动 rollout restart API(需要时把下面取消注释,或 CI 设 RESTART_APIS=1)
|
||||||
|
# if [[ "$RESTART_APIS" == "1" ]]; then
|
||||||
|
# readarray -t RESTART_SET < <(printf '%s\n' "${RESTART_SET[@]}" | sort -u)
|
||||||
|
# echo "==> rollout restart: ${RESTART_SET[*]}"
|
||||||
|
# for d in "${RESTART_SET[@]}"; do
|
||||||
|
# [[ -n "$d" ]] || continue
|
||||||
|
# if kubectl -n "$NS" get "deploy/${d}" >/dev/null 2>&1; then
|
||||||
|
# kubectl -n "$NS" rollout restart "deploy/${d}"
|
||||||
|
# kubectl -n "$NS" rollout status "deploy/${d}" --timeout=180s || true
|
||||||
|
# else
|
||||||
|
# echo "SKIP deploy/${d}(不存在)"
|
||||||
|
# fi
|
||||||
|
# done
|
||||||
|
# fi
|
||||||
if [[ "$RESTART_APIS" == "1" ]]; then
|
if [[ "$RESTART_APIS" == "1" ]]; then
|
||||||
# 去重
|
echo "==> SKIP rollout restart(已暂时关闭;RESTART_APIS=1 被忽略)"
|
||||||
readarray -t RESTART_SET < <(printf '%s\n' "${RESTART_SET[@]}" | sort -u)
|
|
||||||
echo "==> rollout restart: ${RESTART_SET[*]}"
|
|
||||||
for d in "${RESTART_SET[@]}"; do
|
|
||||||
[[ -n "$d" ]] || continue
|
|
||||||
if kubectl -n "$NS" get "deploy/${d}" >/dev/null 2>&1; then
|
|
||||||
kubectl -n "$NS" rollout restart "deploy/${d}"
|
|
||||||
kubectl -n "$NS" rollout status "deploy/${d}" --timeout=180s || true
|
|
||||||
else
|
|
||||||
echo "SKIP deploy/${d}(不存在)"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "DONE"
|
echo "DONE"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user