首页 > 解决方案 > K8s - 在 K8s 升级之前无法升级 statefulset API

问题描述

我正在将 K8s 从 1.15 升级到 1.16。在此之前,我必须将我的 statefulset yaml API 迁移到 apps/v1 版本。但是 K8s 不允许我这样做。

以前版本的 yamls 在这里(变量存储在另一个文件中):

apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
  name: {{ .NAME_KAFKA }}
  namespace: {{ .NS }}
spec:
  serviceName: {{ .NAME_KAFKA  }}-service
  replicas: {{ .CLUSTER_SIZE_KAFKA }}
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: {{ .NAME_KAFKA }}
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9009"
    spec:
      priorityClassName: {{ .PRIORITY_HIGHEST }}
      nodeSelector:
        lifecycle: OnDemand
      terminationGracePeriodSeconds: 301
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - {{ .NAME_KAFKA }}
              topologyKey: "kubernetes.io/hostname"
      containers:
      - name: local-{{ .NAME_KAFKA }}
        imagePullPolicy: Always
        image: {{ .REPO }}/{{ .IMAGE_KAFKA }}:{{ .VERSION_KAFKA }}
        resources:
          requests:
            memory: 768Mi
            cpu: 500m
          limits:
            memory: 768Mi
            cpu: 500m
        ports:
        - containerPort: 9092
          name: server
        - containerPort: 9009
          name: prometheus
        volumeMounts:
        - name: datadir
          mountPath: /var/lib/kafka
        env:
        - name: KAFKA_HEAP_OPTS
          value : "-Xmx512M -Xms512M"
        - name: KAFKA_OPTS
          value: "-Dlogging.level=INFO"
        readinessProbe:
          tcpSocket:
            port: 9092
          initialDelaySeconds: 60
          timeoutSeconds: 5
          periodSeconds: 5
          successThreshold: 1
          failureThreshold: 5
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: gp2
      resources:
        requests:
          storage: 20Gi

我将 yaml 文件中的 api-version 从apps/v1beta1 更改apps/v1并尝试应用。可以预见的是,我收到了这个错误。

error: error validating "STDIN": error validating data: ValidationError(StatefulSet.spec): missing required field "selector" in io.k8s.api.apps.v1.StatefulSetSpec; if you choose to ignore these errors, turn validation off with --validate=false

所以我添加了 StatefulSet.spec.selector 字段

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .NAME_KAFKA }}
  namespace: {{ .NS }}
spec:
  selector:
    matchExpressions:
      - key: "app"
        operator: In
        values:
          - {{ .NAME_KAFKA }}
  serviceName: {{ .NAME_KAFKA  }}-service
  replicas: {{ .CLUSTER_SIZE_KAFKA }}
  updateStrategy:
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: {{ .NAME_KAFKA }}
      annotations:
        prometheus.io/scrape: "true"
        prometheus.io/port: "9009"
    spec:
      priorityClassName: {{ .PRIORITY_HIGHEST }}
      nodeSelector:
        lifecycle: OnDemand
      terminationGracePeriodSeconds: 301
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: "app"
                    operator: In
                    values:
                    - {{ .NAME_KAFKA }}
              topologyKey: "kubernetes.io/hostname"
      containers:
      - name: local-{{ .NAME_KAFKA }}
        imagePullPolicy: Always
        image: {{ .REPO }}/{{ .IMAGE_KAFKA }}:{{ .VERSION_KAFKA }}
        resources:
          requests:
            memory: 768Mi
            cpu: 500m
          limits:
            memory: 768Mi
            cpu: 500m
        ports:
        - containerPort: 9092
          name: server
        - containerPort: 9009
          name: prometheus
        volumeMounts:
        - name: datadir
          mountPath: /var/lib/kafka
        env:
        - name: KAFKA_HEAP_OPTS
          value : "-Xmx512M -Xms512M"
        - name: KAFKA_OPTS
          value: "-Dlogging.level=INFO"
        readinessProbe:
          tcpSocket:
            port: 9092
          initialDelaySeconds: 60
          timeoutSeconds: 5
          periodSeconds: 5
          successThreshold: 1
          failureThreshold: 5
      securityContext:
        runAsUser: 1000
        fsGroup: 1000
  volumeClaimTemplates:
  - metadata:
      name: datadir
    spec:
      accessModes:
        - ReadWriteOnce
      storageClassName: gp2
      resources:
        requests:
          storage: 20Gi

但是当我尝试应用它时,我收到了这个错误:

The StatefulSet "kafka-name" is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden

根据 K8s 文档,应该有一种方法可以在此 yaml 中更新 API,而无需重建 K8s 中的所有状态集。但是我该怎么做呢?

提前致谢。

标签: kubernetesyaml

解决方案


升级到 1.16 后,您可以转换您的资源。

正如博客中所写,您可以使用 kubectl convert。迁移建议转换。请参阅kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16

kubectl convert -f ./my-statefulset.yaml --output-version apps/v1

另一种选择是使用 cascade=false 删除 statefulset。

它会删除 statefulset 并使 pod 保持正常运行。现在您应该能够再次应用新的 statefulset 文件。

kubectl delete statefulset/<your-statefulset> --cascade=false

推荐阅读