Code change:
return nil } <ins> // collectServiceNodePorts returns nodePorts specified in the Service. // Please note that: //   1. same nodePort with *same* protocol will be duplicated as it is //   2. same nodePort with *different* protocol will be deduplicated </ins> func collectServiceNodePorts(service *corev1.Service) []int { <del> servicePorts := []int{} for i := range service.Spec.Ports { servicePort := &service.Spec.Ports[i] if servicePort.NodePort != 0 { servicePorts = append(servicePorts, int(servicePort.NodePort)) </del> <ins> var servicePorts []int // map from nodePort to set of protocols seen := make(map[int]sets.String) for _, port := range service.Spec.Ports { nodePort := int(port.NodePort) if nodePort == 0 { continue } proto := string(port.Protocol) s := seen[nodePort] if s == nil { // have not seen this nodePort before s = sets.NewString(proto) servicePorts = append(servicePorts, nodePort) } else if s.Has(proto) { // same nodePort with same protocol servicePorts = append(servicePorts, nodePort) } else { // same nodePort with different protocol s.Insert(proto) </ins> } <ins> seen[nodePort] = s </ins> } <del> if service.Spec.HealthCheckNodePort != 0 { servicePorts = append(servicePorts, int(service.Spec.HealthCheckNodePort)) </del> <ins> healthPort := int(service.Spec.HealthCheckNodePort) if healthPort != 0 { s := seen[healthPort] // TODO: is it safe to assume the protocol is always TCP? if s == nil || s.Has(string(corev1.ProtocolTCP)) { servicePorts = append(servicePorts, healthPort) } </ins> } return servicePorts

Related discussion:
text: /assign
Ahh, I thought you meant that you had accidentally been allocated the same nodePorts and I was very confused when you said "all of them". I have reproduced this issue, and I can see it by inspection. The obvious fix would be to collect ports split by protocol, but I think that's not right since we don't store it split. An even simpler fix would be for to build a . Then for each protocol, for each port, build that contains all the port numbers, but remove any duplicates ONLY IF they are duplicated across protocols. Duplicates in the same protocol should be retained (to report an error later). I don't have time to tackle this tonight (and write a test), but it seems like a good bug.
perhaps I can fix this problem /assign
things may be a little more complicated. Right now the is not aware of the protocol of the port so I guess simply rewriting function to return is not enough, the port allocator will still return on same node port even with different protocol. perhaps we need to refactor the to make it protocol-aware.
I don't think we need to do make the allocator be protocol aware. IIRC we allow you to use the same nodeport on different protocols ONLY within a single service. This means (I think) that we can do hyper-local deduplication as we collect the nodeports for each service. If we find the same nodeport number with different protocols, just remove the duplicates because it is allowed. I.e. a service that looks like: return - deduped. if ANY OTHER service tried to use it would be an error at the "rebuilt" allocator Likewise if a single Service claims to use the same nodeport number more than once on the same protocol, it should be an error: return - NOT deduped.
obviously, we want a great unit test here :P
ah got it! thanks for your detailed explanation!
Hi! I have filed a PR to resolve this issue, could you take a look?