mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-27 05:27:21 +00:00
Hold node-ports for publicIPs for local IPs
This commit is contained in:
parent
f5a9281a26
commit
5087ae6c93
@ -84,14 +84,16 @@ type Proxier struct {
|
|||||||
// assert Proxier is a ProxyProvider
|
// assert Proxier is a ProxyProvider
|
||||||
var _ proxy.ProxyProvider = &Proxier{}
|
var _ proxy.ProxyProvider = &Proxier{}
|
||||||
|
|
||||||
// A key for the portMap
|
// A key for the portMap. The ip has to be a tring because slices can't be map
|
||||||
|
// keys.
|
||||||
type portMapKey struct {
|
type portMapKey struct {
|
||||||
|
ip string
|
||||||
port int
|
port int
|
||||||
protocol api.Protocol
|
protocol api.Protocol
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *portMapKey) String() string {
|
func (k *portMapKey) String() string {
|
||||||
return fmt.Sprintf("%s/%d", k.protocol, k.port)
|
return fmt.Sprintf("%s:%d/%s", k.ip, k.port, k.protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
// A value for the portMap
|
// A value for the portMap
|
||||||
@ -459,6 +461,15 @@ func (proxier *Proxier) openPortal(service proxy.ServicePortName, info *serviceI
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, proxyIP net.IP, proxyPort int, name proxy.ServicePortName) error {
|
func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, proxyIP net.IP, proxyPort int, name proxy.ServicePortName) error {
|
||||||
|
if local, err := isLocalIP(portal.ip); err != nil {
|
||||||
|
return fmt.Errorf("can't determine if IP is local, assuming not: %v", err)
|
||||||
|
} else if local {
|
||||||
|
err := proxier.claimNodePort(portal.ip, portal.port, protocol, name)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle traffic from containers.
|
// Handle traffic from containers.
|
||||||
args := proxier.iptablesContainerPortalArgs(portal.ip, portal.isExternal, false, portal.port, protocol, proxyIP, proxyPort, name)
|
args := proxier.iptablesContainerPortalArgs(portal.ip, portal.isExternal, false, portal.port, protocol, proxyIP, proxyPort, name)
|
||||||
existed, err := proxier.iptables.EnsureRule(iptables.Append, iptables.TableNAT, iptablesContainerPortalChain, args...)
|
existed, err := proxier.iptables.EnsureRule(iptables.Append, iptables.TableNAT, iptablesContainerPortalChain, args...)
|
||||||
@ -507,13 +518,13 @@ func (proxier *Proxier) openOnePortal(portal portal, protocol api.Protocol, prox
|
|||||||
|
|
||||||
// Marks a port as being owned by a particular service, or returns error if already claimed.
|
// Marks a port as being owned by a particular service, or returns error if already claimed.
|
||||||
// Idempotent: reclaiming with the same owner is not an error
|
// Idempotent: reclaiming with the same owner is not an error
|
||||||
func (proxier *Proxier) claimNodePort(port int, protocol api.Protocol, owner proxy.ServicePortName) error {
|
func (proxier *Proxier) claimNodePort(ip net.IP, port int, protocol api.Protocol, owner proxy.ServicePortName) error {
|
||||||
proxier.portMapMutex.Lock()
|
proxier.portMapMutex.Lock()
|
||||||
defer proxier.portMapMutex.Unlock()
|
defer proxier.portMapMutex.Unlock()
|
||||||
|
|
||||||
// TODO: We could pre-populate some reserved ports into portMap and/or blacklist some well-known ports
|
// TODO: We could pre-populate some reserved ports into portMap and/or blacklist some well-known ports
|
||||||
|
|
||||||
key := portMapKey{port: port, protocol: protocol}
|
key := portMapKey{ip: ip.String(), port: port, protocol: protocol}
|
||||||
existing, found := proxier.portMap[key]
|
existing, found := proxier.portMap[key]
|
||||||
if !found {
|
if !found {
|
||||||
// Hold the actual port open, even though we use iptables to redirect
|
// Hold the actual port open, even though we use iptables to redirect
|
||||||
@ -523,11 +534,12 @@ func (proxier *Proxier) claimNodePort(port int, protocol api.Protocol, owner pro
|
|||||||
// it. Tools like 'ss' and 'netstat' do not show sockets that are
|
// it. Tools like 'ss' and 'netstat' do not show sockets that are
|
||||||
// bind()ed but not listen()ed, and at least the default debian netcat
|
// bind()ed but not listen()ed, and at least the default debian netcat
|
||||||
// has no way to avoid about 10 seconds of retries.
|
// has no way to avoid about 10 seconds of retries.
|
||||||
socket, err := newProxySocket(protocol, net.ParseIP("127.0.0.1"), port)
|
socket, err := newProxySocket(protocol, ip, port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("can't open node port for %s: %v", key.String(), err)
|
return fmt.Errorf("can't open node port for %s: %v", key.String(), err)
|
||||||
}
|
}
|
||||||
proxier.portMap[key] = &portMapValue{owner: owner, socket: socket}
|
proxier.portMap[key] = &portMapValue{owner: owner, socket: socket}
|
||||||
|
glog.V(2).Infof("Claimed local port %s", key.String())
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if existing.owner == owner {
|
if existing.owner == owner {
|
||||||
@ -539,11 +551,11 @@ func (proxier *Proxier) claimNodePort(port int, protocol api.Protocol, owner pro
|
|||||||
|
|
||||||
// Release a claim on a port. Returns an error if the owner does not match the claim.
|
// Release a claim on a port. Returns an error if the owner does not match the claim.
|
||||||
// Tolerates release on an unclaimed port, to simplify .
|
// Tolerates release on an unclaimed port, to simplify .
|
||||||
func (proxier *Proxier) releaseNodePort(port int, protocol api.Protocol, owner proxy.ServicePortName) error {
|
func (proxier *Proxier) releaseNodePort(ip net.IP, port int, protocol api.Protocol, owner proxy.ServicePortName) error {
|
||||||
proxier.portMapMutex.Lock()
|
proxier.portMapMutex.Lock()
|
||||||
defer proxier.portMapMutex.Unlock()
|
defer proxier.portMapMutex.Unlock()
|
||||||
|
|
||||||
key := portMapKey{port: port, protocol: protocol}
|
key := portMapKey{ip: ip.String(), port: port, protocol: protocol}
|
||||||
existing, found := proxier.portMap[key]
|
existing, found := proxier.portMap[key]
|
||||||
if !found {
|
if !found {
|
||||||
// We tolerate this, it happens if we are cleaning up a failed allocation
|
// We tolerate this, it happens if we are cleaning up a failed allocation
|
||||||
@ -562,7 +574,7 @@ func (proxier *Proxier) openNodePort(nodePort int, protocol api.Protocol, proxyI
|
|||||||
// TODO: Do we want to allow containers to access public services? Probably yes.
|
// TODO: Do we want to allow containers to access public services? Probably yes.
|
||||||
// TODO: We could refactor this to be the same code as portal, but with IP == nil
|
// TODO: We could refactor this to be the same code as portal, but with IP == nil
|
||||||
|
|
||||||
err := proxier.claimNodePort(nodePort, protocol, name)
|
err := proxier.claimNodePort(nil, nodePort, protocol, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -616,6 +628,14 @@ func (proxier *Proxier) closePortal(service proxy.ServicePortName, info *service
|
|||||||
func (proxier *Proxier) closeOnePortal(portal portal, protocol api.Protocol, proxyIP net.IP, proxyPort int, name proxy.ServicePortName) []error {
|
func (proxier *Proxier) closeOnePortal(portal portal, protocol api.Protocol, proxyIP net.IP, proxyPort int, name proxy.ServicePortName) []error {
|
||||||
el := []error{}
|
el := []error{}
|
||||||
|
|
||||||
|
if local, err := isLocalIP(portal.ip); err != nil {
|
||||||
|
el = append(el, fmt.Errorf("can't determine if IP is local, assuming not: %v", err))
|
||||||
|
} else if local {
|
||||||
|
if err := proxier.releaseNodePort(nil, portal.port, protocol, name); err != nil {
|
||||||
|
el = append(el, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle traffic from containers.
|
// Handle traffic from containers.
|
||||||
args := proxier.iptablesContainerPortalArgs(portal.ip, portal.isExternal, false, portal.port, protocol, proxyIP, proxyPort, name)
|
args := proxier.iptablesContainerPortalArgs(portal.ip, portal.isExternal, false, portal.port, protocol, proxyIP, proxyPort, name)
|
||||||
if err := proxier.iptables.DeleteRule(iptables.TableNAT, iptablesContainerPortalChain, args...); err != nil {
|
if err := proxier.iptables.DeleteRule(iptables.TableNAT, iptablesContainerPortalChain, args...); err != nil {
|
||||||
@ -665,13 +685,30 @@ func (proxier *Proxier) closeNodePort(nodePort int, protocol api.Protocol, proxy
|
|||||||
el = append(el, err)
|
el = append(el, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := proxier.releaseNodePort(nodePort, protocol, name); err != nil {
|
if err := proxier.releaseNodePort(nil, nodePort, protocol, name); err != nil {
|
||||||
el = append(el, err)
|
el = append(el, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return el
|
return el
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isLocalIP(ip net.IP) (bool, error) {
|
||||||
|
addrs, err := net.InterfaceAddrs()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
for i := range addrs {
|
||||||
|
intf, _, err := net.ParseCIDR(addrs[i].String())
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
if ip.Equal(intf) {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
|
||||||
// See comments in the *PortalArgs() functions for some details about why we
|
// See comments in the *PortalArgs() functions for some details about why we
|
||||||
// use two chains for portals.
|
// use two chains for portals.
|
||||||
var iptablesContainerPortalChain iptables.Chain = "KUBE-PORTALS-CONTAINER"
|
var iptablesContainerPortalChain iptables.Chain = "KUBE-PORTALS-CONTAINER"
|
||||||
|
@ -46,7 +46,11 @@ type proxySocket interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func newProxySocket(protocol api.Protocol, ip net.IP, port int) (proxySocket, error) {
|
func newProxySocket(protocol api.Protocol, ip net.IP, port int) (proxySocket, error) {
|
||||||
host := ip.String()
|
host := ""
|
||||||
|
if ip != nil {
|
||||||
|
host = ip.String()
|
||||||
|
}
|
||||||
|
|
||||||
switch strings.ToUpper(string(protocol)) {
|
switch strings.ToUpper(string(protocol)) {
|
||||||
case "TCP":
|
case "TCP":
|
||||||
listener, err := net.Listen("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
|
listener, err := net.Listen("tcp", net.JoinHostPort(host, strconv.Itoa(port)))
|
||||||
|
Loading…
Reference in New Issue
Block a user