错误信息如下:

Error: UPGRADE FAILED: cannot patch "kb-cloud-vms-server" with kind StatefulSet: StatefulSet.apps "kb-cloud-vms-server" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'ordinals', 'template', 'updateStrategy', 'persistentVolumeClaimRetentionPolicy' and 'minReadySeconds' are forbidden

查看sts配置信息未看到不能更新的字段

apiVersion: apps/v1
kind: StatefulSet
metadata:
  annotations:
    meta.helm.sh/release-name: kb-cloud
    meta.helm.sh/release-namespace: kb-cloud
  creationTimestamp: "2026-03-26T09:35:08Z"
  generation: 1
  labels:
    app: server
    app.kubernetes.io/instance: kb-cloud
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: vms
    app.kubernetes.io/version: v1.133.0
    helm.sh/chart: victoria-metrics-single-0.28.0
  name: kb-cloud-vms-server
  namespace: kb-cloud
  resourceVersion: "12482"
  uid: 5461ca09-780f-4500-8d93-83abcda15fa2
spec:
  persistentVolumeClaimRetentionPolicy:
    whenDeleted: Retain
    whenScaled: Retain
  podManagementPolicy: OrderedReady
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: server
      app.kubernetes.io/instance: kb-cloud
      app.kubernetes.io/name: vms
  serviceName: kb-cloud-vms-server
  template:
    metadata:
      annotations:
        prometheus.io/port: "8428"
        prometheus.io/scrape: "true"
      creationTimestamp: null
      labels:
        app: server
        app.kubernetes.io/instance: kb-cloud
        app.kubernetes.io/managed-by: Helm
        app.kubernetes.io/name: vms
        app.kubernetes.io/version: v1.133.0
        helm.sh/chart: victoria-metrics-single-0.28.0
    spec:
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: node-role.cloud.kubeblocks.io/control-plane
                operator: Exists
            weight: 100
      automountServiceAccountToken: true
      containers:
      - args:
        - --dedup.minScrapeInterval=1s
        - --envflag.enable
        - --envflag.prefix=VM_
        - --httpListenAddr=:8428
        - --loggerFormat=json
        - --retentionPeriod=48h
        - --storageDataPath=/storage
        image: sealos.hub:5000/apecloud/victoria-metrics:v1.133.0
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 10
          initialDelaySeconds: 30
          periodSeconds: 30
          successThreshold: 1
          tcpSocket:
            port: http
          timeoutSeconds: 5
        name: vmsingle
        ports:
        - containerPort: 8428
          name: http
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /health
            port: http
            scheme: HTTP
          initialDelaySeconds: 5
          periodSeconds: 15
          successThreshold: 1
          timeoutSeconds: 5
        resources:
          limits:
            cpu: "1"
            memory: 1Gi
          requests:
            cpu: 10m
            memory: 10Mi
        securityContext: {}
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /storage
          name: server-volume
      dnsPolicy: ClusterFirst
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      serviceAccount: kb-cloud-vms-server
      serviceAccountName: kb-cloud-vms-server
      terminationGracePeriodSeconds: 60
      tolerations:
      - effect: NoSchedule
        key: node-role.cloud.kubeblocks.io/control-plane
        operator: Exists
      - effect: NoSchedule
        key: node-role.cloud.kubeblocks.io/data-plane
        operator: Exists
      - effect: NoSchedule
        key: node.cloud.kubeblocks.io
        operator: Exists
      - effect: NoSchedule
        key: cloud.kubeblocks.io/node-group
        operator: Exists
      - effect: NoSchedule
        key: kb-controller
        operator: Equal
        value: "true"
      - effect: NoExecute
        key: node.kubernetes.io/not-ready
        operator: Exists
        tolerationSeconds: 10
      - effect: NoExecute
        key: node.kubernetes.io/unreachable
        operator: Exists
        tolerationSeconds: 10
  updateStrategy:
    rollingUpdate:
      partition: 0
    type: RollingUpdate
  volumeClaimTemplates:
  - apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      creationTimestamp: null
      name: server-volume
    spec:
      accessModes:
      - ReadWriteOnce
      resources:
        requests:
          storage: 50Gi
      volumeMode: Filesystem
    status:
      phase: Pending
status:
  availableReplicas: 1
  collisionCount: 0
  currentReplicas: 1
  currentRevision: kb-cloud-vms-server-645977f45d
  observedGeneration: 1
  readyReplicas: 1
  replicas: 1
  updateRevision: kb-cloud-vms-server-645977f45d
  updatedReplicas: 1

尝试删除sts再upgrade的方式解决问题

# 1. 备份当前配置(已完成)
kubectl -n kb-cloud get statefulset kb-cloud-vms-server -o yaml > current-statefulset.yaml

# 2. 删除 StatefulSet,但保留 Pod
kubectl -n kb-cloud delete statefulset kb-cloud-vms-server --cascade=orphan

# 3. 验证 Pod 仍在运行
kubectl -n kb-cloud get pods | grep vms-server

# 4. 执行 Helm 升级
helm -n kb-cloud upgrade kb-cloud kb-charts/kubeblocks-cloud-v2.1.169.tgz -f kb-cloud-values.yaml

# 5. 检查新的 StatefulSet 是否创建成功
kubectl -n kb-cloud get statefulset kb-cloud-vms-server

# 6. 查看 Pod 状态(可能需要滚动更新)
kubectl -n kb-cloud get pods -w

为什么先删除sts再upgrade就可以?

核心原理:Kubernetes API 的更新限制 vs 创建时的灵活性

1. StatefulSet 的更新限制

Kubernetes 对 StatefulSet 的 spec 字段有严格的更新限制:

  • 通过 kubectl editkubectl patch 更新现有 StatefulSet 时,只能修改特定字段
  • 尝试修改其他字段(如 selectorserviceNamevolumeClaimTemplates 的结构等)会被 API Server 拒绝

这是 Kubernetes 的设计决策,目的是保证 StatefulSet 管理的 Pod 的稳定性有序性

2. Helm upgrade 的工作机制

当执行 helm upgrade 时,Helm 会:

  1. 生成新的 Kubernetes 资源清单
  2. 对集群中已存在的资源执行 kubectl applykubectl patch
  3. 对于已存在的 StatefulSet,Helm 尝试更新

如果新版本的 Chart 中,StatefulSet 的 spec 包含了不允许更新的字段变更,API Server 就会拒绝,导致发生看到的错误。

3. 如何绕过这个限制

kubectl -n kb-cloud delete statefulset kb-cloud-vms-server --cascade=orphan
helm upgrade ...

这个方案的关键在于:

步骤 做了什么 效果
delete --cascade=orphan 删除 StatefulSet 对象,但保留其管理的 Pod 和 PVC StatefulSet 对象从 etcd 中移除
helm upgrade Helm 发现 StatefulSet 不存在,于是执行 kubectl create 创建全新的 StatefulSet,而不是更新旧的

4. 创建 vs 更新的区别

操作 限制 适用场景
创建 StatefulSet 可以设置所有 spec 字段 首次部署,或删除后重建
更新 StatefulSet 只能修改少数几个字段 滚动更新镜像、副本数等

关键点:创建操作不受更新限制的约束!这就是为什么先删除再创建可以解决问题。

5. 为什么 --cascade=orphan 很重要

--cascade=orphan  # 孤立模式
  • 没有这个参数:删除 StatefulSet 时会同时删除 Pod(级联删除)
  • 使用这个参数:只删除 StatefulSet 控制器,Pod 继续运行

这样做的优势:

  • ✅ Pod 继续提供服务,业务不中断
  • ✅ PVC 保留,数据不丢失
  • ✅ 新 StatefulSet 创建后,会接管现有的 Pod 和 PVC

6. 示意图解

升级前状态:

etcd 中: [StatefulSet 对象 A] → 管理 → [Pod-0, PVC-0]

执行过程:

1. delete --cascade=orphan
   etcd 中: [StatefulSet 对象 A] 被删除
   集群中: [Pod-0, PVC-0] 继续运行 (孤儿状态)

2. helm upgrade (创建新 StatefulSet)
   etcd 中: [StatefulSet 对象 B] 被创建
   StatefulSet B 发现已有 Pod-0 和 PVC-0 → 接管它们

最终: [StatefulSet 对象 B] → 接管 → [Pod-0, PVC-0]

7. 什么时候不需要此方案?

如果新版本只修改了允许的字段(如 replicastemplate 中的镜像),直接 helm upgrade 就能成功:

# 这些字段可以直接更新
- replicas: 1 → 3
- template.spec.containers[0].image: v1.133.0 → v1.134.0
- minReadySeconds
- updateStrategy

8. 验证原理

可以通过以下实验验证:

# 1. 查看当前 StatefulSet 的 resourceVersion
kubectl -n kb-cloud get statefulset kb-cloud-vms-server -o jsonpath='{.metadata.resourceVersion}'

# 2. 使用方案后,查看新的 resourceVersion
# 会发现 resourceVersion 变化了,说明是一个全新的对象

总结

此方案有效的原因

  1. 删除操作移除了有更新限制的旧对象
  2. 创建操作允许设置任意字段
  3. --cascade=orphan 保证了业务连续性数据安全

这就像换房子:不能直接修改旧房子的承重墙(更新限制),但可以拆掉旧房子,在原址建一栋新房子(删除+创建),而里面的家具(Pod 和数据)可以继续使用。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐