服务网格升级、迁移与弃用治理:用双轨验证完成可证明的退出
Istio canary 升级中,新旧 istiod Ready 且测试 namespace 已改成新 revision,只说明控制面和未来注入目标已准备。现有 sidecar 不会因 namespace 标签变化而自动重建,手工安装并原地升级的 gateway 也可能不属于任一可回退 revision。控制面双跑若没有覆盖正在承载请求的数据面,就不能作为卸载旧控制面的依据。
迁移 Gateway API 所有权时,如果先在旧 Helm release 中关闭 CRD 管理,再部署新的 CRD bundle,Helm 可能把原 CRD 视作应删除资源,依赖它的 Route 实例也会消失。重新创建 CRD 不能恢复已删除对象;节点 CNI、旧代理和新策略控制器还会形成“请求仍被截获,但没有完整控制面负责”的半迁移状态。
升级单位不是控制面 Pod,而是一组有顺序的状态
服务网格的版本状态分散在 API server、控制器、节点和工作负载中。一个可回滚变更至少包含以下对象:
CRD 决定对象能否保存、以哪个版本保存和如何转换;控制面读取这些对象并产生配置;CNI、eBPF 或 iptables 决定请求是否进入数据面;代理执行路由、授权和证书验证;CA 与 issuer 决定新身份能否签发;遥测决定团队是否看得见迁移中的偏差。只替换其中一个组件,会产生版本偏差窗口,而不是完成升级。
把每次变更写成版本事务:固定源版本和目标版本,声明允许的 skew,定义每个对象的 owner,列出提交点和回滚点。事务不要求所有组件原子更新,但要求任何阶段都只有一套清晰的请求语义,并能停止继续推进。若 CRD/storage 已迁移到旧二进制无法读取的格式,回滚就不再是“换回旧镜像”,而是恢复状态备份或执行反向迁移。
先做资产账本,再安装候选版本
升级前从目标产品的支持页、upgrade notes 和安装入口确定可行路径。Istio canary 可跨官方允许的 minor 窗口,in-place 要逐 minor;Cilium 只测试相邻 minor 的升级与回滚;Kuma 一次最多跨两个 minor;Consul 需要按版本里程碑和逐版本 notes 计算路径;OpenShift Service Mesh 还受 Operator channel、OCP 和 downstream 支持矩阵约束。任何 latest、chart 浮动版本或未固定 digest 都会让回滚基线失去意义。
资产账本至少导出这些内容,并标明 owner 与恢复入口:
Helm release、values、Operator CR、镜像 digest、CLI 与 Kubernetes 版本;CRD 的 served/storage versions、conversion webhook、所有 CR 实例与 finalizer;Gateway API bundle、实现 conformance、Gateway/Route/ReferenceGrant 和 CRD owner;
namespace/Pod 注入标签与注解、revision tag、webhook selector;CNI 配置、DaemonSet、节点规则、eBPF/iptables、gateway/waypoint;sidecar、ztunnel、dataplane、Envoy 与扩展组件版本分布;
identity root/intermediate、issuer、trust bundle、证书有效期和轮换任务;授权、路由、超时重试、egress、多集群、遥测、dashboard 与 alert;remote secret、ServiceAccount、ACL token、LoadBalancer、DNS、PVC 和云费用资源。
以下命令只读取状态,适合建立基线;输出仍可能包含内部服务名、地址和身份,应存入受控证据库,不要直接贴到工单或公开日志:
kubectl get crd -o custom-columns=NAME:.metadata.name,STORAGE:.status.storedVersions
kubectl get mutatingwebhookconfigurations,validatingwebhookconfigurations
kubectl get ns --show-labels
kubectl get pods -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
helm list -A
istioctl proxy-status安装候选版本前验证权限边界。平台发布身份可以更新 CRD、webhook、ClusterRole、CNI 和控制面;应用发布身份只应迁移指定 namespace;PKI 身份负责 issuer 与根信任;观测身份只能读取必要状态。临时 kubeconfig、registry credential、remote token、CA 私钥和 Helm registry credential 不得进入 values、命令行历史或流水线明文日志。候选镜像应固定 digest 并保留签名、SBOM 与来源记录。
弃用发现要覆盖“仓库里有什么、集群存了什么、运行时还有谁在调用”三层。只搜索 YAML 会漏掉 Helm 渲染、Operator 生成对象、旧控制器和外部客户端;只看 API server 对象又会漏掉尚未部署的分支。先用与目标 release 对齐的 CLI 分析期望配置和现存配置,再结合 Kubernetes 的 Warning、审计事件与 API 指标识别真实调用者:
# 候选 istioctl 对 Git 中的完整渲染结果做离线分析
istioctl analyze --use-kube=false rendered-mesh/*.yaml
# 对现存所有 namespace 做只读分析,IST0002 表示依赖已弃用能力
istioctl analyze --all-namespaces
# CRD 的 served/storage 与历史存储版本必须分别观察
kubectl get crd \
-o custom-columns='NAME:.metadata.name,SERVED:.spec.versions[*].served,STORAGE:.spec.versions[*].storage,STORED:.status.storedVersions'Kubernetes 从 1.19 起会为弃用 API 请求返回 Warning、在审计事件标记 k8s.io/deprecated=true,并暴露 apiserver_requested_deprecated_apis。指标为 1 只说明至少有请求发生,还要用审计中的 user agent、身份和对象定位调用者;仓库扫描为零也不能覆盖集群外客户端。CRD 把新版本标为 storage: true 后,旧对象不会自动改写;只有完成存储迁移并确认旧版本从 status.storedVersions 消失,才能关闭旧 served 和 conversion webhook。Kubernetes 弃用策略 CRD 版本迁移
每一条弃用项都要有 owner、最后调用者、替代对象、语义差异、迁移批次和删除 release。istioctl analyze 能发现配置问题,但官方明确它只分析 Kubernetes 配置,不观察真实流量;因此 IST0002 清零只是进入请求实验的条件,不是删除旧能力的依据。Istio 配置分析
用 Istio revision 建立最小 canary
Istio 官方推荐 canary/revision 升级。先用目标版本 CLI 对源版本做 precheck,再升级共享 base/CRD,最后并行安装不可变 revision。版本和 revision 由发布流水线显式注入;参数未设置时让 shell 立即退出,避免尖括号占位符被误当成重定向:
: "${SOURCE_MINOR:?set the installed Istio minor, for example 1.x}"
: "${TARGET_VERSION:?set the pinned target chart version}"
: "${TARGET_REVISION:?set an immutable target revision}"
istioctl x precheck --from-version="${SOURCE_MINOR}"
helm upgrade istio-base istio/base \
--namespace istio-system \
--version "${TARGET_VERSION}" \
-f base-values.yaml
helm install istiod-canary istio/istiod \
--namespace istio-system \
--version "${TARGET_VERSION}" \
--set "revision=${TARGET_REVISION}" \
-f istiod-values.yamlbase/CRD 是共享资源,不属于某一个 revision;先升级它们会改变新旧控制面共同读取的 schema。revision 是不可变控制面实例,revision tag 是可变注入指针。移动 tag 或修改 namespace 标签只影响后续创建的 Pod,现有 sidecar 必须 rollout 后才连接新控制面。
Istio 的支持边界要求控制面最多领先数据面一个版本,数据面不能领先控制面;revision 虽能支持官方允许的跨 minor canary 路径,也不意味着任意跨度都可跳跃。升级前把 Kubernetes 支持范围、Istio/Envoy 发行线、扩展 ABI、Gateway API bundle 和数据面版本偏差写入矩阵,超出任一产品明示窗口就拆成中间跳板。compatibilityVersion 只临时保留官方列出的旧行为,且会随对应旧发行线结束支持而失效,不能代替中间版本或长期冻结迁移。Istio 支持发行线 兼容行为版本
用隔离的 mesh-canary namespace 部署 client、orders-v1、orders-v2,保留旧 revision 作为 stable cohort,再把 canary cohort 绑定目标 revision:
: "${TARGET_REVISION:?set the installed canary revision}"
kubectl label namespace mesh-canary istio-injection- "istio.io/rev=${TARGET_REVISION}" --overwrite
kubectl -n mesh-canary rollout restart deployment
kubectl -n mesh-canary rollout status deployment --timeout=5m
istioctl proxy-status
istioctl version预期证据是新建 Pod 的注入状态、代理镜像和控制面连接都指向目标 revision;旧 cohort 仍连接旧 revision;CR 与代理配置没有 NACK;新旧数据面均可建立身份、执行策略并访问正确 endpoint。rollout status 成功只证明 Pod 达到 Deployment 条件,不能替代请求链证据。
revision tag 适合把 prod-canary 和 prod-stable 指向不同 revision,再按 namespace 或 workload 批次重建。引入 default tag 时要特别检查默认 injection、validation webhook 和 singleton leader,避免 non-revisioned webhook 与新 webhook 同时注入。gateway 若由 Helm 手工管理,不会因为 tag 移动而自动升级;它必须列入独立 cohort。
配置字段决定升级的影响半径
| 对象或字段 | 它真正控制什么 | 迁移错误的后果 |
|---|---|---|
namespace istio.io/rev | 新 Pod 选择哪个注入 webhook/revision | 已运行 Pod 不变,出现标签已切但代理仍旧 |
| revision tag | 后续注入目标的可变指针 | 移动过快使新建 Pod跨批次漂移 |
CRD served/storage | API 可接受版本与持久化版本 | 旧控制器读不懂新状态,降级失败 |
| conversion webhook | 多 API 版本之间的读写转换 | webhook 删除后旧版本读取或写入失败 |
| Gateway API CRD owner | 谁安装、升级和删除共享 CRD | Helm ownership 切换导致 Route 级联删除 |
CNI excludeNamespaces/重定向 | 哪些 Pod 被捕获、节点何时就绪 | 出现明文绕过、启动阻塞或全节点中断 |
| proxy metadata / compatibility | 数据面连接、功能兼容和旧行为开关 | 误把局部兼容开关当成完整旧版本模拟 |
| trust bundle / issuer | 哪些新旧证书可互认与谁负责签发 | 旧连接存活、新连接批量 TLS 失败 |
policy selector/targetRefs | 策略由 sidecar、waypoint 或其他目标执行 | 新旧数据面各自加载不同授权语义 |
配置变更要从 desired object 追到 observed data plane。API server apply 成功只证明 schema/admission 通过;Route 还要看 Accepted、ResolvedRefs、observedGeneration,代理还要看实际 listener/route/cluster/endpoint 与策略。字段被目标版本忽略时,控制面可能 Ready、请求却悄悄回到默认行为。
正反实验覆盖四种版本方向
双轨窗口至少验证旧到旧、旧到新、新到旧、新到新四种调用方向;若有 gateway、egress 或跨集群,再给每种方向增加对应路径。每个请求带唯一 request ID,同时保存源/目标身份、双方代理版本、控制面 revision、命中 endpoint、策略 revision、应用响应、代理本地响应和上游响应。
正向集合包括:正常身份访问允许路径;错误身份被拒绝;L4 与 L7 policy 命中相同语义;版本路由、timeout/retry 总预算不变;egress 仍经批准路径;证书轮换后新连接成功;日志、指标和 Trace 标签能区分新旧 cohort。目标环境尚未执行时将结果标为“待测”;兼容矩阵只能决定能否进入实验,不能替代请求证据。
反向集合至少主动制造四类错误:
给 Route 引用不存在的 backend,预期 controller status 显示 ResolvedRefs=False 或产品对应 reason,代理不应悄悄采用旧路由。让 canary 使用错误 ServiceAccount,预期授权在目标数据面拒绝,应用无对应请求;若请求成功,说明身份或策略作用域发生变化。暂停候选控制面连接,预期既有代理使用最后配置,但新策略、endpoint 和证书续期不收敛;恢复后 observed version 应追上 desired generation。
在安全隔离环境缩短测试证书或制造不重叠 bundle,预期新连接出现明确 TLS 失败,旧连接行为单独记录;禁止通过关闭校验修复。
容量也要纳入升级判据。固定相同 RPS、连接、payload、policy、日志和采样,比较升级前后 p99、error/reset、proxy/control-plane CPU 与 RSS、配置收敛、active series、日志字节和 Trace ingest。示例停止条件可以是任一 SLO 越界、错误持续增长、配置长时间 NACK、遥测丢失或资源预算超限;生产阈值来自现网基线和容量预算,不使用脱离环境的万能百分比。
迁移波次应是一台可暂停的状态机,而不是“观察一会儿继续”。每一波只包含一个明确故障域,推荐顺序为离线渲染与空集群、非关键 namespace、单 zone、单 cluster、同区域其余集群、跨区域;共享 CNI、根信任和 CRD 不能伪装成 namespace 波次。开始下一波前同时检查以下信号:
| 信号 | 继续条件 | 立即停止并回切流量的条件 |
|---|---|---|
| 配置 | desired generation 已被目标代理 ACK,关键 Route/Policy condition 正常 | NACK、旧 generation 停滞、默认路由或默认授权接管 |
| 身份与权限 | 新旧四向请求的允许和拒绝语义一致,新连接证书链正确 | 错误身份获准、正确身份拒绝、旧根撤销后仍受信 |
| 流量 | error、reset、retry amplification 与 p99 在本项目预算内 | 任一用户 SLO 越界,或重试/连接风暴持续增长 |
| 容量 | 失去一个副本或节点后仍有已测余量 | proxy、gateway、控制面或遥测队列越过安全水位 |
| 观测 | request ID、revision、cluster、response flag 能闭环 | 日志/指标/Trace 中断,无法区分候选与稳定批次 |
| 状态 | CRD storedVersions、CNI、证书和数据库仍处于声明的回滚区间 | 已发生旧版本无法解释的写入或不可逆 schema 迁移 |
停止后先冻结 GitOps 自动推进和新建 Pod,再把业务权重、revision tag 或节点调度指回 stable;候选仍保留用于取证。只有请求链恢复并证明旧控制面重新接管,才清理候选。若停止条件来自 CRD/storage、CA 或数据存储的不可逆写入,不执行二进制降级,转入隔离恢复或前滚修复。
CRD 与 Gateway API 所有权迁移必须先接管,再放弃
CRD 是数据容器,不是普通无状态安装文件。删除 CRD 会级联删除所有 CR 实例;重新创建同名 CRD 不会恢复对象。迁移 owner 前先导出 CRD、CR、storedVersions、conversion 配置和 finalizer,并在副本环境验证恢复。若目标版本要求 storage migration,应完成迁移、确认所有对象可由新旧读者解释,再关闭旧 conversion webhook。
Linkerd 的 Gateway API ownership 迁移提供了典型教训:2.19 起 Linkerd 不再代装/拥有 Gateway API CRD,过渡必须按官方 ownership migration 让外部安装先接管,再移除旧 Helm ownership。顺序反转可能删除 CRD 和所有依赖 Route。Gateway API CRD 也可能被 Istio、Cilium、网关控制器和业务共同使用,任何单个 mesh release 都无权在卸载时擅自删除。
升级还要核对目标 Gateway API bundle、Mesh Profile 和实现 conformance。Service parentRef 已进入 Standard Channel,不代表任意产品版本、sidecar/ambient 模式、所有 filter 和 consumer route 都兼容。上游 Istio 的 conformance 报告也不能外推到 OpenShift Service Mesh downstream build。每个 Route 都要检查目标 parent 的 condition 与真实请求。
CNI、节点代理和共享数据面不能按 workload 灰度
sidecar 可以按 Pod rollout,节点 CNI、eBPF agent、ztunnel 这类共享组件却以节点为故障域。Istio ambient 升级要拆分 base/CRD、istiod、Istio CNI、ztunnel、waypoint/gateway;CNI 当前没有和 sidecar revision 等价的 per-workload canary,ztunnel 原地升级会影响节点上所有 ambient 流量。需要更小影响面时,使用 cordon/drain、专用 canary node pool 或 blue/green 节点池,并验证长连接重建。
Cilium 同时承担 CNI 时,升级 agent、operator、Envoy/Hubble 和 CRD 要遵守同一受支持组合。官方只测试相邻 minor;先升级当前线最新 patch,再逐跳阅读 Upgrade Guide。跨 chart 升级不要用 --reuse-values,否则新默认值可能被旧 values 静默遮蔽。经过 userspace proxy 的 L7 policy、Ingress/Gateway API 连接可能中断并需要重连,不能把 L3/L4 的最小中断承诺外推到所有路径。
节点层回滚前保存 CNI config、binary、BPF program/map、tc、route、link 与 IPAM 状态。新 CRD 或 datapath state 已被写入后,DaemonSet rollout undo 只回退容器模板,不保证旧 agent 能解释节点和 API 状态。替代 CNI 未就绪前卸载 Cilium会直接让新 Pod 网络失败。
策略与证书迁移需要重叠窗口,不需要永久双写
策略迁移先建立等价性表:旧对象的 selector、作用域、默认 allow/deny、执行点和冲突优先级,分别映射到新对象。迁移期间允许短暂双轨观察,但不能让两套控制器长期同时写同一 listener/route 或授权边界。shadow/dry-run 只能生成观察证据,不会阻断;切到真实 deny 前必须发送正确身份、错误身份、错误 path 和未纳管来源四组请求。
sidecar 迁移到 ambient 时,L4 policy 可由 ztunnel 执行,L7 policy、JWT、Wasm 或流量路由通常要迁到 waypoint 的 targetRefs/Gateway API 语义。官方 sidecar 到 ambient 迁移 允许按 namespace 渐进回退,但 L7 policy 没有原子 handoff;sidecar source 还可能绕过 waypoint。正确顺序是先建立 waypoint 与新策略,再启用 ambient、验证 HBONE,然后移除 injection 并重建 Pod。EnvoyFilter 不能直接迁到 waypoint,primary-remote、VM 和特定证书提供方也可能成为阻塞项。
证书事务要分 root、intermediate、issuer、workload certificate 和 trust bundle。先让验证方同时信任旧根与新根,再让签发方切到新链,确认所有新工作负载获得新证书并完成新连接,最后撤销旧根。旧长连接存活不能证明轮换成功。Linkerd 自动轮换 workload 证书,但 issuer/trust anchor 是另一项运维责任;Consul CA provider、Kuma MeshIdentity/SPIRE 与 Istio 外部 CA 也各有不同的签发和回退状态。
项目双轨接入要限制写入者和批次
GitOps 仓库可以同时保存 stable 与 candidate 的不可变 values。Kubernetes 对象可以有多个 field manager,但同一语义字段只能有一个明确 owner;多个 manager 仅在字段集合互不重叠且冲突能被审计时并存,不能让两套控制器争写 listener、route、selector 或授权规则。按 namespace、工作负载或节点池建立 cohort,清单中记录负责人、开始条件、停止条件、回滚动作和完成证据。自动化每次只推进一个批次,等待代理版本、配置、身份、请求和容量窗口全部稳定后再继续。
应用团队需要看到的不是 mesh 内部版本号,而是调用契约:目标身份是否变化、明文是否仍允许、路由/重试语义是否变化、观测标签是否改名、故障时由谁回切。若应用依赖 mesh 注入的 Header、TLS origination、重试或 DNS rewrite,必须先建立非 mesh 替代路径,不能等卸载后才发现隐式依赖。
共享环境禁止用集群级 --force、--purge 或批量 CRD 删除缩短窗口。所有破坏性动作应要求二人复核 context、owner 与对象清单;凭证使用短期身份,命令输出脱敏,诊断 artifact 设置保留期限。离职、供应商退出和集群退役时同步撤销 registry、Kubernetes、remote API、CA、ACL 与观测访问。
产品升级机制不能横向套模板
Linkerd 的顺序是 CLI、CRD/control plane、extensions、data plane,最后 prune 旧资源。控制面最多领先数据面一个完整 Linkerd version;edge release 不遵循 semver。linkerd check --proxy 和 linkerd version --proxy 用于找旧代理,不能代替业务请求。Upgrading Linkerd
Linkerd multicluster 从旧 service-mirror Deployment 迁到 GitOps controller 时,以 Lease 表示单写所有权。先确认新 controller 已取得目标 Link 的 Lease,再删除旧 controller;两个 controller 同时存在不等于可以并行写镜像 Service。Upgrading Multi-cluster Components
Kuma single-zone 先 control plane 后 dataplane;multi-zone 先 global CP、再 zone CP、最后 DPP,兼容窗口也约束共享 store。Universal transparent proxy 还要迁移宿主机规则,二进制回退不会自动恢复 iptables。Upgrade Kuma
Consul 先逐个 server 保持 quorum,再升级 client/dataplane、gateway 和 mesh workload。Kubernetes 从 client agent 转 Consul Dataplane 时要保留旧 client,重建所有 mesh workload 后确认新 dataplane 接管,再删除旧 DaemonSet。Upgrade Consul
OpenShift Service Mesh 同时有 OLM Operator channel 与 Istio.spec.version/updateStrategy 两个更新面。从 2.x 迁移时,源端必须先达到官方要求的 2.6.14,再依次进入 3.0、3.1 和目标 3.2 z-stream;过程还涉及 ServiceMeshControlPlane 到 Istio、独立 CNI、add-ons、成员发现和 gateway 所有权变化,不能照抄上游 istioctl 或跳过中间 minor。OpenShift Service Mesh 更新文档
Istio ambient 推荐的组件顺序和 sidecar revision 不同;compatibilityVersion 只保留 release note 明确列出的旧行为,不是完整旧版本模拟,也不能成为永久配置债务。
机制选型时优先问:是否能并存候选控制面、能否按 workload 或节点控制影响、CRD/storage 是否可逆、策略是否有 shadow、证书能否建立重叠信任、供应商是否给出支持窗口和降级说明。没有这些条件的产品,升级预算要包含更大的维护窗口和完整状态恢复。
归档项目触发迁移,不触发历史抹除
CNCF Open Service Mesh 项目页 已将 OSM 标为 Archived,官方 openservicemesh/osm 仓库也已归档并声明不再开发。它不适合作为新生产基线;已有集群则要先盘点 MeshConfig、SMI/OSM CRD、sidecar injection、证书、策略、ingress/egress 和 Prometheus 指标,再迁移等价能力。直接卸载会让旧代理、策略和证书依赖失去 owner。
Service Mesh Interface 官方仓库同样已归档,标示规范停在 v0.6.0。已有 TrafficSplit、TrafficTarget 等对象可以作为迁移输入,但不能继续把 SMI 描述为活跃演进、跨实现一致的标准。迁移时按目标实现重新验证默认值、冲突优先级和身份语义,不做机械 YAML 改名。
Traefik Mesh 的官方仓库没有显示 GitHub archived 标记,也没有明确 EOL/归档公告;只能把维护状态记为未确认。长期没有新 release 是风险信号,不是“官方已停止维护”的证据。现有用户应向维护方或供应商确认支持、漏洞响应和兼容计划,同时准备可演练退出路径;新选型在状态澄清前不应假设其生命周期承诺。
Linkerd Jaeger extension 从 2.19 起不再更新,是另一种更细粒度弃用:core mesh 仍可运行,扩展却应迁往独立 tracing infrastructure。弃用治理必须落到组件级,不能只看顶层项目是否活跃。
回滚先回流量,再回配置,最后决定是否回二进制
canary 出现问题时,第一动作通常是停止新批次并把流量/注入 tag 切回 stable,随后重建受影响 workload;旧 revision 仍在时,这比立刻卸载候选更可控。接着恢复策略和路由到已知版本,验证四种调用方向及身份正反例。只有确认 CRD、stored state、CNI 和证书仍在旧版本兼容范围内,才考虑回退二进制。
回滚证明包括:新创建 Pod 确实注入旧数据面;旧控制面收到代理连接;目标代理加载旧配置 generation;新连接使用预期证书;业务请求、拒绝请求、egress 和跨集群路径恢复;候选 gateway/waypoint 无剩余流量。只看到 Deployment Ready 或 Helm rollback 成功不算完成。
若 CRD/storage、数据库或 CA 已越过不可逆提交点,优先从验证过的状态备份恢复到隔离环境,或继续前滚到修复版本。把未知状态强行交给旧控制器会把可见故障变成静默配置误解。
网格退出按八个状态完成核销
盘点隐式依赖: 注入、CNI、DNS rewrite、identity、mTLS、授权、route、retry、egress、多集群、遥测和应用读取的 mesh Header。建立非网格路径: 恢复 Kubernetes Service/DNS/NetworkPolicy、客户端 TLS/认证、负载均衡、timeout/retry 和批准出口,并做正反请求。分批撤数据面: 移除新 Pod 的注入或 ambient 标签,rollout 后检查 Pod spec、节点路径和真实请求;旧 Pod 仍带代理时批次未完成。
迁移策略语义: 接受 NetworkPolicy 只能替代部分 L3/L4 语义;L7 authorization、outlier detection、TLS origination 和重试必须有明确替代或已审批的能力损失。拆多集群: 停止导出,清零 mirror/global service 流量,unlink 远端,撤销 remote Secret/ServiceAccount 和 trust bundle。
拆观测: 把 SLO/告警迁到应用、gateway、CNI 或独立 OTel pipeline,保留重叠观察窗口,再删除旧指标与 dashboard。删扩展与控制面: 确认无 injected Pod、无代理连接、无 CR 实例后,按 owner 删除 extension、gateway、control plane;CRD 最后处理。核销资产: webhook、RBAC、namespace 标签、Secret/PVC、CNI/BPF/iptables、DNS、LoadBalancer、证书、镜像仓库权限、日志索引和云费用全部归零。
Istio istioctl uninstall --purge 会删除共享 cluster-scoped 资源;Linkerd --force 会绕过 injected Pod 检查;Consul Kubernetes 卸载默认保留 Secret/PVC,而 wipe-data 是破坏性动作;Cilium 的 post-uninstall-cleanup 会删除节点 CNI、BPF、tc、route 与 link 状态。这些命令都不能作为普通清理捷径。先证明业务已经脱网,再由对应 owner 审批执行。
退出完成有五条硬证据:所有 workload spec 无旧代理/注入;旧控制面和 gateway 无连接、无流量;旧身份、remote credential 和 registry 权限已撤销;替代告警能够发现正反实验中的故障;PVC、LB、DNS、日志保留和商业订阅不再产生费用。项目从资产账本移除前还应保存最终配置、恢复期限、审计记录和数据删除证明。
长期治理把生命周期债务变成可见预算
每个网格组件指定 owner、支持发行线、升级频率、最大允许 skew、CRD owner、证书轮换责任、回滚等级和退出替代。每次例行巡检统计代理版本分布、过期 revision、未使用 CRD/策略、即将到期证书、远端凭据、遥测基数和孤儿 LoadBalancer;超过宽限期的旧 cohort 阻止继续发布。
容量成本要同时计算双轨控制面、重复 gateway、额外节点池、双写遥测和重叠保留。canary 不是免费保险:它降低变更影响半径,却增加一段时间内的 CPU、内存、镜像、指标和运维认知成本。若团队无法为双轨证据和清理负责,宁可选择更小批次和明确维护窗口,也不要让候选 revision 永久留在集群。
最后把退出演练纳入年度或重大版本前验证:从一个非关键 namespace 撤掉网格,证明直连身份、授权、超时、出口与告警都能接管,再恢复或完成删除。能安装、能升级、能回滚、能退出四项同时成立,服务网格才是受治理的平台能力,而不是只能继续续费和叠加版本的基础设施依赖。
