发布实验:真实业务与隔离流量基线
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
本文缩写(英文全称与中文含义)
| 缩写 | 英文全称/名称 | 中文含义 |
|---|---|---|
| API | Application Programming Interface | 应用程序编程接口 |
| CI | Continuous Integration | 持续集成 |
| CPU | Central Processing Unit | 中央处理器 |
| CSI | Container Storage Interface | 容器存储接口 |
| DNS | Domain Name System | 域名系统 |
| GitOps | GitOps | 以 Git 保存期望状态、由自动化持续协调实际状态的运维方式 |
| HTTPS | Hypertext Transfer Protocol Secure | 使用 TLS 加密的 HTTP |
| IP | Internet Protocol | 网际协议;IP 地址是网络寻址标识 |
| NaN | Not a Number | 非数值结果 |
| RWO | ReadWriteOnce | 卷访问模式:由一个节点以读写方式挂载 |
| SLO | Service Level Objective | 服务等级目标 |
| TLS | Transport Layer Security | 传输层安全协议 |
| WAF | Web Application Firewall | Web 应用防火墙 |
前置:企业业务基线、Gateway API、Prometheus;使用 Bash、Python 3、jq、curl、kubectl。所有操作只对预生产 context,先核对 kubectl config current-context。使用真实 API 两个已签名 digest;外部支付/邮件使用沙箱,数据库与生产隔离。
1. 生成两套工作负载#
下载 生成脚本 为 prepare.py。它读取真实 Deployment Pod 模板,保留探针、Secret、ServiceAccount、资源和安全配置;使用专属标签避免原 Service 选中副本。
set -euo pipefail
export STABLE_IMAGE='REPLACE_REGISTRY/orders@sha256:REPLACE_DIGEST'
export CANDIDATE_IMAGE='REPLACE_REGISTRY/orders@sha256:REPLACE_DIGEST'
kubectl -n orders get deployment orders-api -o json > source.json
kubectl -n orders get services -o json > services.json
python3 prepare.py source.json services.json > release.json
kubectl apply --dry-run=server -f release.json审查生成清单:app 新标签对应的 NetworkPolicy/ServiceMonitor 必须补齐;脚本将 app.kubernetes.io/name 改为专属名称,并用同命名空间 Service 快照检查重叠,发现即停止。快照之后有 Service 变更时重新生成;发布期间冻结选择器变更。原标签对应的 NetworkPolicy、ServiceMonitor 和 PDB 也需调整,不能扩大原 Service selector 来“修复”新副本不可达。检查 affinity、挂载与 CSI:不能让两个版本竞争同一 RWO 卷。预留六副本加 surge 的 CPU、IP、Quota、数据库连接。使用独立 release 数据 Secret 时,在生成文件中替换引用。
kubectl apply -f release.json
kubectl -n orders rollout status deployment/orders-stable --timeout=10m
kubectl -n orders rollout status deployment/orders-candidate --timeout=10m
kubectl -n orders get endpointslices -l kubernetes.io/service-name=orders-candidate
kubectl -n orders get endpointslices -l kubernetes.io/service-name=orders-api -o yaml
# 原 orders-api 的 targetRef 必须只有原副本;若出现 stable/candidate,停止并删除 release.json。2. 独立发布域名#
平台在已有 edge/public Gateway 增加 release-https listener:使用 release.staging.example.com、443、HTTPS、独立有效 TLS Secret,allowedRoutes 仅 orders。按入口篇创建同 namespace 的 Certificate 并等待 Ready;保留原 listener,先核对 GatewayClass 是否支持同端口按 hostname 分流。域名指向该 Gateway 地址,沿用原入口认证/WAF;不能拿 orders.staging.example.com 的单域名证书充当 release 证书。
平台确认已有 acme-production ClusterIssuer 可为该域名签发后,保存 release-cert.yaml(否则替换成实际 issuer):
apiVersion: cert-manager.io/v1
kind: Certificate
metadata: {name: release-tls, namespace: edge}
spec:
secretName: release-tls
dnsNames: [release.staging.example.com]
issuerRef: {name: acme-production, kind: ClusterIssuer}kubectl apply -f release-cert.yaml
kubectl -n edge wait --for=condition=Ready certificate/release-tls --timeout=10m
kubectl -n edge get gateway public -o json > gateway-before.json
# 仅首次添加;若名字已存在,先检查现有 listener,不要重复追加。
jq -e '[.spec.listeners[]|select(.name=="release-https")]|length==0' gateway-before.json
kubectl -n edge patch gateway public --type=json -p '[{"op":"add","path":"/spec/listeners/-","value":{"name":"release-https","hostname":"release.staging.example.com","port":443,"protocol":"HTTPS","tls":{"mode":"Terminate","certificateRefs":[{"name":"release-tls"}]},"allowedRoutes":{"namespaces":{"from":"Selector","selector":{"matchLabels":{"kubernetes.io/metadata.name":"orders"}}}}}}]'将以下内容保存为 route-stable.yaml。listener 是明确的前置条件,未完成不能继续。
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata: {name: orders-release, namespace: orders}
spec:
parentRefs:
- {name: public, namespace: edge, sectionName: release-https}
hostnames: [release.staging.example.com]
rules:
- backendRefs:
- {name: orders-stable, port: 80, weight: 100}
- {name: orders-candidate, port: 80, weight: 0}kubectl apply --dry-run=server -f route-stable.yaml
kubectl apply -f route-stable.yaml
kubectl -n orders get httproute orders-release -o yaml
export BASE_URL='https://release.staging.example.com'
curl --fail-with-body "$BASE_URL/readyz"验收 listener Accepted/Programmed、Route 当前 generation 的 Accepted/ResolvedRefs=True,不存在其他同 hostname 冲突 Route。用真实业务鉴权完成创建/查询/幂等重放。API 响应或日志记录实际构建版本,避免只看期望权重。
3. 指标与恢复基线#
监控必须分别标识 release_track=stable|candidate;每次新 digest 清空旧观测窗口,等待完整新窗口,避免前次版本数据混入。为真实指标配置记录规则:
release_requests_10m{release="orders",track="candidate"}:完整 10 分钟请求增量。release_error_ratio_10m{release="orders",track="candidate"}:5xx/总请求。release_p95_seconds_10m{release="orders",track="candidate"}:histogram_quantile 计算,单位秒。
应用若暴露 http_requests_total(含 status)及 http_request_duration_seconds_bucket,且采集 relabel 已把 Pod 的 release_track 映射为 track,可采用以下 PrometheusRule.spec.groups;其他指标名称先映射,不能照抄后忽略 No data。PrometheusRule metadata labels 必须匹配现有 Prometheus ruleSelector,namespace 匹配 ruleNamespaceSelector。
groups:
- name: orders-release
interval: 30s
rules:
- record: release_requests_10m
labels: {release: orders, track: candidate}
expr: sum(increase(http_requests_total{namespace="orders",track="candidate"}[10m]))
- record: release_error_ratio_10m
labels: {release: orders, track: candidate}
expr: (sum(increase(http_requests_total{namespace="orders",track="candidate",status=~"5.."}[10m])) or vector(0)) / sum(increase(http_requests_total{namespace="orders",track="candidate"}[10m]))
- record: release_p95_seconds_10m
labels: {release: orders, track: candidate}
expr: histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket{namespace="orders",track="candidate"}[10m])))门禁额外查询 min(up{namespace="orders",track="candidate"}),所以 target relabel 也必须提供 namespace/track。采集目标必须全部 up,5xx counter 按 status 正确初始化,监控中断立即停止发布;窗口内旧样本可能继续产生结果,不能只看记录规则的新 timestamp。多集群 Prometheus 的表达式和 gate.py 原始 up 查询还必须增加 cluster 过滤。预期目标数应与 Ready 候选副本一致,防止 ServiceMonitor 漏选部分副本。Prometheus recording rule 每项必须只返回一个结果。下载 门禁脚本 为 gate.py,设置 PROM_URL 为经过鉴权的内网 Prometheus API;可设置短期 PROM_TOKEN。默认要求 1000 请求、5xx≤1%、p95≤0.5s,需按业务 SLO 调整脚本并入 Git。
export PROM_URL='https://prometheus.internal.example.com'
python3 gate.py缺指标、多序列、过期值、NaN、查询失败均失败;再执行 业务压测 验证写入/消息/账务。任何异常恢复 route-stable.yaml,确认实际请求回旧版本;连接排空期间保留 candidate。禁止同时用 GitOps 和手工命令抢写:演练目录暂不自动同步,生产由单一 CI/GitOps 流程提交同样文件。
结束:先删除 release Route,确认无访问,再删除 release.json 中的专属资源;单独移除 release listener/证书/DNS,保留共享 Gateway 与原 orders 服务。