From 93f8d41aac0c3fdd833c3e2dbbeea9ed07e71eb3 Mon Sep 17 00:00:00 2001 From: pierre Date: Thu, 23 Jul 2026 10:06:43 +0100 Subject: [PATCH] fix(reverse-proxy): preserve real client IP in nginx logs Nginx logs showed internal cluster IPs instead of public client IPs. Root cause was three stacked issues in the traffic path from MetalLB LoadBalancer VIP to the reverse-proxy pods: 1. Service was using externalTrafficPolicy: Cluster, allowing kube-proxy to forward traffic cross-node and SNAT the source IP in the process. Changed to externalTrafficPolicy: Local so traffic is only handled by pods on the node that received it. 2. reverse-proxy DaemonSet had a pinned in the pod template, forcing all replicas onto a single node instead of scheduling one per node as expected for a DaemonSet. Removed nodeName so the DaemonSet scheduler places one pod per eligible node (both control-plane nodes, tolerations already in place). 3. Even with the above fixed, flannel's CNI masquerade rule was still SNAT'ing traffic to the pod network address (10.244.x.x) before it reached nginx, since traffic into the pod overlay network gets masqueraded regardless of kube-proxy's policy. Switched the DaemonSet to hostNetwork: true (with dnsPolicy: ClusterFirstWithHostNet) so nginx binds directly to the node's network namespace and bypasses the overlay masquerade entirely. Result: nginx access logs now show the real public client IP for every request instead of node/pod-internal addresses. --- Nginx.kube.yaml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Nginx.kube.yaml b/Nginx.kube.yaml index 6c44228..e24f521 100644 --- a/Nginx.kube.yaml +++ b/Nginx.kube.yaml @@ -4,14 +4,15 @@ metadata: name: reverse-proxy --- apiVersion: apps/v1 -kind: Deployment +#kind: Deployment +kind: DaemonSet metadata: name: reverse-proxy namespace: reverse-proxy annotations: reloader.stakater.com/search: "true" spec: - replicas: 1 + #replicas: 1 selector: matchLabels: app: reverse-proxy @@ -20,7 +21,9 @@ spec: labels: app: reverse-proxy spec: - nodeName: kube-master + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet # required when hostNetwork: true + #nodeName: kube-master # Allows the sidecar to see and signal the Nginx process shareProcessNamespace: true containers: @@ -63,6 +66,7 @@ spec: limits: cpu: 250m memory: 250Mi + - name: watcher image: alpine:latest command: ["/bin/sh", "-c"] @@ -88,7 +92,15 @@ spec: volumeMounts: - name: blacklisted-memory-volume mountPath: /etc/nginx/blacklisted.d/ - + tolerations: + # these tolerations are to have the daemonset runnable on control plane nodes + # remove them if your control plane nodes should not run pods + - key: node-role.kubernetes.io/control-plane + operator: Exists + effect: NoSchedule + - key: node-role.kubernetes.io/master + operator: Exists + effect: NoSchedule volumes: - name: reverse-proxy-log