十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

原生 Kubernetes RollingUpdate 加固指南:Pusher 优雅排空、失败关闭门禁与 N/N-1 回滚契约

原生 Kubernetes RollingUpdate 加固指南:Pusher 优雅排空、失败关闭门禁与 N/N-1 回滚契约 原生 Kubernetes RollingUpdate 加固指南Pusher 优雅排空、失败关闭门禁与 N/N-1 回滚契约【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend导读本文以backend/charts/pusher的 GKE 工作负载为对象系统讲解原生 KubernetesRollingUpdate的完整加固方案如何在持有长连接 WebSocket 的服务上实现零新连接拒绝 有界重连窗口的优雅排空如何用探针拆分、preStop应用级 drain 与 BackendConfigconnectionDraining精确控制终止时序以及部署前必须通过的失败关闭fail-closed预算与质量门禁、共享 ConfigMap/Secret 迁移守卫和 N/N-1 兼容性红线。读完本文你将获得一套可直接复用的滚动发布运维手册从helm template渲染核对、静态预检、实时容量门禁到不可变镜像身份部署、安全回滚与 dev-first 资格认证流程。一、文档定位与适用范围这是一份 pusher GKE 工作负载加固后的原生 KubernetesRollingUpdate的运维契约文档。它刻意不是设计散文而是明确说明操作者与开发者可以依赖什么、Chart 实际产生的精确终止序列、滚动发布被允许前必须通过的预检门禁以及 N/N-1 兼容性规则。范围与所有权约定Chart values 是滚动发布输入的单一事实来源backend/charts/pusher/dev_omi_pusher_values.yaml 与 backend/charts/pusher/prod_omi_pusher_values.yaml。当线上集群与 Chart 不一致时以 Chart 为准差距属于需要收敛的部署漂移问题而不是削弱 Chart 的理由。本次加固仅限原生RollingUpdate。Argo Rollouts、Flagger、Service Mesh、Gateway API、双色发布均不在范围内。生产采用是后续的、明确的决定。本文档在既有 pusher 基线上落地加固与运维契约当前资格为dev 优先见八、Dev 资格认证计划。在 SCA-40 落地且确认生产 pusher 基线健康之前不要将本文档解读为pusher 已为新的发布方式做好生产准备。相关 runbookbackend/docs/runbooks/pusher-degraded.md 覆盖持续的降级会话占比问题本文覆盖发布本身。二、诚实的可用性契约文档开篇直白声明一个约束所有后续操作决策的前提没有任何方式能在经 ALB NEG 代理的路径上跨 pusher 切换保留在途 WebSocket 会话。Pusher 持有来自 backend-listen 的长连接二进制 WebSocket 会话当某个 Pod 的端点离开 NEG 时负载均衡器会切断其上的既有连接。在此前提下优雅排空graceful drain的精确含义是承诺说明健康发布期间零新连接拒绝就绪门禁将排空中的 Pod 翻转为503负载均衡器不再向其路由新会话其他 Pod 继续服务新 backend-listen 连接打到健康 Pod每个受影响会话的有界重连窗口约 1–60 秒backend-listen 负责重连pusher socket 被切断后它会重连到健康 Pod窗口是切断到下一次成功重连的时间差而非迁移LB 切断受 BackendConfigconnectionDraining约束它决定端点离开 NEG 后负载均衡器等待多久再硬切在途连接——此处为drainingTimeoutSec: 60没有它默认是端点移除时立即硬切后台终结受 Pod 宽限期约束在途工作批量上传 GCS 的音频、路由到集成的转录、LLM 分析、说话人样本提取由应用在terminationGracePeriodSeconds内排空超时仍在运行的任务被 SIGKILL。持久化终结由 conversation-finalization 作业通道对账因此被 SIGKILL 的会话不会让对话卡在processing不要声称亚秒级或零会话影响的切换。契约是新连接持续流动、既有会话经历有界重连窗口、后台工作要么完成要么被持久化对账。该契约在应用层也有代码支撑backend/pusher/main.py 中的/ready端点依据ReadinessGate.is_serving()返回200serving或503drainingbackend/utils/readiness.py 的模块注释同样强调翻转 DRAINING 只停止新连接在途会话不会在 ALBNEG 路径上迁移永远不要把 drain 当作亚秒级或零会话影响。三、加固内容变更前后对比加固之前Chart 将 liveness、readiness、startup 三个探针全部指向/health没有应用级排空preStop只有sleep 15BackendConfig 也没有connectionDraining端点移除时 LB 硬切在途 WebSocket。加固的核心动作是把服务就绪信号从存活信号中拆分出来并加入应用级排空关注点加固前加固后就绪信号readinessProbe-/healthreadinessProbe-/ready200 serving / 503 drainingliveness / startup/health不变仍为/healthLB 健康检查BackendConfighealthCheck.requestPath: /health不变仍为/health新连接排空无preStopsleep 15preStop:curl -sf -m 5 -X POST http://localhost:8080/__internal/drain \|\| true; sleep 15——POSTloopback将/ready翻转为 503\|\| true保证 drain 调用失败也不阻塞终止sleep 15覆盖 NEG 收敛LB 在途切断无缺少connectionDraining端点移除即硬切BackendConfigconnectionDraining.drainingTimeoutSec: 60约束 LB 等待60 宽限 120以上配置在 dev/prod 两份 values 文件中均有落实lifecycle.preStop.exec.command完全一致见 dev values 与 prod values注释说明了设计意图preStop 通过/__internal/drain提前翻转就绪让 kubelet 尽早移除端点sleep 覆盖 NEG → backend-service → ALB 重编程收敛后再发 SIGTERM。探针拆分见 prod valueslivenessProbe与startupProbe指向/healthreadinessProbe指向/readyfailureThreshold: 3、periodSeconds: 10。backendconfig.yaml 渲染connectionDraining.drainingTimeoutSec默认 60并强制healthCheck.requestPath: /health——模板注释明确健康检查必须保留 liveness 语义路由到/ready会在排空期间把 backend 翻为不健康从而让 connectionDraining 失效。本次加固引入的端点pusher 进程端口 8080GET /ready- 服务中返回200进程进入排空后返回503。POST /__internal/drain-仅限 loopback。触发排空将/ready翻转为 503并让后台终结在宽限期内跑完。preStop是唯一预期的调用方。后端实现上backend/pusher/main.py 对/__internal/drain做了严格的信任边界校验仅接受request.client.host为127.0.0.1或::1的 loopback 对端其他一律403。该屏障依赖 uvicorn不启用--proxy-headers因此request.client.host是真实 TCP 对端而非可伪造的X-Forwarded-For。同时排空是幂等的——ReadinessGate.begin_drain() 首次调用原子地翻转 SERVING → DRAINING 并记录单调时钟起点后续调用为 no-op因此 preStop 钩子与 SIGTERM 驱动的 lifespan shutdown 可以安全地同时调用。此外 shutdown_event() 提供纵深防御即使 Chart 的 preStop 钩子未执行进程关闭时也会先关闭就绪ReadinessGate.begin_drain()再在 10 秒内排空后台任务drain_background_tasks并关闭异步 HTTP 客户端池。复用的既有正确输入已对照 dev/prod values 验证以下发布输入在 Chart 中已经正确直接复用而非重建progressDeadlineSeconds: 9600dev 与 prod 两份 values 均有。CI 从 Chart 推导健康发布预算backend/scripts/verify_pusher_rollout_budget.pyprod 在 40 Pod 的 HPA 上限下是 14 波 × ~640s 可用性 8960s 健康预算以 9600s 作为承诺的截止时间。线上某 release 观察到的 600 是部署漂移缺口而非 Chart 缺口——Chart 值保持 9600真实部署必须把集群收敛到该值。prodstrategy: RollingUpdate { maxUnavailable: 1, maxSurge: 2 }dev 为{ maxUnavailable: 0, maxSurge: 1 }。两份 values 均为terminationGracePeriodSeconds: 120。prod 自动扩缩minReplicas: 12、maxReplicas: 40、activeConnectionsPerPod: 30devminReplicas: 1、maxReplicas: 3。prod values 注释说明activeConnectionsPerPod: 30特意高于 backend-listen 的 22因为 pusher 的 WebSocket 处理画像每 Pod 可维持 30 个并发连接。两份 values 均为podDisruptionBudget.minAvailable: 80%。专用开发 Pusher 容量开发环境 Pusher 单独容忍dedicatedpusher:NoSchedule污点。其既有必选节点亲和仍要求匹配servicepusher与envdev标签因此该容忍不会把 LLM Gateway、Agent Proxy 或其他工作负载放进该资源池。生产刻意不保留对应的容忍这是独立的配置边界。dev values 中的tolerations与affinity在 dev values 中显式声明。开发 Pusher 发布之前外部批准执行的 GKE 操作必须提供两个满足该亲和且 Ready、可调度的 Pusher 专用节点每个节点打上dedicatedpusher:NoSchedule污点。两个匹配节点为单个服务 Pod 及其滚动更新中的maxSurge: 1替换 Pod 留出空间。Helm 只渲染工作负载的容忍它不创建、不打标签、不污点、不扩缩 GKE 节点容量。Dev HPA 保持minReplicas: 1、maxReplicas: 3滚动更新设置保持maxSurge: 1、maxUnavailable: 0。失败关闭的发布门禁部署前必须通过的预检脚本列在五、运维手册中阻塞信号列在六、失败关闭的发布质量门禁中。四、终止序列单 Pod 替换对于RollingUpdate期间被替换的单个 PodChart 产生的精确时序如下与 templates/deployment.yaml 及两份 values 文件一致Pod 进入Terminating。Kubernetes 启动 Pod 的terminationGracePeriodSeconds: 120时钟。preStop钩子与端点移除并行运行。它执行curl -sf -m 5 -X POST http://localhost:8080/__internal/drain || true; sleep 15——POSTloopback将/ready翻转为 503|| true保证 drain 调用失败也不阻塞终止sleep 15在 SIGTERM 前给 NEG 留出收敛时间。就绪开始失败端点离开 NEG。就绪探针为failureThreshold: 3×periodSeconds: 10因此排空中的 Pod 在/ready变为 503 后约30 秒被从 Service/NEG 端点移除。此后 LB 不再向该 Pod 发送新连接。SIGTERM送达在preStop完成后sleep 15界定了耗时上限。pusher 生命周期关闭排空进程级后台任务drain_background_tasks并关闭异步 HTTP 客户端池。后台终结在宽限期内排空。每个活跃 WebSocket 会话排空其后台任务队列由 WS 处理器中的BG_DRAIN_TIMEOUT界定能在剩余宽限内完成的音频/转录/分析工作都会完成。120 秒时SIGKILL。宽限截止仍在运行的内容被杀死。被 SIGKILL 的会话不会滞留对话持久化终结由 conversation-finalization 作业通道对账。关键时序旋钮及其约束对象旋钮约束内容preStopsleep 15SIGTERM 前的 NEG 收敛窗口就绪failureThreshold * periodSeconds约 30s/ready翻转 503 后端点实际被移出 NEG 的耗时BackendConfigconnectionDraining.drainingTimeoutSec: 60LB 硬切被移除端点上的在途连接前的等待时间刻意 120s Pod 宽限terminationGracePeriodSeconds: 120SIGKILL 前后台终结的硬上限这些旋钮都被静态契约校验强制保护verify_pusher_rollout_budget.py 的validate_probe_and_drain_contract校验三探针路径readiness →/readyliveness/startup →/health以及drainingTimeoutSec terminationGracePeriodSeconds的不变式同时校验 BackendConfig 健康检查必须渲染到/health否则排空期间会翻转 backend 不健康、使 connectionDraining 失效。五、运维手册Operator runbook运维步骤小而难用错从与目标部署镜像匹配的仓库 checkout 根目录执行。1. 渲染 Chart 并确认输入渲染 dev 与 prod目测驱动可用性的值helm template pusher backend/charts/pusher \ -f backend/charts/pusher/dev_omi_pusher_values.yaml \ --set-string image.digestsha256:64-lowercase-hex \ --set-string image.tag \ --set-string image.pullPolicyIfNotPresent /tmp/pusher-dev.yaml helm template pusher backend/charts/pusher \ -f backend/charts/pusher/prod_omi_pusher_values.yaml \ --set-string image.digestsha256:64-lowercase-hex \ --set-string image.tag \ --set-string image.pullPolicyIfNotPresent /tmp/pusher-prod.yaml在渲染输出中确认readinessProbe.httpGet.path: /ready、livenessProbe/startupProbe指向/health、BackendConfighealthCheck指向/health且带connectionDraining、preStop调用/__internal/drain、progressDeadlineSeconds: 9600。确认 dev Deployment 带dedicatedpusher:NoSchedule容忍而 prod Deployment 不带。Chart 模板层面对镜像身份有强校验在 templates/deployment.yaml 中若设置了image.digest则必须是sha256:[a-f0-9]{64}格式否则渲染失败且image.tag必须为空、pullPolicy必须为IfNotPresentdigest 即内容地址Always只会多一次 registry 往返。渲染时 malformed/ambiguous 身份会被拒绝。2. 运行失败关闭的预检Chart 预算与发布门禁都必须通过。两者都是无依赖的静态/契约检查仅标准库不读集群或 registry# 从 Chart 推导健康发布预算波次 x 可用性并在 progressDeadlineSeconds # 或工作流 rollout 超时低于预算时失败。 python3 backend/scripts/verify_pusher_rollout_budget.py # 静态 契约预检容量余量、镜像/配置身份、探针拆分 # 以及发布阻塞指标是否在 utils/metrics.py 中定义。 python3 backend/scripts/verify_pusher_rollout_gate.py preflightverify_pusher_rollout_budget.py将 prod 重算为十四波 × ~640s若progressDeadlineSeconds低于预算或某个工作流的kubectl rollout status ... --timeout过短则失败。核心推导逻辑在 rollout_budget()以 HPAmaxReplicas为上限pods_in_flight maxSurge maxUnavailablewaves ceil(replica_ceiling / pods_in_flight)单 Pod 可用性 startup 探针预算initialDelay failureThreshold × max(period, timeout) readiness 预算initialDelay (failure success) × max(period, timeout)minReadySeconds。以 prod 为例startup 0 60×10 600sreadiness 0 (31)×10 40sminReady 0即每 Pod 640s14 波 × 640s 8960s由progressDeadlineSeconds: 9600覆盖。脚本还会校验模板必须渲染minReadySeconds与progressDeadlineSeconds来自.Values见 validate_template。verify_pusher_rollout_gate.py preflight默认子命令在任何门禁未通过时失败关闭非零退出。它静态检查见 validate_preflight容量余量podDisruptionBudget.minAvailable必须存在、启用 autoscaling 时 HPAminReplicas必须存在、maxUnavailable 1且maxSurge 1、terminationGracePeriodSeconds connectionDraining超时镜像身份tag 模式将 tag 委托给部署工作流tag: 仅是 INFOdigest 固定build-once promotion必须是精确的sha256:hex且 tag 置空、pullPolicy: IfNotPresent探针拆分readinessProbe-/ready、liveness/startup -/health、connectionDraining存在且 BackendConfighealthCheck.requestPath渲染为/health遥测定义发布阻塞指标必须在utils/metrics.py中定义——缺少某个指标的定义就是失败因为无法用不存在的遥测判断发布是否健康。它不抓取实时值实时契约检查使用... rollback --env envrollback 模式是只读捕获输出结构化 JSON绝不执行任何回滚、部署或集群变更。不要为了通过检查而削弱 Chart修复输入。3. 实时生产门禁与开发资格认证镜像摘要提升自动化的开发 Pusher 工作流构建一次解析推送的sha256摘要运行 ConfigMap 引用与实时容量门禁等待发布完成之后才上传pusher-dev-qualification。生产保持手动需要该摘要加成功的开发运行 ID。生产工作流下载 attestation校验其确切的 GitHub 运行与主源 SHA拒绝自 bake 以来 Pusher 源码/Chart 漂移将同一摘要复制到生产 registry并部署repositorysha256:...。它从不重建生产 Pusher 镜像。紧邻 Helm 之前verify_pusher_live_deployment_gate.py渲染该确切摘要并只读取 Kubernetes 元数据。它失败关闭除非下一个maxSurge波次能放进一个满足 Pusher 亲和与容忍的 Ready、可调度节点。这是容量证据不是发布已有产品流量或用户成功证据的声明。dev Pusher 仪表盘由隔离的 dev Prometheus 抓取支撑。它展示既有连接、就绪/排空、重连/恢复以及 backend-listen 熔断聚合外加目标健康度不制造流量。仅 Pod 健康不是产品成功证据。只读开发证据边界开发 Prometheus 任务只发现带envdev工作负载标签的dev-omi-backendPod。它们保留既有 bearer-token 文件引用不要直接抓取/metrics、检查 token、复制请求头或削弱认证。仪表盘只包含低基数的聚合与目标标签job、namespace、pod绝不包含连接 ID、用户数据或请求负载。若需在许可的只读操作平面做被动的开发 bake 检查可使用 Pusher 仪表盘或以下等价 PromQL 表达式活跃 Pusher WebSocketsum(pusher_active_ws_connections{jobpusher-metrics})正在重连或降级的会话sum(pusher_sessions_degraded{jobbackend-listen-metrics})重连熔断状态与拒绝次数pusher_circuit_breaker_state{jobbackend-listen-metrics}与sum(rate(pusher_circuit_breaker_rejections_total{jobbackend-listen-metrics}[5m]))已认证抓取目标健康up{job~pusher-metrics|backend-listen-metrics}up 1只证明 Prometheus 完成认证并抓取了一个目标不是连接、排空或恢复证明。恢复聚合只会在真实客户端重连时变化。若被动窗口内不存在真实连接请把重连/恢复记录为未证实unproven——不要制造合成流量来让信号非零。4. 共享 ConfigMap/Secret 迁移守卫密钥变更时必需2026-07-22 的生产 Pusher 事故是非原子的跨资源迁移共享密钥REDIS_DB_HOST在来源中停止物化而线上 pusher Pod 仍引用它。Pusher 通过envFrom批量加载全部 ConfigMap 键因此从该对象移除某个键会让 Pod 进入CreateContainerConfigError而/health仍保持绿色——舰队在没有探针信号的情况下跌到零健康 Pod。verify_shared_config_migration.py在任何变更前失败关闭只要某个服务工作负载仍引用被提议状态移除或改类的 ConfigMap/Secret 来源或键。守卫的实现与事故复盘见 backend/scripts/verify_shared_config_migration.py它同时扫描两种绑定风格显式按键引用env[].valueFrom.configMapKeyRef/secretKeyRef与整对象批量加载envFrom[].configMapRef/secretRef。预检CI / pre-push仅标准库。python3 backend/scripts/verify_shared_config_migration.py preflight扫描 pusher Chart values在出现双来源绑定或畸形valueFrom时失败。注册为shared-config-migration-preflight见 .github/checks-manifest.yaml自动运行。它没有清单因此无法检测从批量加载对象中移除的键。守卫模式操作者调用——事故的真正根因修复。在任何会新增、移除或移动 pusher 或任何服务工作负载Deployment/StatefulSet/DaemonSet/Job/CronJob/ReplicaSet含initContainers所消费的 ConfigMap/Secret键的变更之前运行。它解析每个env.valueFrom、envFrom及按键引用对照提议的来源清单在移除/改类键时失败关闭。它只读对象与键的名称——从不读 ConfigMap/Secret 的值。# 渲染提议状态--rendered 可跨环境/工作负载重复 helm template pusher backend/charts/pusher \ -f backend/charts/pusher/prod_omi_pusher_values.yaml \ --set-string image.digestsha256:64-lowercase-hex \ --set-string image.tag \ --set-string image.pullPolicyIfNotPresent /tmp/pusher-prod.yaml # 以守卫清单格式捕获当前线上键名 # ({configmaps: {obj: [key,...]}, secrets: {...}} —— 仅名称绝不取值) kubectl -n env-omi-backend get configmap cfg -o json \ | jq {configmaps: {(.metadata.name): (.data | keys)}} /tmp/live-keys.yaml # 以同样形状编写 /tmp/proposed-keys.yaml写明对象在变更后携带的键 # 然后运行守卫。--previous-inventory 正是捕获从 envFrom 批量加载对象中移除 # 键的那类事故的关键没有它envFrom 移除是静默的。 python3 backend/scripts/verify_shared_config_migration.py guard \ --rendered /tmp/pusher-prod.yaml \ --source-inventory /tmp/proposed-keys.yaml \ --previous-inventory /tmp/live-keys.yaml非零退出 某个服务工作负载仍引用被提议状态移除或改类的来源/键不要应用。需要 PyYAMLbackend venv 或pip install pyyaml。5. 部署不可变标签部署确切的 short-SHA 镜像标签。绝不部署latest也不允许仅改 Chart 的部署把工作负载重置回latest按.github/AGENTS.md的约定。部署工作流必须用kubectl rollout status deploy/env-omi-pusher --timeout...等待发布完成并在超时后失败。实际工作流中该超时被设为--timeout9600s与 Chart 的progressDeadlineSeconds: 9600对齐见 .github/workflows/gcp_backend_pusher.yml。6. 回滚回滚 用先前的不可变镜像标签不是latest重新执行 Helm 部署。因为流量/运行时回滚到 N-1 在设计上始终安全见七、N/N-1 兼容性清单这是默认回滚路径把 Chart 指向先前标签并部署。生产采用是单独的、后续的决定。在 SCA-40digest Chart 支持、仅 Chart/复用镜像部署模式、回滚证据落地且确认健康的 pusher prod 基线之前不要把本次加固的生产回滚视为可用。见九、后续部署控制。verify_pusher_rollout_gate.py rollback --env prod会以结构化 JSON 输出只读的回滚契约见 rollback_contract包括捕获当前部署镜像的命令tag 模式用kubectl get deployment release -o jsonpath{.spec.template.spec.containers[0].image} | sed s/.*://digest 模式用grep -oE sha256:[a-f0-9]{64}、恢复命令tag 模式与 digest 模式的helm upgrade --install两种写法、以及流量回滚安全且始终可用与数据回滚不可逆、绝不自动回滚的明确区分。六、失败关闭的发布质量门禁fail-closed存在两个失败关闭层且两层都必须成立静态/契约预检部署前运行见五、运维手册——verify_pusher_rollout_gate.py preflight断言容量、身份、探针拆分与指标定义契约。若某个阻塞指标连定义都没有就失败因为无法用不存在的遥测判断发布是否健康。它不抓取实时值。实时发布门禁部署期间监控——阻塞信号必须为绿且充分填充。压倒一切的规则是遥测缺失 暂停或失败绝不是绿。静默或不可抓取的仪表盘是失败的门禁不是通过的门禁。阻塞信号pusher / backend-listen 发出的真实指标名指标含义与发布判据pusher_active_ws_connections活跃 pusher WebSocket 会话。新 Pod 必须接受会话且计数恢复到发布前基线平线意味着新 Pod 未接受流量backend_listen_active_ws_connections路径的 backend-listen 侧持续下降且无恢复表示监听者重连失败pusher_circuit_breaker_state0 关闭 / 1 打开 / 2 半开与pusher_circuit_breaker_rejections_total发布期间熔断打开或拒绝上升 pusher 在拒绝连接pusher_sessions_degradedbackend-listen 从 pusher 路由走的会话。持续偏高见 backend/docs/runbooks/pusher-degraded.md是用户影响信号omi_journey_terminal_total{journeypusher_session}终态会话结果failure关闭码 1011 / 应用失败上升是回归omi_journey_latency_seconds{journeypusher_session}端到端会话延迟发布不得把它推出有界阈值之外终结健康listen_finalization_jobs、listen_finalization_retries_total、listen_finalization_dead_letter_total、listen_finalization_oldest_nonterminal_age_seconds发布期间重试、死信或最老非终态年龄飙升 排空不干净这些指标的定义可在 backend/utils/metrics.py 中找到pusher_active_ws_connections在第 21 行、pusher_circuit_breaker_state第 43 行、pusher_sessions_degraded第 53 行、omi_journey_terminal_total第 64 行、omi_journey_latency_seconds第 70 行pusher_ready与pusher_drain_in_progress在第 643/647 行附近由 readiness.py 在排空时翻转 gauge。verify_pusher_rollout_gate.py的ROLLOUT_BLOCKING_METRICS元组第 71-77 行静态扫描这些名字必须作为字符串字面量出现在metrics.py中否则预检直接失败。门禁要求最低能力/会话计数加上有界的错误与延迟阈值而不只是经过的时间。纯时间门禁被禁止仅仅够老但没服务足够会话、或超出错误/延迟边界的发布不是绿的。七、N/N-1 兼容性清单区分两种回滚流量/运行时回滚到 N-1 在设计上始终安全。把 Chart 重新指向先前不可变标签并重新部署从不要求数据迁移来撤销。这是操作者在压力下唯一需要执行的回滚。不可逆数据变更属于不同类别绝不能被发布的回滚路径要求。如果变更是不可逆的设计义务是让 N 与 N-1 共存加性、双读/双写或特性门控使流量可以在不进行数据回滚的情况下回到 N-1。引入以下任何不兼容之前必须先在 N-1 上完全排空这些变更会破坏安全回滚到 N-1因此不能搭常规滚动更新的便车信封/密钥变更ENCRYPTION_SECRET或按用户信封推导backend/utils/encryption.py 中的 HKDF-SHA256。N-1 无法解密 N 写入的片段。GCS 音频块信封pusher 批量/上传 GCS 音频块方式的变更且 N-1 无法读回。新增ConversationStatus或任何持久化处理状态枚举N-1 无法识别且会误处理。持久化模型上移除或重命名的读取字段已发布的 app 客户端或 N-1 服务仍会读取。Redis 键或 TTL 变更N-1 解释不同缓存、限流桶、listen 锁。终结租约/围栏协议变更持久化对话终结的租约与围栏协议pusher 强制执行的durable_job_required/ claim / lease-epoch 契约——此类变更可能让 N-1 会话重复处理或绕过持久化 claim。如果变更触及以上任何一项它不适合走本次加固的滚动更新除非有文档化的 N/N-1 共存计划并在相关时先完整排空 N-1。常规推送探针/排空/可用性加固、非破坏性加性字段则搭乘滚动更新并通过把 Chart 指回 N-1 来回滚。八、Dev 资格认证计划本次加固按dev 优先认证。Dev 是端到端证明编排就绪翻转、应用排空、NEG 收敛、重连窗口、终结排空的地方然后才谈生产考虑。在 dev 上认证pusher dev1-3 PodmaxUnavailable: 0 / maxSurge: 1构建一次并渲染摘要方式与五、运维手册完全一致。自动工作流只在开发发布成功后才记录其摘要。观察被动 bake。使用 dev Pusher 仪表盘的连接、就绪/排空与重连熔断面板。不要制造流量也不要只凭就绪推断产品成功。用生成的 attestation 发起手动生产请求。提供确切摘要与开发认证运行 ID生产工作流在 Helm 变更前校验证据、实时 ConfigMap 引用、确切摘要渲染与真实的下一波容量。把证据记录在 PR 中命令、输出、门禁结果按根目录AGENTS.md的完成定义。必须明确承认 dev 认证的局限dev 证明编排不证明生产规模的 NEG/ILB 行为。Dev 只跑 1-3 个 Pod、WebSocket 流量低因此它能演练就绪/排空/重连序列但不能证明生产规模的 NEG 传播、生产 40-Pod / 十四波发布或生产 ILB 连接排空。这些需要以 SCA-40 与健康的生产 pusher 基线为前提的、后续独立的生产证明。九、后续部署控制SCA-115SCA-115 完成对原生 RollingUpdate 加固的有界后续工作镜像摘要身份从一次成功的开发发布中选择提升保留那份确切的清单摘要生产工作流在变更 Pusher release 前先对线上集群的下一波 surge 容量做门禁。既有回滚契约仍是独立的操作者动作该工作流不会自动回滚流量或数据。结合 SCA-40digest Chart 支持与回滚证据这构成了 pusher 滚动发布从加固落地走向生产可证明的完整演进路径dev 证明编排 → 生产证明容量与 NEG/ILB 行为 → 不可变摘要提升 → 独立的人工回滚契约。附相关仓库文件索引Chart 输入backend/charts/pusher 目录下的 dev values 与 prod valuesChart 模板backend/charts/pusher/templates/deployment.yaml、backend/charts/pusher/templates/backendconfig.yaml发布预算推导backend/scripts/verify_pusher_rollout_budget.py失败关闭门禁 回滚契约backend/scripts/verify_pusher_rollout_gate.py共享配置迁移守卫backend/scripts/verify_shared_config_migration.py应用层排空实现backend/pusher/main.py、backend/utils/readiness.py发布阻塞指标定义backend/utils/metrics.py发布工作流.github/workflows/gcp_backend_pusher.yml、.github/workflows/gcp_backend_pusher_auto_deploy.yml相关 runbookbackend/docs/runbooks/pusher-degraded.md【免费下载链接】FriendAI that sees your screen, listens to your conversations and tells you what to do项目地址: https://gitcode.com/GitHub_Trending/fr/Friend创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表