Preserve Source Internet Protocol (IP) Address When Using Ingress

Some applications require a Kubernetes service of type LoadBalancer, which preserves the source IP address of incoming packets. Example: Ingress controllers. You can manually integrate a Network Load Balancer (NLB) by exposing and attaching a public IP address to a viable Kubernetes node. This node serves as a load balancer using kube-proxy.

Note:

  • This works fine with services that use externalTrafficPolicy: Cluster, but in this case, the client's source IP address is lost.

  • The public IP address that is used as the Load Balancer IP address also needs to be bound to those nodes on which the ingress controller is running.

To preserve the client source IP address, Kubernetes services with externalTrafficPolicy: Local need to be used. This configuration ensures that packets reaching a node are only forwarded to Pods that run on the same node, preserving the client source IP address. Therefore, the load balancer IP address of the service needs to be attached to the same node running the ingress controller pod.

This can be achieved with different strategies. One approach is to use a DaemonSet to ensure that a pod is running on each node. However, this approach is feasible only in some cases, and if a cluster has a lot of nodes, then using DaemonSet could lead to a waste of resources.

For an efficient setup, you can schedule Pods to be run only on nodes of a specific node pool using nodeSelector. The node pool needs to have labels that can be used in the node selector. To ensure that the service's load balancer IP is also attached to one of these nodes, annotate the service with cloud.ionos.com/node-selector: key=value, where the key and value are the labels of the node pool.

The following example shows how to install the ingress-nginx helm chart as a DaemonSet with node selector and to configure the controller service with the required annotation.

  1. Create a node pool with a label nodepool=ingress:

    ionosctl k8s nodepool create --cluster-id <cluster-id> \
        --name ingress --node-count 1 --datacenter-id <datacenter-id> --labels nodepool=ingress
  2. Create a values.yaml file for later use in the helm command with the following content:

    controller:
      nodeSelector:
        nodepool: ingress
      service:
        annotations:
          cloud.ionos.com/node-selector: nodepool=ingress
      kind: DaemonSet
  3. Install ingress-nginx via helm using the following command:

    helm upgrade --install ingress-nginx ingress-nginx \
    --repo https://kubernetes.github.io/ingress-nginx \
    --namespace ingress-nginx --create-namespace -f values.yaml

Last updated