kubectl: Unable to change service from type=NodePort to type=ClusterIP with kubectl

Is this a BUG REPORT or FEATURE REQUEST? (choose one): /kind bug

Kubernetes version (use kubectl version):

$ kubectl version
Client Version: version.Info{Major:"1", Minor:"8", GitVersion:"v1.8.6", GitCommit:"6260bb08c46c31eea6cb538b34a9ceb3e406689c", GitTreeState:"clean", BuildDate:"2017-12-21T06:34:11Z", GoVersion:"go1.8.3", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"10+", GitVersion:"v1.10.0-alpha.1.930+0d1986ad8219bf-dirty", GitCommit:"0d1986ad8219bf1a64fc657eac407cc84d3ad647", GitTreeState:"dirty", BuildDate:"2018-01-17T03:10:36Z", GoVersion:"go1.9.2", Compiler:"gc", Platform:"linux/amd64"}

What happened:

  • Create a service with type=ClusterIP. Let’s say kube-dns:
apiVersion: v1
kind: Service
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: KubeDNS
  name: kube-dns
  namespace: kube-system
spec:
  clusterIP: 10.0.0.10
  ports:
  - name: dns
    port: 53
    protocol: UDP
    targetPort: 53
  - name: dns-tcp
    port: 53
    protocol: TCP
    targetPort: 53
  selector:
    k8s-app: kube-dns
  type: ClusterIP
  • Edit type from ClusterIP to NodePort, and now we have:
apiVersion: v1
kind: Service
metadata:
  labels:
    addonmanager.kubernetes.io/mode: Reconcile
    k8s-app: kube-dns
    kubernetes.io/cluster-service: "true"
    kubernetes.io/name: KubeDNS
  name: kube-dns
  namespace: kube-system
spec:
  clusterIP: 10.0.0.10
  ports:
  - name: dns
    nodePort: 31716
    port: 53
    protocol: UDP
    targetPort: 53
  - name: dns-tcp
    nodePort: 30492
    port: 53
    protocol: TCP
    targetPort: 53
  selector:
    k8s-app: kube-dns
  type: NodePort
  • Edit type from NodePort to ClusterIP with all the auto-allocated nodePorts removed, and we hit this error:
# services "kube-dns" was not valid:
# * spec.ports[1].nodePort: Forbidden: may not be used when `type` is 'ClusterIP'
  • Try to use kubectl apply -f with a similar kube-dns yaml (type=ClusterIP with all nodePorts removed) and hit the same error:
$ kubectl apply -f kube-dns.yaml 
The Service "kube-dns" is invalid: spec.ports[1].nodePort: Forbidden: may not be used when `type` is 'ClusterIP'

What you expected to happen: Users should be able to modify service type from NodePort to CluserIP.

Anything else we need to know: Is this a regression? There was a similar bug before (https://github.com/kubernetes/kubernetes/issues/42282), which was fixed.

@mengqiy @kubernetes/sig-cli-bugs

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Comments: 24 (7 by maintainers)

Commits related to this issue

Most upvoted comments

Dup of kubernetes/kubernetes#66390, which has been fixed in kubernetes/kubernetes#66602.

Please try using kubectl apply -f test-service.yaml --force.

/close

Please reopen if needed.

nodePort: null definitely works declaratively. Thanks @aserrallerios.

I use helm and this helped me fix the issue:

spec:
  type: {{ .Values.service.type }}
  ports:
    - port: {{ .Values.service.externalPort }}
{{- if (eq .Values.service.type "ClusterIP") }}
      nodePort: null
{{- end }}
      targetPort: {{ .Values.service.internalPort }}
      protocol: TCP
      name: {{ .Values.service.name }}

Edit: this only works after the first install. So there’s no “declarative” workaround, you need to change your service manually.

Not fixed:

$ kubectl replace -f grav-deployment.yml
deployment.apps/grav replaced
The Service "grav-service" is invalid: spec.clusterIP: Invalid value: "": field is immutable
$ kubectl delete -f grav-deployment.yml                                                                                                                                                                                                           
deployment.apps "grav" deleted
service "grav-service" deleted
$ kubectl apply -f grav-deployment.yml                                                                                                                                                                                                            
deployment.apps/grav created
service/grav-service created

nodePort: null definitely works declaratively. Thanks @aserrallerios.

The following worked for me kubectl patch svc my-service --type='json' -p '[{"op":"replace","path":"/spec/type","value":"ClusterIP"},{"op":"replace","path":"/spec/ports/0/nodePort","value":null}]'.

use edit service, and comment out the # nodePort: 30492 change to ClusterIP save it

Just came across this issue so definitely not stale.

I ran into this message with kubectl replace: The Service ... is invalid: spec.clusterIP: Invalid value: "": field is immutable

I suspect this is because I do not have the ip address hard-coded as mentioned in comment 221. In my case is is not practical to do that for every service, and instead I am using a NodePort type as a workaround.

This is caused by a known issue: mergeKey in ports is portNumber (both are 53) cannot uniquely identify an entry in this case.