<p>I am upgrading K8s from 1.15 to 1.16. Before I do it, I must migrate my statefulset yaml API to the apps/v1 version. But K8s doesn't allow me to do it.</p>
<p>The previous version of yamls is here (the variables are stored in another file):</p>
<pre><code>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: &quot;true&quot;
        prometheus.io/port: &quot;9009&quot;
    spec:
      priorityClassName: {{ .PRIORITY_HIGHEST }}
      nodeSelector:
        lifecycle: OnDemand
      terminationGracePeriodSeconds: 301
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: &quot;app&quot;
                    operator: In
                    values:
                    - {{ .NAME_KAFKA }}
              topologyKey: &quot;kubernetes.io/hostname&quot;
      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 : &quot;-Xmx512M -Xms512M&quot;
        - name: KAFKA_OPTS
          value: &quot;-Dlogging.level=INFO&quot;
        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
</code></pre>
<p>I change the api-version from <strong>apps/v1beta1</strong> to <strong>apps/v1</strong> in the yaml file and try to apply. Predictably, I receive this error.</p>
<pre><code>error: error validating &quot;STDIN&quot;: error validating data: ValidationError(StatefulSet.spec): missing required field &quot;selector&quot; in io.k8s.api.apps.v1.StatefulSetSpec; if you choose to ignore these errors, turn validation off with --validate=false
</code></pre>
<p>So I add the field StatefulSet.spec.selector</p>
<pre><code>apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: {{ .NAME_KAFKA }}
  namespace: {{ .NS }}
spec:
  selector:
    matchExpressions:
      - key: &quot;app&quot;
        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: &quot;true&quot;
        prometheus.io/port: &quot;9009&quot;
    spec:
      priorityClassName: {{ .PRIORITY_HIGHEST }}
      nodeSelector:
        lifecycle: OnDemand
      terminationGracePeriodSeconds: 301
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            - labelSelector:
                matchExpressions:
                  - key: &quot;app&quot;
                    operator: In
                    values:
                    - {{ .NAME_KAFKA }}
              topologyKey: &quot;kubernetes.io/hostname&quot;
      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 : &quot;-Xmx512M -Xms512M&quot;
        - name: KAFKA_OPTS
          value: &quot;-Dlogging.level=INFO&quot;
        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
</code></pre>
<p>But when I try to apply it, I receive this error:</p>
<pre><code>The StatefulSet &quot;kafka-name&quot; is invalid: spec: Forbidden: updates to statefulset spec for fields other than 'replicas', 'template', and 'updateStrategy' are forbidden
</code></pre>
<p>According to K8s documentation, there should be a way to update the API in this yaml without rebuilding all the stateful sets in K8s. But how can I do it?</p>

dice2011
<p>When upgraded to 1.16, you can convert your resources.</p>
<p>As written in the blog you can use kubectl convert.
The migration recommend convert. See <a href="https://kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16" rel="nofollow noreferrer">kubernetes.io/blog/2019/07/18/api-deprecations-in-1-16</a></p>
<pre><code>kubectl convert -f ./my-statefulset.yaml --output-version apps/v1
</code></pre>
<p>Another option is to delete the statefulset with cascade=false.</p>
<p>It deletes the statefulset and keeps the pods up and running. Now you should be able again to apply the new statefulset file.</p>
<pre><code>kubectl delete statefulset/&lt;your-statefulset&gt; --cascade=false
</code></pre>
