From 6ce612ef65c6ac67a7f67a1c12eec970c05a6c6f Mon Sep 17 00:00:00 2001 From: Quan Tian Date: Sat, 8 Jan 2022 01:55:39 +0800 Subject: [PATCH] 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. --- pkg/proxy/iptables/proxier.go | 11 ++++++++++- pkg/proxy/iptables/proxier_test.go | 10 +++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/proxy/iptables/proxier.go b/pkg/proxy/iptables/proxier.go index 981b2564355..3ff3c77ef70 100644 --- a/pkg/proxy/iptables/proxier.go +++ b/pkg/proxy/iptables/proxier.go @@ -975,6 +975,16 @@ func (proxier *Proxier) syncProxyRules() { 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) } + // 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. 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 // other service portal rules. - isIPv6 := proxier.iptables.IsIPv6() for address := range nodeAddresses { // TODO(thockin, m1093782566): If/when we have dual-stack support we will want to distinguish v4 from v6 zero-CIDRs. if utilproxy.IsZeroCIDR(address) { diff --git a/pkg/proxy/iptables/proxier_test.go b/pkg/proxy/iptables/proxier_test.go index 1d67c18fcd5..6f02bfa40ce 100644 --- a/pkg/proxy/iptables/proxier_test.go +++ b/pkg/proxy/iptables/proxier_test.go @@ -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 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()) }