How to preserve source IP from traffic arriving on a ClusterIP service with an external IP?

2/27/2017

I currently have a service that looks like this:

apiVersion: v1
kind: Service
metadata:
  name: httpd
spec:
  ports:
    - port: 80
      targetPort: 80
      name: http
      protocol: TCP
    - port: 443
      targetPort: 443
      name: https
      protocol: TCP
  selector:
    app: httpd
  externalIPs:
    - 10.128.0.2  # VM's internal IP

I can receive traffic fine from the external IP bound to the VM, but all of the requests are received by the HTTP with the source IP 10.104.0.1, which is most definitely an internal IP – even when I connect to the VM's external IP from outside the cluster.

How can I get the real source IP for the request without having to set up a load balancer or ingress?

--
google-compute-engine
google-kubernetes-engine
kubernetes
network-programming

2 Answers

7/20/2017

If you only have exactly one pod, you can use hostNetwork: true to achieve this:

apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: caddy
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: caddy
    spec:
      hostNetwork: true # <---------
      containers:
      - name: caddy
        image: your_image
        env:
        - name: STATIC_BACKEND # example env in my custom image
          value: $(STATIC_SERVICE_HOST):80

Note that by doing this your pod will inherit the host's DNS resolver and not Kubernetes'. That means you can no longer resolve cluster services by DNS name. For example, in the example above you cannot access the static service at http://static. You still can access services by their cluster IP, which are injected by environment variables.

-- willwill
Source: StackOverflow

6/9/2017

This is not simple to achieve -- because of the way kube-proxy works, your traffic can get forwarded between nodes before it reaches the pod that's backing your Service.

There are some beta annotations that you can use to get around this, specifically service.beta.kubernetes.io/external-traffic: OnlyLocal.

More info in the docs, here: https://kubernetes.io/docs/tutorials/services/source-ip/#source-ip-for-services-with-typeloadbalancer

But this does not meet your additional requirement of not requiring a LoadBalancer. Can you expand upon why you don't want to involve a LoadBalancer?

-- Symmetric
Source: StackOverflow