Files
conti-docs/backend/07-config-governance.md
T
Guangfei.Zhao 1e0cbb86a2 feat: Add comprehensive documentation for integration layer, API design, config governance, observability, build/deploy, and testing strategies
- Introduced integration layer design with Resilience4j for external vendor calls.
- Established API design standards with unified response structures and global exception handling.
- Defined configuration and service governance using Kubernetes native solutions.
- Implemented observability practices including trace ID propagation and structured logging.
- Outlined build and multi-environment deployment strategies using Gradle and GitLab CI/CD.
- Specified testing strategies across different layers, utilizing JUnit, MockK, Testcontainers, and WireMock.
2026-08-12 18:23:11 +08:00

130 lines
5.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 07. 配置与服务治理
## 决策
K8s 原生方案:ConfigMap + Secret + Spring Cloud Kubernetes,不引入 Nacos 等额外治理组件,贴合已有 Azure + GitLab CI/CD 部署方式(见 [Architecture-Diagram/deployment-architecture-diagram.drawio](../Architecture-Diagram/deployment-architecture-diagram.drawio))。
选这条路而不是 Spring Cloud AlibabaNacos)的原因:部署环境已经是 K8s,K8s 本身自带 Service(服务发现)、ConfigMap/Secret(配置)、Deployment 滚动更新(发布),再引入 Nacos 意味着多维护一套集群、多一套"配置到底以谁为准"的心智负担。除非未来有 Nacos 才能提供、K8s 原生方案覆盖不了的能力(比如更细粒度的灰度配置推送),否则先用 K8s 原生的就够。
## 结构约定
- **非敏感配置**(菜单开关、超时参数、日志级别等)放 ConfigMap,挂载成 `application-{profile}.yml` 或环境变量。
- **敏感配置**DB 密码、JWT secret、F6 API key)放 Secret,都不进代码库、不进镜像。
- 各环境(dev/uat/prod)对应各自 namespace 下的 ConfigMap/Secret + Spring profile`bootstrap``SPRING_PROFILES_ACTIVE` 加载对应配置。
## ConfigMap / Secret 示例
```yaml
# k8s/configmap-workbench-uat.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: conti-backend-config
namespace: retailapp-uat
data:
application-uat.yml: |
resilience4j:
circuitbreaker:
instances:
f6-api:
failure-rate-threshold: 50
workbench:
degrade-message: "部分数据暂时无法显示,请稍后刷新"
```
```yaml
# k8s/secret-uat.yaml(实际值由 CI/CD 从密钥管理服务注入,不手写明文提交)
apiVersion: v1
kind: Secret
metadata:
name: conti-backend-secret
namespace: retailapp-uat
type: Opaque
stringData:
SECURITY_JWT_SECRET: "__injected_by_pipeline__"
DB_PASSWORD: "__injected_by_pipeline__"
F6_API_KEY: "__injected_by_pipeline__"
```
```yaml
# k8s/deployment-uat.yaml(节选)
spec:
containers:
- name: conti-backend
image: registry.example.com/conti-backend:__TAG__
envFrom:
- secretRef:
name: conti-backend-secret
env:
- name: SPRING_PROFILES_ACTIVE
value: uat
volumeMounts:
- name: config-volume
mountPath: /app/config
volumes:
- name: config-volume
configMap:
name: conti-backend-config
```
## 启用 Spring Cloud Kubernetes 配置热更新
```groovy
// bootstrap/build.gradle
dependencies {
implementation 'org.springframework.cloud:spring-cloud-starter-kubernetes-client-config'
}
```
```yaml
# application.yml
spring:
cloud:
kubernetes:
config:
enabled: true
sources:
- name: conti-backend-config
reload:
enabled: true
mode: polling # 定期轮询 ConfigMap 变化,无需重启 Pod
period: 15s
```
```kotlin
// 需要热更新的配置类加 @RefreshScope
@RefreshScope
@ConfigurationProperties(prefix = "workbench")
@Component
class WorkbenchProperties {
var degradeMessage: String = "部分数据暂时无法显示"
}
```
## 关键规则
- 配置变更优先走 ConfigMap 热更新(`@RefreshScope` + `spring.cloud.kubernetes.reload`),不重新构建镜像;涉及 Secret 轮换的走正常发布流程(Secret 变化通常需要重启 Pod 才能生效,不像 ConfigMap 可以做到无重启热更)。
- 对应架构图里 `Config Center`(菜单配置、开关配置、WebView 入口策略)暂时也落在 ConfigMap;如果后续配置项复杂到需要审批流程、按门店灰度下发、版本回滚,再评估引入独立配置中心(比如 Apollo)。
- Pod 需要有权限读取所在 namespace 的 ConfigMap`spring-cloud-kubernetes` 底层调用 K8s API),需要配置好对应的 `ServiceAccount` + `Role`/`RoleBinding`
## 附录:ConfigMap 和 Secret 的本质区别,以及为什么两者都要用
两者在 K8s API 层面结构几乎一样,都是 key-value 集合,区别主要在于:
- **Secret 的值默认 base64 编码存储**(不是加密,只是编码),K8s 对 Secret 有一些额外处理:不会出现在 `kubectl describe` 的默认输出里、可以配置只挂载到内存卷(`tmpfs`)不落盘、可以对接外部密钥管理服务(Azure Key Vault 等)做真正的静态加密和访问审计。
- **ConfigMap 没有这些额外保护**,设计上就是给"泄漏了也不严重"的配置用的。
所以规则很简单:**这个值如果出现在日志里、被同事在 `kubectl get configmap -o yaml` 时看到会不会造成安全问题**——会,就放 Secret;不会,就放 ConfigMap。DB 密码、JWT 签名密钥、第三方 API key 毫无疑问要放 Secret;而"首页降级提示文案"这种放哪都无所谓的东西放 ConfigMap 就行,还能享受到热更新不用走发布流程的好处。
## 待补充
- 具体 ConfigMap/Secret 命名规范和 namespace 划分细节。
- 多环境 profile 的详细参数列表。
- 是否需要接入 Azure Key Vault 做 Secret 的进一步加固。
## 参考链接
- [Spring Cloud Kubernetes 官方文档](https://docs.spring.io/spring-cloud-kubernetes/reference/)
- [Kubernetes ConfigMap 官方文档](https://kubernetes.io/docs/concepts/configuration/configmap/)
- [Kubernetes Secret 官方文档](https://kubernetes.io/docs/concepts/configuration/secret/)