<p><strong>traefik.toml</strong>:</p>

<pre><code>defaultEntryPoints = ["http", "https"]

[entryPoints]
  [entryPoints.http]
  address = ":80"
    [entryPoints.http.forwardedHeaders]
      trustedIPs = ["0.0.0.0/0"]
    [entryPoints.http.redirect]
      entryPoint = "https"
  [entryPoints.https]
  address = ":443"
    [entryPoints.https.tls]
    [entryPoints.https.forwardedHeaders]
      trustedIPs = ["0.0.0.0/0"]
[api]
</code></pre>

<p><strong>traefik Service</strong>:</p>

<pre><code>kind: Service
apiVersion: v1
metadata:
  name: traefik-ingress-service
  namespace: kube-system
spec:
  selector:
    k8s-app: traefik-ingress-lb
  ports:
    - protocol: TCP
      port: 80
      name: http
    - protocol: TCP
      port: 443
      name: https
  type: LoadBalancer
</code></pre>

<p><strong>Then:</strong></p>

<pre><code>kubectl run source-ip-app --image=k8s.gcr.io/echoserver:1.4
deployment "source-ip-app" created

kubectl expose deployment source-ip-app --name=clusterip --port=80 --target-port=8080
service "clusterip" exposed

kubectl get svc clusterip
NAME        TYPE        CLUSTER-IP    EXTERNAL-IP   PORT(S)   AGE
clusterip   ClusterIP   10.5.55.102   &lt;none&gt;        80/TCP    2h
</code></pre>

<p><strong>Create ingress for clusterip:</strong></p>

<pre><code>apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: clusterip-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: traefik
spec:
  rules:
  - host: clusterip.staging
    http:
      paths:
      - backend:
          serviceName: clusterip
          servicePort: 80
</code></pre>

<p><strong>clusterip.staging ip: 192.168.0.69</strong></p>

<p><strong>From other pc with ip: 192.168.0.100:</strong></p>

<pre><code>wget -qO - clusterip.staging
</code></pre>

<p><strong>and get results:</strong></p>

<pre><code>CLIENT VALUES:
client_address=10.5.65.74
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://clusterip.staging:8080/

SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001

HEADERS RECEIVED:
accept=text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
accept-encoding=gzip, deflate, br
accept-language=ru-RU,ru;q=0.8,en-US;q=0.5,en;q=0.3
cache-control=max-age=0
host=clusterip.staging
upgrade-insecure-requests=1
x-forwarded-for=10.5.64.0
x-forwarded-host=clusterip.staging
x-forwarded-port=443
x-forwarded-proto=https
x-forwarded-server=traefik-ingress-controller-755cc56458-t8q9k
x-real-ip=10.5.64.0
BODY:
-no body in request-
</code></pre>

<p><strong>kubectl get svc --all-namespaces</strong></p>

<pre><code>NAMESPACE     NAME                      TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)                                                 AGE
default       clusterip                 NodePort       10.5.55.102   &lt;none&gt;         80:31169/TCP                                            19h
default       kubernetes                ClusterIP      10.5.0.1      &lt;none&gt;         443/TCP                                                 22d
kube-system   kube-dns                  ClusterIP      10.5.0.3      &lt;none&gt;         53/UDP,53/TCP                                           22d
kube-system   kubernetes-dashboard      ClusterIP      10.5.5.51     &lt;none&gt;         443/TCP                                                 22d
kube-system   traefik-ingress-service   LoadBalancer   10.5.2.37     192.168.0.69   80:32745/TCP,443:30219/TCP                              1d
kube-system   traefik-web-ui            NodePort       10.5.60.5     &lt;none&gt;         80:30487/TCP                                            7d
</code></pre>

<p><strong>How to get real ip (192.168.0.100) in my installation? Why x-real-ip 10.5.64.0?</strong> I could not find the answers in the documentation.</p>

Andrey Perminov
<p>When <code>kube-proxy</code> uses the <code>iptables</code> mode, it uses NAT to send data to the node where payload works, and you lose the original <code>SourceIP</code> address in that case.</p>

<p>As I understood, you use <code>Matallb</code> behind the <code>Traefik</code> Ingress Service (because its type is <code>LoadBalancer</code>). That means traffic from the client to the backend goes that way:</p>

<p><code>Client -&gt; Metallb -&gt; Traefik LB -&gt; Traefik Service -&gt; Backend pod</code>.</p>

<p>Traefik works correctly and adds headers <code>x-*</code>, including <code>x-forwarded-for</code> and <code>x-real-ip</code> which contain a fake address, and that's why:</p>

<p>From the <code>Metallb</code> <a href="https://metallb.universe.tf/usage/" rel="noreferrer">documentation</a>:</p>

<blockquote>
  <p>MetalLB understands the service’s <code>externalTrafficPolicy</code> option and implements different announcements modes depending on the policy and announcement protocol you select.</p>
  
  <ul>
  <li><p><strong>Layer2</strong></p>
  
  <p>This policy results in uniform traffic distribution across all pods in the service. However, <code>kube-proxy</code> will <strong>obscure the source IP address</strong> of the connection when it does load-balancing, so your pod logs will show that external traffic appears to be coming from the cluster’s leader node.</p></li>
  <li><p><strong>BGP</strong></p>
  
  <ul>
  <li><p><strong>“Cluster” traffic policy</strong></p>
  
  <p>With the default Cluster traffic policy, every node in your cluster will attract traffic for the service IP. On each node, the traffic is subjected to a second layer of load-balancing (provided by kube-proxy), which directs the traffic to individual pods.</p>
  
  <p>......</p>
  
  <p>The other downside of the “Cluster” policy is that <code>kube-proxy</code> will <strong>obscure the source IP address</strong> of the connection when it does its load-balancing, so your pod logs will show that external traffic appears to be coming from your cluster’s nodes.</p></li>
  <li><p><strong>“Local” traffic policy</strong></p>
  
  <p>With the Local traffic policy, nodes will only attract traffic if they are running one or more of the service’s pods locally. The BGP routers will load-balance incoming traffic only across those nodes that are currently hosting the service. On each node, the traffic is forwarded only to local pods by kube-proxy, there is no “horizontal” traffic flow between nodes.</p>
  
  <p>This policy provides the most efficient flow of traffic to your service. Furthermore, because <code>kube-proxy</code> doesn’t need to send traffic between cluster nodes, <strong>your pods can see the real source IP address</strong> of incoming connections.</p></li>
  </ul></li>
  </ul>
</blockquote>

<p>Finally, the only way to get the real source IP address is to use "Local" mode of <code>TrafficPolicy</code>.</p>

<p>If you set it up, you will get what you want.</p>
