Hello Linkerd community,
I’m trying to implement a solution for using fixed IP addresses for egress traffic from specific applications in my Kubernetes cluster. I would appreciate any guidance on how to achieve this using Linkerd.
My setup
- Self-hosted RKE2 Kubernetes cluster (v1.31.3+rke2r1)
- 6 nodes
- Linkerd version: edge-25.5.1
- CNI: Canal (Calico+Flannel)
- LoadBalancer: MetalLB
- OPNsense firewall for external traffic
What I’m trying to achieve
I want specific applications to use a fixed, predefined IP address (10.x.y.100) for their outbound/egress traffic to the internet. Specifically:
- Regular pods in the cluster should use their default node IP for egress traffic
- Some specific applications need to use a predetermined IP (10.x.y.100)
- The solution should work with HTTP and HTTPS traffic
Current approach
I’ve set up an Envoy-based egress gateway with Linkerd:
apiVersion: v1
kind: Namespace
metadata:
name: linkerd-egress
annotations:
linkerd.io/inject: enabled
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: egress-gateway
namespace: linkerd-egress
spec:
replicas: 1
selector:
matchLabels:
app: egress-gateway
template:
metadata:
labels:
app: egress-gateway
annotations:
config.linkerd.io/proxy-outbound-port: "8080"
config.linkerd.io/skip-outbound-ports: "443,80"
spec:
containers:
- name: proxy
image: envoyproxy/envoy:v1.22.0
# ... [configuration details]
---
apiVersion: v1
kind: Service
metadata:
name: egress-gateway
namespace: linkerd-egress
spec:
type: LoadBalancer
loadBalancerIP: 10.x.y.100
ports:
- port: 8080
targetPort: 8080
selector:
app: egress-gateway
Then I created an app that tries to use this gateway:
apiVersion: v1
kind: Pod
metadata:
name: egress-debug-pod
namespace: app-fixed-ip-linkerd
annotations:
linkerd.io/inject: enabled
spec:
containers:
- name: debug
image: nicolaka/netshoot:latest
# ... [configuration details]
The issue
When I run tests from inside the pod, I can successfully reach external services like httpbin.org, but my tcpdump monitoring on the node shows that the traffic is leaving with the node’s IP (10.x.y.12) instead of the gateway’s fixed IP (10.x.y.100):
09:27:18.917124 cali115e2e38908 In IP 172.16.a.b.55964 > 18.205.c.d.80: Flags [S], seq 399294597, win 64860, options [mss 1410,sackOK,TS val 213956220 ecr 0,nop,wscale 7], length 0
09:27:18.917161 eth0 Out IP 10.x.y.12.17975 > 18.205.c.d.80: Flags [S], seq 399294597, win 64860, options [mss 1410,sackOK,TS val 213956220 ecr 0,nop,wscale 7], length 0
Even when accessing the egress gateway service directly:
curl http://egress-gateway.linkerd-egress.svc.cluster.local:8080/ip
The traffic still shows my public IP (a.b.c.d) rather than the fixed IP.
Questions
- What is the recommended approach to achieve fixed egress IPs with Linkerd?
- Is there a way to configure Linkerd to route egress traffic from specific namespaces through a dedicated gateway with a fixed IP?
- Should I be using a different Linkerd configuration or pattern for this use case?
- Do I need specific firewall rules to make this work properly?
I understand that I might need to set up NAT rules in my OPNsense firewall, but I’d like to understand the proper Linkerd configuration first, to ensure the traffic is correctly routed through the egress gateway.
Any help or pointers to relevant documentation or examples would be greatly appreciated!
Thanks for your time!
Daniel