fix(cluster): 强制关键副本跨节点分散

避免同站点 Worker 与容量控制器在滚动发布时集中到同一节点,并让 Kubernetes 运行态清单变更进入可追溯的 API release。\n\n验证:bash -n、ShellCheck、manual-release-test、生产集群 server-side dry-run。
This commit is contained in:
2026-08-01 12:33:19 +08:00
parent fcc3dc3cb9
commit 773d310214
3 changed files with 34 additions and 1 deletions
@@ -174,6 +174,13 @@ spec:
spec:
serviceAccountName: easyai-capacity-controller
terminationGracePeriodSeconds: 30
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: easyai.io/site
labelSelector:
matchLabels:
app.kubernetes.io/name: easyai-capacity-controller
nodeSelector:
easyai.io/workload: "true"
topologySpreadConstraints:
@@ -447,6 +454,14 @@ spec:
spec:
serviceAccountName: easyai-ai-gateway
terminationGracePeriodSeconds: 90
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: easyai-worker
easyai.io/site: ningbo
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
@@ -612,6 +627,14 @@ spec:
spec:
serviceAccountName: easyai-ai-gateway
terminationGracePeriodSeconds: 90
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: kubernetes.io/hostname
labelSelector:
matchLabels:
app.kubernetes.io/name: easyai-worker
easyai.io/site: hongkong
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
+1
View File
@@ -49,6 +49,7 @@ const changed = git([
const apiPatterns = [
/^apps\/api\//,
/^go\.work(?:\.sum)?$/,
/^deploy\/kubernetes\//,
]
const webPatterns = [
/^apps\/web\//,
+10 -1
View File
@@ -8,7 +8,8 @@ trap 'rm -rf "$tmp"' EXIT
new_repo() {
local name=$1
local repo=$tmp/$name
mkdir -p "$repo/apps/api/migrations" "$repo/apps/web/src" "$repo/packages/contracts/src" "$repo/docs"
mkdir -p "$repo/apps/api/migrations" "$repo/apps/web/src" "$repo/packages/contracts/src" \
"$repo/deploy/kubernetes/production" "$repo/docs"
git -C "$repo" init -q
git -C "$repo" config user.name 'Manual Release Test'
git -C "$repo" config user.email 'manual-release-test@example.invalid'
@@ -16,6 +17,7 @@ new_repo() {
printf 'SELECT 1;\n' >"$repo/apps/api/migrations/0001_init.sql"
printf 'web\n' >"$repo/apps/web/src/app.ts"
printf 'contracts\n' >"$repo/packages/contracts/src/index.ts"
printf 'kind: Deployment\n' >"$repo/deploy/kubernetes/production/application.yaml"
# shellcheck disable=SC2016
printf 'ARG API_RUNTIME_IMAGE=scratch\nARG WEB_RUNTIME_IMAGE=scratch\nFROM ${API_RUNTIME_IMAGE} AS api\nCOPY apps/api /app\nFROM ${WEB_RUNTIME_IMAGE} AS web\nCOPY apps/web /web\n' >"$repo/Dockerfile"
printf 'docs\n' >"$repo/docs/readme.md"
@@ -80,6 +82,13 @@ git -C "$repo" add -A && git -C "$repo" commit -qm docs
result=$(classify "$repo" "$base")
node -e 'const value=JSON.parse(process.argv[1]); if(value.components!=="none")process.exit(1)' "$result"
repo=$(new_repo kubernetes-runtime)
base=$(git -C "$repo" rev-parse HEAD)
printf 'kind: Deployment\n# scheduling changed\n' >"$repo/deploy/kubernetes/production/application.yaml"
git -C "$repo" add -A && git -C "$repo" commit -qm kubernetes-runtime
result=$(classify "$repo" "$base")
node -e 'const value=JSON.parse(process.argv[1]); if(value.components!=="api"||value.migrationsChanged)process.exit(1)' "$result"
bare=$tmp/origin.git
git init -q --bare "$bare"
repo=$(new_repo preflight)