kube-proxy: fix duplicate port opening

When nodePortAddresses is not specified for kube-proxy, it tried to open
the node port for a NodePort service twice, triggered by IPv4ZeroCIDR
and IPv6ZeroCIDR separately. The first attempt would succeed and the
second one would always generate an error log like below:

"listen tcp4 :30522: bind: address already in use"

This patch fixes it by ensuring nodeAddresses of a proxier only contain
the addresses for its IP family.
This commit is contained in:
Quan Tian 2022-01-08 01:55:39 +08:00
parent 475644ccd8
commit 6ce612ef65
2 changed files with 19 additions and 2 deletions

View File

@ -975,6 +975,16 @@ func (proxier *Proxier) syncProxyRules() {
if err != nil { if err != nil {
klog.ErrorS(err, "Failed to get node ip address matching nodeport cidrs, services with nodeport may not work as intended", "CIDRs", proxier.nodePortAddresses) klog.ErrorS(err, "Failed to get node ip address matching nodeport cidrs, services with nodeport may not work as intended", "CIDRs", proxier.nodePortAddresses)
} }
// nodeAddresses may contain dual-stack zero-CIDRs if proxier.nodePortAddresses is empty.
// Ensure nodeAddresses only contains the addresses for this proxier's IP family.
isIPv6 := proxier.iptables.IsIPv6()
for addr := range nodeAddresses {
if utilproxy.IsZeroCIDR(addr) && isIPv6 == netutils.IsIPv6CIDRString(addr) {
// if any of the addresses is zero cidr of this IP family, non-zero IPs can be excluded.
nodeAddresses = sets.NewString(addr)
break
}
}
// Build rules for each service. // Build rules for each service.
for svcName, svc := range proxier.serviceMap { for svcName, svc := range proxier.serviceMap {
@ -1438,7 +1448,6 @@ func (proxier *Proxier) syncProxyRules() {
// Finally, tail-call to the nodeports chain. This needs to be after all // Finally, tail-call to the nodeports chain. This needs to be after all
// other service portal rules. // other service portal rules.
isIPv6 := proxier.iptables.IsIPv6()
for address := range nodeAddresses { for address := range nodeAddresses {
// TODO(thockin, m1093782566): If/when we have dual-stack support we will want to distinguish v4 from v6 zero-CIDRs. // TODO(thockin, m1093782566): If/when we have dual-stack support we will want to distinguish v4 from v6 zero-CIDRs.
if utilproxy.IsZeroCIDR(address) { if utilproxy.IsZeroCIDR(address) {

View File

@ -1587,7 +1587,15 @@ COMMIT
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS -A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
COMMIT COMMIT
` `
assert.Equal(t, []*netutils.LocalPort{
{
Description: "nodePort for ns1/svc1:p80",
IP: "",
IPFamily: netutils.IPv4,
Port: svcNodePort,
Protocol: netutils.TCP,
},
}, fp.portMapper.(*fakePortOpener).openPorts)
assertIPTablesRulesEqual(t, expected, fp.iptablesData.String()) assertIPTablesRulesEqual(t, expected, fp.iptablesData.String())
} }