登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  业界新闻

Kubernetes 默认命名空间迁移的零停机工程方法

来源:17golang原创

时间:2026-10-02 17:49:09 490浏览 收藏

Kubernetes 官方文档明确建议生产集群不要长期使用 default 命名空间。真正迁移时,最稳妥的做法不是修改现有对象的 namespace,也不是先删旧资源再建新资源,而是在目标命名空间并行重建一套可独立运行的应用,完成身份、配置、网络、DNS、存储和容量验收后,在入口层受控切流,并保留旧环境作为短期回滚路径。

官方文档:https://kubernetes.io/docs/

这个结论来自 Kubernetes 的对象模型:Deployment、Service、ConfigMap、Secret、ServiceAccount 等对象是命名空间级资源,对象身份包含 API 资源类型、namespace 和 name。把应用从 default 搬到 app-prod,本质上是在新作用域创建新对象,而不是给原对象换一个目录。

一、三种迁移路线怎么选

命名空间迁移常见有三种做法。它们表面上都能得到“资源出现在新 namespace”这个结果,但可用性和回滚能力完全不同。

Kubernetes 命名空间三种迁移路线对比说明图
图1:三种命名空间迁移路线对比说明图,并行双跑在可用性和回滚能力上更适合作为生产默认方案。
路线可用性主要风险适用场景
先删旧资源,再在新命名空间创建必然出现窗口期新 Pod 启动、探针、镜像拉取或权限失败时无法快速恢复允许停机的测试环境
导出清单,批量修改 namespace 后直接应用可能并行,但不可控遗漏 ServiceAccount、RoleBinding、Secret、PVC、DNS 和入口配置依赖很少的临时服务
从版本库重建新环境,并行验收后切流可以做到业务无感需要额外容量和明确的入口切换机制生产环境默认选择

推荐第三种路线还有一个原因:旧环境保持不动,新环境的每项修正都可以单独验证。若切流后错误率、延迟或业务指标异常,只需恢复入口路由,不必在故障现场重新拼装旧资源。

二、先做资源与依赖盘点

不要把 kubectl get all 当成完整清单。它不会覆盖 Secret、ConfigMap、Role、RoleBinding、NetworkPolicy、PodDisruptionBudget、HorizontalPodAutoscaler、Ingress、PVC 以及 CRD 实例等全部对象。更可靠的做法是先区分命名空间级和集群级资源,再围绕应用标签盘点。

# 查看当前集群中哪些 API 资源属于命名空间作用域
kubectl api-resources --namespaced=true

# 按应用标签盘点核心工作负载和服务,避免把 default 中无关对象一起迁移
kubectl get deploy,sts,ds,svc,ingress,pdb,hpa \
  -n default -l app.kubernetes.io/part-of=my-app

# 单独检查配置、身份、策略和存储引用
kubectl get configmap,secret,serviceaccount,role,rolebinding,networkpolicy,pvc \
  -n default -l app.kubernetes.io/part-of=my-app

这一步至少要把对象分成三类:

  • 需要在新命名空间重建:Deployment、Service、ConfigMap、Secret、ServiceAccount、RoleBinding、NetworkPolicy、PDB、HPA、Ingress 等。
  • 可能继续共享:Node、StorageClass、PersistentVolume、ClusterRole、CRD 等集群级资源,但要重新检查绑定和授权范围。
  • 必须单独设计迁移:PVC、单写数据库、本地盘、队列消费者位点、定时任务和依赖固定 DNS 名称的组件。

Kubernetes 官方文档指出,PersistentVolume 是集群级资源,而 PersistentVolumeClaim 是命名空间级资源,Pod 会在自己的命名空间查找 PVC。不能因为 PV 仍在集群里,就假设把相同 PVC 清单复制到新 namespace 后会自动、安全地接管原数据。单写存储要先设计快照恢复、数据复制、只读窗口或应用级切换。

三、在新命名空间按依赖顺序重建

我通常按“命名空间策略 → 身份与权限 → 配置与凭据 → 网络策略 → 服务发现 → 工作负载 → 自动伸缩与中断预算 → 入口”的顺序创建。这样失败会尽量暴露在流量进入之前。

# 创建目标命名空间;名称应使用稳定、可读的 DNS 标签
kubectl create namespace app-prod

# 先应用命名空间级基础对象,再部署工作负载
kubectl apply -n app-prod -f base/identity-and-policy.yaml
kubectl apply -n app-prod -f base/config-and-secrets.yaml
kubectl apply -n app-prod -f workload/

# 等待新 Deployment 达到可用状态,但此时仍不切生产入口
kubectl rollout status deployment/my-app -n app-prod --timeout=10m

这里不建议把从集群导出的完整 YAML 直接作为迁移源。实时对象通常包含 status、resourceVersion、uid、ownerReferences 等服务端字段,也可能把不应落盘的 Secret 暴露到临时文件。更好的方式是从 GitOps 或版本库中的声明式清单渲染目标环境,只把确实属于新命名空间的差异参数化。

ServiceAccount 和 RBAC 必须重新绑定

ServiceAccount 是命名空间级身份。每个 namespace 都有各自的 default ServiceAccount,自定义 ServiceAccount 也不会因为同名就继承旧 namespace 的权限。RoleBinding 只在它所在的命名空间授予权限,因此需要在 app-prod 重建,并检查 subject 中引用的 ServiceAccount namespace。

迁移时不要为了“先跑起来”临时改成 ClusterRoleBinding 或授予 cluster-admin。更宽的权限会掩盖原有依赖问题,也会扩大 Secret 和 API 访问范围。应保留最小权限,并在切流前用目标 ServiceAccount 验证真实调用。

短 DNS 名称会改变解析目标

Service 的完整 DNS 形式通常是 ..svc.cluster.local。Pod 只写 orders 时,会优先解析本命名空间中的同名 Service。因此,新旧命名空间并行期间,应用内部依赖可能自然切到新 namespace 的同名 Service,也可能因为缺少该 Service 而失败。

迁移前应把依赖分为“应随应用一起迁移”和“继续跨 namespace 访问”。后者在过渡期应使用命名空间限定名,例如 orders.default,或者完整 FQDN;等依赖也迁完后再切回目标地址。不要同时改 namespace 和大量业务配置,却不给每项依赖留下独立验证点。

四、切流前需要通过哪些验收

Pod 处于 Running 不等于应用能够接流量。Kubernetes 的 readiness probe 失败时,Pod 会从匹配 Service 的 EndpointSlice 可用端点中移除,这正是并行迁移时的核心门禁。新环境至少要有两个副本,并把 readiness 检查绑定到真实依赖是否可用,而不是只判断进程存在。

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 2  # 零停机需要并行容量,单副本无法抵御启动和切流抖动
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 0  # 更新时不主动减少可用副本
      maxSurge: 1        # 允许额外创建一个副本完成替换
  template:
    spec:
      containers:
      - name: app
        image: registry.example.com/my-app:stable
        readinessProbe:
          httpGet:
            path: /ready  # 只在缓存、数据库等关键依赖可用时返回成功
            port: 8080
          periodSeconds: 5
          failureThreshold: 3

上线前应逐项确认:

  • 新 Deployment 的期望副本、就绪副本和可用副本一致。
  • 新 Service 的 EndpointSlice 只包含已 Ready 的新 Pod。
  • Pod 使用的是目标 namespace 的 ConfigMap、Secret 与 ServiceAccount。
  • NetworkPolicy 允许必要的入口、DNS、数据库和外部 API 流量。
  • 应用内短 DNS、FQDN、回调地址和消息队列消费者组符合并行期设计。
  • 新旧环境同时运行时,不会重复执行 CronJob、一次性 Job、账务扣减或其他非幂等任务。

PodDisruptionBudget 可以约束一部分自愿中断,但不能把它当作此次迁移的兜底。官方文档明确说明,直接删除 Deployment 或 Pod 会绕过 PDB,而且 Deployment 自身滚动升级的可用性由工作负载策略控制。迁移的真正保障仍然是副本、探针、入口切换和回滚路径。

五、切流时保留一个明确的回滚窗口

Kubernetes 命名空间并行切流与回滚结构图
图2:命名空间并行切流结构图,入口只在新环境通过健康和依赖检查后切换,并在观察期内保留旧环境回滚路径。

切流点应该位于业务入口,而不是通过删除旧 Pod“逼迫”流量进入新环境。可选择的入口取决于现有架构:

  • Ingress 或 Gateway:在目标 namespace 创建对应入口对象,再通过 DNS、Gateway 路由或控制器支持的权重能力切换。传统 Ingress 的 Service 后端通常与 Ingress 同 namespace,不能只修改一个跨 namespace 的 Service 名字。
  • 外部负载均衡器:让新旧入口同时注册,先小比例观察,再完成切换。
  • 服务网格:可做细粒度权重或按请求特征切流,但必须把控制面配置也纳入回滚方案。
  • 纯 ClusterIP 内部服务:调用方需要显式更换 FQDN,或通过稳定的上层代理保持入口不变。

切流完成后不要立刻删除 default 中的旧资源。先将旧环境保留为热回滚路径,但暂停会产生重复副作用的 CronJob、消费者或写任务;观察一个能覆盖高峰流量和关键业务链路的窗口。回滚动作应只是恢复入口指向,而不是临时重新部署旧环境。

六、哪些情况不能承诺零停机

“零停机”不是修改几个 YAML 字段就自动获得的属性。下面这些情况要先完成额外改造:

  • 应用只有一个副本,且启动时间长或没有 readiness probe。
  • 新旧实例不能同时写同一份数据,数据库或文件系统也没有复制能力。
  • PVC 绑定、访问模式或底层存储不允许在两个 namespace 的工作负载间并行使用。
  • 消费者组、定时任务、回调注册或领导者选举在双跑时会产生重复操作。
  • 入口控制器不支持平滑权重切换,而 DNS TTL 和客户端缓存又无法满足恢复时间目标。
  • 容量不足,无法让新旧副本在同一集群同时运行。

对这些系统,更准确的目标是“可控停机”或“业务级双写与切换”,而不是把无状态服务的并行迁移步骤生搬过去。

七、最终决策表

约束推荐做法不建议做法
无状态 HTTP 服务,有多副本和稳定入口新 namespace 并行部署、探针验收、入口切流先删旧 Deployment
跨 namespace 依赖较多先使用限定 DNS,按依赖逐项迁移只批量替换 YAML 中的 namespace 字符串
自定义 ServiceAccount 与最小权限在目标 namespace 重建 ServiceAccount 和 RoleBinding临时授予 cluster-admin
单写 PVC 或内嵌数据库单独设计数据复制、快照恢复或停写窗口复制 PVC 清单后假设自动接管数据
需要分钟级回滚观察期内保留旧副本和旧路由切流后立即清理 default

这套方法的重点不是“把资源复制过去”,而是把迁移拆成两次独立决策:先证明新命名空间具备完整运行能力,再决定何时让流量进入。只要旧环境在观察期内保持可恢复、入口切换可逆、数据写入策略明确,命名空间整理就不必和业务中断绑定在一起。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>