fix: roll development pods on config changes

This commit is contained in:
youfak 2026-08-07 21:09:08 +08:00
parent 51158007b4
commit 3ae04d8a62
11 changed files with 64 additions and 4 deletions

View File

@ -53,6 +53,10 @@ Overlay 的 Gateway 从 `gateway-a` 证书派生 `worker_id=gateway-a`Checker
`minReplicas=maxReplicas=1`。因此不得在此 Overlay 上增加副本数或放宽 HPA重复使用 `minReplicas=maxReplicas=1`。因此不得在此 Overlay 上增加副本数或放宽 HPA重复使用
同一证书和 Worker 身份会破坏 session、ownership 和证书角色边界。 同一证书和 Worker 身份会破坏 session、ownership 和证书角色边界。
Overlay 的 `proxy-pool-runtime-config` 带内容哈希;修改 `config.yaml`Kustomize 会重写三个
Deployment 的 ConfigMap volume 引用,从而触发 Kubernetes 滚动更新。控制面 TLS 与
`proxy-pool-secrets` 使用外部创建的固定名称 Secret轮换后仍需按运行手册显式滚动对应工作负载。
生产环境需要由工作负载身份系统为每个副本签发独立、可轮换的证书,并将该副本的 生产环境需要由工作负载身份系统为每个副本签发独立、可轮换的证书,并将该副本的
身份注入 Gateway Client TLS 或 Checker Client TLS并启用自动身份派生。应用会在每次新 身份注入 Gateway Client TLS 或 Checker Client TLS并启用自动身份派生。应用会在每次新
控制面 TLS 握手读取更新后的叶证书和信任根;已有 gRPC 流仍按原会话保留,根轮换时先投放 控制面 TLS 握手读取更新后的叶证书和信任根;已有 gRPC 流仍按原会话保留,根轮换时先投放

View File

@ -18,6 +18,9 @@ spec:
mountPath: /run/proxy-pool-tls/client mountPath: /run/proxy-pool-tls/client
readOnly: true readOnly: true
volumes: volumes:
- name: config
configMap:
name: proxy-pool-runtime-config
- name: controlplane-checker-tls - name: controlplane-checker-tls
secret: secret:
secretName: proxy-pool-controlplane-checker-tls secretName: proxy-pool-controlplane-checker-tls

View File

@ -0,0 +1,6 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: proxy-pool-config
namespace: proxy-pool
$patch: delete

View File

@ -14,6 +14,9 @@ spec:
mountPath: /run/proxy-pool-tls/server mountPath: /run/proxy-pool-tls/server
readOnly: true readOnly: true
volumes: volumes:
- name: config
configMap:
name: proxy-pool-runtime-config
- name: controlplane-server-tls - name: controlplane-server-tls
secret: secret:
secretName: proxy-pool-controlplane-server-tls secretName: proxy-pool-controlplane-server-tls

View File

@ -19,6 +19,9 @@ spec:
mountPath: /run/proxy-pool-tls/client mountPath: /run/proxy-pool-tls/client
readOnly: true readOnly: true
volumes: volumes:
- name: config
configMap:
name: proxy-pool-runtime-config
- name: controlplane-gateway-tls - name: controlplane-gateway-tls
secret: secret:
secretName: proxy-pool-controlplane-gateway-tls secretName: proxy-pool-controlplane-gateway-tls

View File

@ -6,14 +6,12 @@ resources:
- controller-service.yaml - controller-service.yaml
- checker-networkpolicy.yaml - checker-networkpolicy.yaml
configMapGenerator: configMapGenerator:
- name: proxy-pool-config - name: proxy-pool-runtime-config
namespace: proxy-pool namespace: proxy-pool
behavior: replace
files: files:
- config.yaml - config.yaml
generatorOptions:
disableNameSuffixHash: true
patches: patches:
- path: configmap-delete.yaml
- path: controller-patch.yaml - path: controller-patch.yaml
- path: gateway-patch.yaml - path: gateway-patch.yaml
- path: checker-patch.yaml - path: checker-patch.yaml

View File

@ -1,7 +1,9 @@
package deploy package deploy
import ( import (
"os"
"os/exec" "os/exec"
"regexp"
"strings" "strings"
"testing" "testing"
) )
@ -42,3 +44,30 @@ func TestKubernetesDevelopmentMTLSOverlayRendersCertificateDerivedIdentities(t *
} }
} }
} }
func TestKubernetesDevelopmentMTLSOverlayUsesVersionedConfigMap(t *testing.T) {
payload, err := os.ReadFile("kubernetes/overlays/development-mtls/kustomization.yaml")
if err != nil {
t.Fatalf("read development mTLS kustomization: %v", err)
}
if strings.Contains(string(payload), "disableNameSuffixHash: true") {
t.Fatal("development mTLS overlay disables ConfigMap versioning")
}
kubectl, err := exec.LookPath("kubectl")
if err != nil {
t.Skip("kubectl is required to render the Kubernetes development mTLS overlay")
}
command := exec.Command(kubectl, "kustomize", "kubernetes/overlays/development-mtls")
command.Dir = "."
renderedPayload, err := command.CombinedOutput()
if err != nil {
t.Fatalf("render development mTLS overlay: %v\n%s", err, renderedPayload)
}
matched := regexp.MustCompile(`(?m)^ name: (proxy-pool-runtime-config-[a-z0-9]+)$`).FindStringSubmatch(string(renderedPayload))
if len(matched) != 2 {
t.Fatalf("rendered overlay has no versioned config map: %s", renderedPayload)
}
if occurrences := strings.Count(string(renderedPayload), "name: "+matched[1]); occurrences != 4 {
t.Fatalf("versioned config map reference count = %d, want config map plus three workload volumes", occurrences)
}
}

View File

@ -113,6 +113,10 @@ Fetch 应表现为 Error 与退避,不应增加 Empty 计数,也不影响已
4. 根据集群 CNI 能力收紧 NetworkPolicy 的外部网段。 4. 根据集群 CNI 能力收紧 NetworkPolicy 的外部网段。
5. 在预发布环境完成数据库向前兼容迁移,再发布 Controller。 5. 在预发布环境完成数据库向前兼容迁移,再发布 Controller。
环境 Overlay 应保持 ConfigMap 内容哈希,令配置变化进入 Deployment Pod 模板并触发滚动更新。
由外部系统以固定名称注入的 Secret 不会天然改变 Pod 模板;完成 Secret 轮换后,必须按受影响
工作负载执行受控滚动,并先验证新旧信任根的重叠窗口。
### 3.2 服务端应用顺序 ### 3.2 服务端应用顺序
```bash ```bash

View File

@ -106,6 +106,8 @@ CI 已配置 Linux race job。PostgreSQL 18 和 Redis 8.2 的隔离 Adapter fixt
mTLS 运行拓扑并由配置、证书、命令装配和部署契约测试覆盖。Kubernetes base 刻意不直接 mTLS 运行拓扑并由配置、证书、命令装配和部署契约测试覆盖。Kubernetes base 刻意不直接
启用 Checker`development-mtls` Overlay 已为单副本 Controller、Gateway 和 Checker 启用 Checker`development-mtls` Overlay 已为单副本 Controller、Gateway 和 Checker
提供固定开发证书、运行时身份派生、mTLS Secret 挂载、最小出站 NetworkPolicy 与渲染/配置契约验证。 提供固定开发证书、运行时身份派生、mTLS Secret 挂载、最小出站 NetworkPolicy 与渲染/配置契约验证。
其 ConfigMap 使用内容哈希以在配置变化时触发三个工作负载滚动;固定名称的外部 Secret 仍要求
受控轮换和显式重启。
Controller、Gateway 与 Checker 的叶证书和信任根已在每个新 TLS 握手时重载,文件短暂 Controller、Gateway 与 Checker 的叶证书和信任根已在每个新 TLS 握手时重载,文件短暂
不一致时保留最后一次有效材料。Gateway、Checker 启动派生和 Controller 授权共用同一 不一致时保留最后一次有效材料。Gateway、Checker 启动派生和 Controller 授权共用同一
SPIFFE URI 解析器X.509-SVID 叶证书必须且只能包含一个 URI SAN并精确匹配其角色。 SPIFFE URI 解析器X.509-SVID 叶证书必须且只能包含一个 URI SAN并精确匹配其角色。

View File

@ -280,3 +280,9 @@ Routing 自上而下匹配,首条命中停止;支持 Gateway 与 Extract 两
- GitHub Actions 的 Deployment job 在同一组无敏感值 fixture 下渲染生产 Compose、测试 Compose - GitHub Actions 的 Deployment job 在同一组无敏感值 fixture 下渲染生产 Compose、测试 Compose
以及 Kubernetes base/development mTLS Overlay并对两份配置运行严格校验它仍不替代 以及 Kubernetes base/development mTLS Overlay并对两份配置运行严格校验它仍不替代
需要镜像网络和真实服务的容器端到端测试。 需要镜像网络和真实服务的容器端到端测试。
## Kubernetes 配置发布审计2026-08-07
- development mTLS Overlay 的 ConfigMap 采用 Kustomize 内容哈希,渲染契约要求三个工作负载
都引用同一版本化名称,因此配置变更进入 Pod 模板并触发滚动。外部固定名称 Secret 不含内容哈希,
它们的轮换需要平台侧 reloader 或受控显式滚动;这一限制已写入运行手册。

View File

@ -2,6 +2,8 @@
## 2026-08-07 ## 2026-08-07
- Kubernetes 开发 mTLS Overlay 恢复 ConfigMap 内容哈希:配置更新会重写 Controller、Gateway
和 Checker 的 volume 引用并触发滚动;固定名称 Secret 的轮换仍要求显式受控重启。
- GitHub Actions Deployment job 现同时静态展开生产与测试 Compose并对本地 Compose 配置和 - GitHub Actions Deployment job 现同时静态展开生产与测试 Compose并对本地 Compose 配置和
开发 mTLS 配置执行严格校验,避免仅检查 Kubernetes 覆盖层。 开发 mTLS 配置执行严格校验,避免仅检查 Kubernetes 覆盖层。
- Docker 构建上下文现由根 `.dockerignore` 保护:本地控制面证书/私钥、环境文件、凭据文件、 - Docker 构建上下文现由根 `.dockerignore` 保护:本地控制面证书/私钥、环境文件、凭据文件、