Change:
<!-- This form is for bug reports and feature requests ONLY! If you're looking for help check and the . --Is this a BUG REPORT or FEATURE REQUEST?: /kind bug /sig api /sig network What happened: Prior to 1.8 it was possible to specify the same targetPort in the service definition multiple times. In 1.8, validation was that prohibited this. What you expected to happen: I expect backwards compatibility for GA resources, so having the same targetPort multiple times should be allowed. This is a valid use case IMO for target ports. If you take the example below, the load balancer terminates SSL, so that manifest allows the nginx pods to receive http on port 80 while the load balancer serves traffic on 80 & 443. How to reproduce it (as minimally and precisely as possible): Anything else we need to know?: Original ticket for validation:
cc
/kind bug /area api
Sounds reasonable. WDYT?
Hi, same problem here. Trying to create a service with helm, both 80 and 443 ports using same targetPort, and got this error: $ kubectl version
Feels reasonable, and it seems this is impacting enough people to warrant reverting the original change. WDYT?
Given Service objects are , how a breaking change like this was accepted?
/assign
For the one looking for a temporary way to fix it you have to mix named port with value, see below:
seems to be the PR that shipped this. Why would we want to validate that there are no duplicate target ports anyway? There should be plenty of IP addresses free inside the cluster IP ranges on most clusters (or you have a different problem on your hands) and there are plenty of high-range ports free for the NodePort type. The NAT path through the node should be safe. I'm not sure why this validation is needed. It seems perfectly safe and sane to me. Plus this is a pretty severe breaking change for the ingress-nginx sidecar for pods.

Discussion:
ports[key] = true } <del> // Check for duplicate TargetPort portsPath = specPath.Child("ports") targetPorts := make(map[core.ServicePort]bool) for i, port := range service.Spec.Ports { if (port.TargetPort.Type == intstr.Int && port.TargetPort.IntVal == 0) || (port.TargetPort.Type == intstr.String && port.TargetPort.StrVal == "") { continue } portPath := portsPath.Index(i) key := core.ServicePort{Protocol: port.Protocol, TargetPort: port.TargetPort} _, found := targetPorts[key] if found { allErrs = append(allErrs, field.Duplicate(portPath.Child("targetPort"), port.TargetPort)) } targetPorts[key] = true } </del> // Validate SourceRange field and annotation _, ok := service.Annotations[core.AnnotationLoadBalancerSourceRangesKey] if len(service.Spec.LoadBalancerSourceRanges) > 0 || ok {

numErrs: 0, }, { <del> name: "invalid duplicate targetports (number with same protocol)", tweakSvc: func(s *core.Service) { s.Spec.Type = core.ServiceTypeClusterIP s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 1, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}) s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 2, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}) }, numErrs: 1, }, { name: "invalid duplicate targetports (name with same protocol)", tweakSvc: func(s *core.Service) { s.Spec.Type = core.ServiceTypeClusterIP s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 1, Protocol: "TCP", TargetPort: intstr.FromString("http")}) s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 2, Protocol: "TCP", TargetPort: intstr.FromString("http")}) }, numErrs: 1, }, { name: "valid duplicate targetports (number with different protocols)", tweakSvc: func(s *core.Service) { s.Spec.Type = core.ServiceTypeClusterIP s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 1, Protocol: "TCP", TargetPort: intstr.FromInt(8080)}) s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 2, Protocol: "UDP", TargetPort: intstr.FromInt(8080)}) }, numErrs: 0, }, { name: "valid duplicate targetports (name with different protocols)", tweakSvc: func(s *core.Service) { s.Spec.Type = core.ServiceTypeClusterIP s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "q", Port: 1, Protocol: "TCP", TargetPort: intstr.FromString("http")}) s.Spec.Ports = append(s.Spec.Ports, core.ServicePort{Name: "r", Port: 2, Protocol: "UDP", TargetPort: intstr.FromString("http")}) }, numErrs: 0, }, { </del> name: "valid type - cluster", tweakSvc: func(s *core.Service) { s.Spec.Type = core.ServiceTypeClusterIP