Code change:
/kind bug /sig network (I'm not sure this is actually a bug but it is definitely a behavior that is different from iptables and some applications rely on this) What happened: From the host network namespace accessing a ClusterIP when using IPVS does not work (it only works when traffic is sent to a local pod) What you expected to happen: To be able to use ClusterIPs from the host network namespace How to reproduce it (as minimally and precisely as possible): Configure kube-proxy in IPVS mode Create a deployment and the associated service Try to access the ClusterIP from the host Anything else we need to know?: This does not work due to how routing is set up when using IPVS If we create a service with ClusterIP , kube-proxy will add this IP to the kube-ivps0 dummy interface: which will add the IP to the local route table: (where 10.0.0.5 is the main interface for the instance) So when accessing the ClusterIP from the host, the source IP will default to the ClusterIP: After IPVS, the destination will be changed to a pod IP but the source will still be ClusterIP. Since ClusterIPs are not routable the answer will be lost. A workaround would be to modify the local route to use the IP of the main interface as source: I tested this and it seems to work fine. Environment: Kubernetes version (use ): Cloud provider or hardware configuration: OS (e.g. from /etc/os-release): Ubuntu 18.04 Kernel (e.g. ): 4.15.0-1008-gcp
/area ipvs
Don't you have MASQUERADE rule somewhere? My clusters use flannel to create MASQUERADE rule and I guess it could also be done in kube-proxy with --masquerade-all=true option.
I don't have any specific masquerade configuration: kubelet is run without so it uses the default (both my pod and service CIDRs are in this range) kube-proxy is run without So I have the following masquerading rules: (from kubelet) from kube-proxy for hairpin traffic My instances are also configured to NAT on KUBE-MARK-MASQ mark but in IPVS mode this chain is not referenced in the default configuration. I confirm that running kube-proxy with works but it feels like a workaround: if we do that we also masquerade pod-to-service traffic which seems unnecessary (and we lose the source pod IP)
Is it possible to have pod ip and service ip configured in same range? Guess I am just familiar with my own cluster setup which use cluster-cidr.... Hope others can help you.
Sorry, I meant both are in but they are different ( and )
cc I assume this bug has already been fixed?
I am going to close this issue since it should be fixed by , please re-open if you still have troubles after picking
/close
Thank you for looking into this I'll check with kube-proxy 1.11 very soon and will let you know
I just tested and it does not seem to work I updated kube-proxy to but I still have the problem Looking at the code, it looks like the KUBE-MARK-MASQ is not to the service chain because the ipset is empty (which should not be the case because I actually have some services deployed) Did I miss something?
Did you configure the --cluster-cidr?
cc any comments?
No I did not I just realized this was the source of the problem here: We usually don't configure it because we have no need for it: we don't advertise the service cidr externally we would rather have pods using loadbalancer IPs actually hit the load-balancers (easier to understand and debug if we have similar routing for hosts outside the cluster and pods for the same "host")
Yeah, seems you find the root cause. clusterIPSet should not be empty.

Related discussion:
text: } // add service Cluster IP:Port to kubeServiceAccess ip set for the purpose of solving hairpin. // proxier.kubeServiceAccessSet.activeEntries.Insert(entry.String()) <del> // Install masquerade rules if 'masqueradeAll' or 'clusterCIDR' is specified. if proxier.masqueradeAll || len(proxier.clusterCIDR) > 0 { if valid := proxier.ipsetList[kubeClusterIPSet].validateEntry(entry); !valid { glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.ipsetList[kubeClusterIPSet].Name)) continue } proxier.ipsetList[kubeClusterIPSet].activeEntries.Insert(entry.String()) </del> <ins> if valid := proxier.ipsetList[kubeClusterIPSet].validateEntry(entry); !valid { glog.Errorf("%s", fmt.Sprintf(EntryInvalidErr, entry, proxier.ipsetList[kubeClusterIPSet].Name)) continue </ins> } <ins> proxier.ipsetList[kubeClusterIPSet].activeEntries.Insert(entry.String()) </ins> // ipvs call serv := &utilipvs.VirtualServer{ Address:   svcInfo.ClusterIP,