错误信息如下:

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 和 PVCStatefulSet 对象从 etcd 中移除
helm upgradeHelm 发现 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

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

更多推荐