<p>kubectl version --short
Client Version: v1.15.0
Server Version: v1.14.10-gke.36</p>
<p>I am trying to update a deployment's Label Selector with apps/v1 API, which as per Kubernetes documentation ([documentation][1]) should error out. But in practice <code>kubectl apply -f &lt;filename&gt;</code>
is not throwing any error and changes are not visible in deployment.</p>
<p>Existing deployment
kubectl get deployment my-deployment -o yaml</p>
<pre><code>apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  annotations:
    canonical-name: my-deployment
    deployment.kubernetes.io/revision: &quot;219&quot;
    kubectl.kubernetes.io/last-applied-configuration: |
      {&quot;apiVersion&quot;:&quot;apps/v1&quot;,&quot;kind&quot;:&quot;Deployment&quot;,&quot;metadata&quot;:{&quot;annotations&quot;:{&quot;canonical-name&quot;:&quot;my-deployment&quot;},&quot;name&quot;:&quot;my-deployment&quot;,&quot;namespace&quot;:&quot;default&quot;},&quot;spec&quot;:{&quot;replicas&quot;:1,&quot;selector&quot;:{&quot;matchLabels&quot;:{&quot;app&quot;:&quot;my-deployment&quot;,&quot;deployment&quot;:&quot;my-deployment&quot;}},&quot;strategy&quot;:{&quot;rollingUpdate&quot;:{&quot;maxSurge&quot;:&quot;25%&quot;,&quot;maxUnavailable&quot;:&quot;0%&quot;},&quot;type&quot;:&quot;RollingUpdate&quot;},&quot;template&quot;:{&quot;metadata&quot;:{&quot;labels&quot;:{&quot;app&quot;:&quot;my-deployment&quot;,&quot;deployment&quot;:&quot;my-deployment&quot;,&quot;enableRolling&quot;:&quot;true&quot;,&quot;testComponent&quot;:&quot;true&quot;,&quot;testName&quot;:&quot;my-deployment&quot;,&quot;type&quot;:&quot;REST&quot;}},&quot;spec&quot;:{&quot;affinity&quot;:{&quot;nodeAffinity&quot;:{&quot;requiredDuringSchedulingIgnoredDuringExecution&quot;:{&quot;nodeSelectorTerms&quot;:[{&quot;matchExpressions&quot;:[{&quot;key&quot;:&quot;node-pool-type&quot;,&quot;operator&quot;:&quot;In&quot;,&quot;values&quot;:[&quot;rest&quot;,&quot;components&quot;]}]}]}},&quot;podAntiAffinity&quot;:{&quot;preferredDuringSchedulingIgnoredDuringExecution&quot;:[{&quot;podAffinityTerm&quot;:{&quot;labelSelector&quot;:{&quot;matchExpressions&quot;:[{&quot;key&quot;:&quot;app&quot;,&quot;operator&quot;:&quot;In&quot;,&quot;values&quot;:[&quot;my-deployment&quot;]}]},&quot;topologyKey&quot;:&quot;kubernetes.io/hostname&quot;},&quot;weight&quot;:100}]}},&quot;containers&quot;:[{&quot;env&quot;:[{&quot;name&quot;:&quot;HOST_IP&quot;,&quot;valueFrom&quot;:{&quot;fieldRef&quot;:{&quot;fieldPath&quot;:&quot;status.hostIP&quot;}}},{&quot;name&quot;:&quot;POD_IP&quot;,&quot;valueFrom&quot;:{&quot;fieldRef&quot;:{&quot;fieldPath&quot;:&quot;status.podIP&quot;}}}],&quot;envFrom&quot;:[{&quot;configMapRef&quot;:{&quot;name&quot;:&quot;cp-env&quot;}},{&quot;configMapRef&quot;:{&quot;name&quot;:&quot;gcp-project-env&quot;}},{&quot;secretRef&quot;:{&quot;name&quot;:&quot;cp-secret-env&quot;}},{&quot;configMapRef&quot;:{&quot;name&quot;:&quot;my-deployment-db-env&quot;}},{&quot;configMapRef&quot;:{&quot;name&quot;:&quot;my-deployment-env&quot;}}],&quot;image&quot;:&quot;quay.io/testrd/my-deployment:latest&quot;,&quot;imagePullPolicy&quot;:&quot;IfNotPresent&quot;,&quot;livenessProbe&quot;:{&quot;failureThreshold&quot;:3,&quot;httpGet&quot;:{&quot;path&quot;:&quot;/heathz&quot;,&quot;port&quot;:8080},&quot;initialDelaySeconds&quot;:3700,&quot;periodSeconds&quot;:18,&quot;successThreshold&quot;:1},&quot;name&quot;:&quot;my-deployment&quot;,&quot;ports&quot;:[{&quot;containerPort&quot;:8080}],&quot;readinessProbe&quot;:{&quot;failureThreshold&quot;:3,&quot;httpGet&quot;:{&quot;path&quot;:&quot;/heathz&quot;,&quot;port&quot;:8080},&quot;initialDelaySeconds&quot;:60,&quot;periodSeconds&quot;:30,&quot;successThreshold&quot;:1},&quot;resources&quot;:{&quot;limits&quot;:{&quot;memory&quot;:&quot;3840Mi&quot;},&quot;requests&quot;:{&quot;cpu&quot;:&quot;247m&quot;,&quot;memory&quot;:&quot;1536Mi&quot;}},&quot;volumeMounts&quot;:[{&quot;mountPath&quot;:&quot;/var/run/secrets/kubernetes.io/accesscontrol&quot;,&quot;name&quot;:&quot;gcp-service-admin-account&quot;},{&quot;mountPath&quot;:&quot;/component&quot;,&quot;name&quot;:&quot;host-volume&quot;},{&quot;mountPath&quot;:&quot;/pinpoint-agent&quot;,&quot;name&quot;:&quot;pinpoint-volume&quot;}]}],&quot;imagePullSecrets&quot;:[{&quot;name&quot;:&quot;mysecret&quot;},{&quot;name&quot;:&quot;gcr-mysecret&quot;}],&quot;priorityClassName&quot;:&quot;low-priority&quot;,&quot;volumes&quot;:[{&quot;name&quot;:&quot;gcp-service-admin-account&quot;,&quot;secret&quot;:{&quot;secretName&quot;:&quot;gcp-service-admin-key&quot;}},{&quot;hostPath&quot;:{&quot;path&quot;:&quot;/mnt/stateful_partition/component&quot;,&quot;type&quot;:&quot;DirectoryOrCreate&quot;},&quot;name&quot;:&quot;host-volume&quot;},{&quot;hostPath&quot;:{&quot;path&quot;:&quot;/mnt/stateful_partition/agent&quot;,&quot;type&quot;:&quot;DirectoryOrCreate&quot;},&quot;name&quot;:&quot;agent-volume&quot;}]}}}}
  creationTimestamp: &quot;2019-04-26T16:43:43Z&quot;
  generation: 508
  labels:
    app: my-deployment
    deployment: my-deployment
    enableRolling: &quot;true&quot;
    testComponent: &quot;true&quot;
    testComponentName: my-deployment
    type: REST
  name: my-deployment
  namespace: default
  resourceVersion: &quot;237385987&quot;
  selfLink: /apis/extensions/v1beta1/namespaces/default/deployments/my-deployment
  uid: 73e059d0-6842-11e9-b98b-42010a960025
spec:
  progressDeadlineSeconds: 2147483647
  replicas: 1
  revisionHistoryLimit: 10
  selector:
    matchLabels:
      app: my-deployment
      deployment: my-deployment
      enableRolling: &quot;true&quot;
      type: REST
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 0%
    type: RollingUpdate
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: my-deployment
        deployment: my-deployment
        enableRolling: &quot;true&quot;
        testComponent: &quot;true&quot;
        testComponentName: my-deployment
        type: REST
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: node-pool-type
                operator: In
                values:
                - rest
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - my-deployment
              topologyKey: kubernetes.io/hostname
            weight: 100
      containers:
      - env:
        - name: LAST_RESTART
          value: &quot;1592331191&quot;
        - name: HOST_IP
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.hostIP
        - name: POD_IP
          valueFrom:
            fieldRef:
              apiVersion: v1
              fieldPath: status.podIP
        - name: VIRTUAL_HOST
          value: my-deployment.default.svc.cluster.local
        envFrom:
        - configMapRef:
            name: my-deployment-env
        image: quay.io/testrd/my-deployment:latest
        imagePullPolicy: IfNotPresent
        livenessProbe:
          failureThreshold: 3
          httpGet:
            path: /get/healthz
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 2700
          periodSeconds: 15
          successThreshold: 1
          timeoutSeconds: 1
        name: my-deployment
        ports:
        - containerPort: 8080
          protocol: TCP
        readinessProbe:
          failureThreshold: 3
          httpGet:
            path: /get/healthz
            port: 8080
            scheme: HTTP
          initialDelaySeconds: 60
          periodSeconds: 30
          successThreshold: 1
          timeoutSeconds: 1
        resources:
          limits:
            memory: 384Mi
          requests:
            cpu: 247m
            memory: 1536Mi
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /var/run/secrets/kubernetes.io/accesscontrol
          name: gcp-service-acc
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: mysecret
      - name: gcr-mysecret
      priorityClassName: low-priority
      restartPolicy: Always
      schedulerName: default-scheduler
      securityContext: {}
      terminationGracePeriodSeconds: 30
      volumes:
      - name: gcp-service-acc
        secret:
          defaultMode: 420
          secretName: gcp-service-admin-key
status:
  availableReplicas: 1
  conditions:
  - lastTransitionTime: &quot;2020-06-15T18:59:25Z&quot;
    lastUpdateTime: &quot;2020-06-15T18:59:25Z&quot;
    message: Deployment has minimum availability.
    reason: MinimumReplicasAvailable
    status: &quot;True&quot;
    type: Available
  observedGeneration: 508
  readyReplicas: 1
  replicas: 1
  updatedReplicas: 1
</code></pre>
<p>New my-deployment.yml</p>
<pre><code>---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-deployment
  namespace: default
  annotations:
  canonical-name: my-deployment
  labels:
    type: &quot;REST&quot;
    testComponent: &quot;true&quot;
    testComponentName: &quot;my-deployment&quot;
spec:
  replicas: 1
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 15%
      maxUnavailable: 0%
  selector:
    matchLabels:
      deployment: my-deployment
      app: my-deployment
  template:
    metadata:
      labels:
        app: my-deployment
        type: REST
        enableRolling: &quot;true&quot;
        deployment: my-deployment
        testComponent: &quot;true&quot;
        testComponentName: my-deployment
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
              - matchExpressions:
                - key: node-pool-type
                  operator: In
                  values:
                    - rest
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - my-deployment
              topologyKey: &quot;kubernetes.io/hostname&quot;
      # scheduling and preemption priority of this pod
      priorityClassName: low-priority
      containers:
      - name: my-deployment
        image: quay.io/testrd/my-deployment:latest
        imagePullPolicy: IfNotPresent
        resources:
          requests:
            cpu: &quot;247m&quot;
            memory: &quot;1536Mi&quot;
          limits:
            memory: &quot;384Mi&quot;
        
        readinessProbe:
          httpGet:
            path: /get/healthz
            port: 8080
          # start after 60s of container launch
          initialDelaySeconds: 60
          # probe every 30s
          periodSeconds: 30
          # declare success (ready) if 1 (default) attempt results in a success
          successThreshold: 1
          failureThreshold: 3
        livenessProbe:
          httpGet:
            path: /get/healthz
            port: 8080
          # start after 45 minutes of container launch
          initialDelaySeconds: 2700
          # probe every 15s
          periodSeconds: 15
          # declare success (live) if 1 (default) attempt results in a success
          successThreshold: 1
          # declare failure (not live) if 3 consecutive probes result in a failure
          failureThreshold: 3
        ports:
        - containerPort: 8080
        envFrom:
        - configMapRef:
            name: my-deployment-env
        # component specific environment variables
        env:
        - name: HOST_IP
          valueFrom:
            fieldRef:
              fieldPath: status.hostIP
        - name: POD_IP
          valueFrom:
            fieldRef:
              fieldPath: status.podIP
        # VIRTUAL_HOST is set as the service name
        - name: VIRTUAL_HOST
          value: &quot;my-deployment.default.svc.cluster.local&quot;
      volumes:
      # volume carrying the Google Cloud Platform authorization key data
      - name: &quot;gcp-service-acc
        secret:
          secretName: &quot;gcp-service-key&quot;
      imagePullSecrets:
      - name: mysecret
      - name: gcr-mysecret
</code></pre>
<p>kubectl apply -f my-deployment.yml</p>
<p>deployment.apps/my-deployment configured</p>
<p>Ideally it should fail with the error</p>
<pre><code>The Deployment &quot;my-deployment&quot; is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{&quot;deployment&quot;:&quot;my-deployment&quot;}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable
</code></pre>
<p>which is not happening in this case and new labels are not reflecting in deployment. Though they are visible in kubectl.kubernetes.io/last-applied-configuration.</p>
<p>Update Wed Jun 17 16:46:15 UTC 2020
Created new  test deployment</p>
<pre><code>---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  namespace: default
spec:
  # scale com-manh-cp-remote to 1 instances
  replicas: 1
  selector:
    matchLabels:
      app: test-deployment
      deployment: test-deployment
      stereotype: REST
  template:
    metadata:
      labels:
        app: test-deployment
        deployment: test-deployment
        stereotype: REST
    spec:
      containers:
      - name: test-deployment
        image: quay.io/manhrd/kube-cp-stax:latest
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: regsecret
      - name: gcr-regsecret
</code></pre>
<p>Applied update by changing label selector</p>
<pre><code>apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-deployment
  namespace: default
spec:
  # scale com-manh-cp-remote to 1 instances
  replicas: 1
  selector:
    matchLabels:
      deployment: test-deployment
  template:
    metadata:
      labels:
        app: test-deployment
        deployment: test-deployment
        stereotype: REST
    spec:
      containers:
      - name: test-deployment
        image: quay.io/manhrd/kube-cp-stax:latest
        imagePullPolicy: IfNotPresent
      imagePullSecrets:
      - name: mysecret
      - name: gcr-mysecret
</code></pre>
<p>Got below error.</p>
<pre><code>kubectl apply -f dep.yaml
The Deployment &quot;test-deployment&quot; is invalid: spec.selector: Invalid value: v1.LabelSelector{MatchLabels:map[string]string{&quot;deployment&quot;:&quot;test-deployment&quot;}, MatchExpressions:[]v1.LabelSelectorRequirement(nil)}: field is immutable
</code></pre>
<p>It is working expected for new deployments.
[1]: <a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#label-selector-updates" rel="nofollow noreferrer">https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#label-selector-updates</a></p>

Sumant Pangotra
<p>This is because </p>

<ol>
<li>The existing deployment that you are trying to update is on <code>extensions/v1beta1</code> API group where label selector is immutable.</li>
<li>Kubernetes version is older than 1.16</li>
</ol>
