Last Updated: March 30th, 2025
Introduction
This article highlights steps on how users can choose the externalTrafficPolicy based on specific application requirements like source IP preservation in Crusoe Managed Kubernetes (CMK).
Prerequisites
Access to a Crusoe Cloud project with appropriate permissions
Existing Crusoe Managed Kubernetes Cluster
Access to
crusoeandkubectlCLI
Step-by-Step Instructions
Apply sample application deployment and service specification.
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-test
spec:
replicas: 1
selector:
matchLabels:
app: web-test
template:
metadata:
labels:
app: web-test
spec:
containers:
- name: web-server
image: python:3.11-slim
command: ["python", "-u", "-m", "http.server", "8000"]
workingDir: /tmp
env:
- name: PYTHONUNBUFFERED
value: "1"
ports:
- containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:
name: web-test-svc
spec:
type: LoadBalancer
selector:
app: web-test
ports:
- protocol: TCP
port: 80
targetPort: 80002. By default, the externalTrafficPolicy is set to Cluster. Refer to Crusoe Load Balancer to deploy the required configuration.
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
web-test-<xxxxxx>-<xxxxx> 1/1 Running 0 47m
$ kubectl get svc web-test-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
web-test-svc LoadBalancer 10.233.24.171 203.0.113.100 80:32444/TCP 67m
$ kubectl get svc web-test-svc -o yaml | grep externalTrafficPolicy
externalTrafficPolicy: ClusterNote: Once you create the Kubernetes service object, ensure to create an ingress firewall rule. This rule should allow inbound traffic from any source IP (0.0.0.0/0) to the destination subnet and the nodePort of the service object.
3. Verify Load Balancer details using Crusoe CLI.
$ crusoe networking load-balancers get default-web-test-svc-1ad5720f
name: default-web-test-svc-1ad5720f
virtual_ip: 203.0.113.100
location: eu-iceland1-a
protocol: tcp
listen_ports: Port 80 (backends: 172.27.61.24:32444:offline,172.27.63.68:32444:online)
health_check: Timeout=5,Interval=5,Success=3,Failure=2
...4. Test endpoint access via curl to ELB IP.
$ LB_IP=$(kubectl get svc web-test-svc -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
$ for i in {1..10}; do
curl -s $LB_IP | grep "DOCTYPE" && echo "Request $i: SUCCESS" || echo "Request $i: FAILED"
done
<!DOCTYPE HTML>
Request 1: SUCCESS
<!DOCTYPE HTML>
Request 2: SUCCESS
<!DOCTYPE HTML>
Request 3: SUCCESS
<!DOCTYPE HTML>
Request 4: SUCCESS
<!DOCTYPE HTML>
Request 5: SUCCESS
<!DOCTYPE HTML>Requests show internal cluster IP, not the real client IP for the curl requests. The node's kube-proxy applies SNAT rules, rewriting the source IP to an internal cluster address before the traffic reaches the pod.
$ kubectl logs -l app=web-test
10.234.0.61 - - [30/Mar/2026 22:22:58] "HEAD / HTTP/1.1" 200 -
10.234.0.61 - - [30/Mar/2026 22:23:01] "HEAD / HTTP/1.1" 200 -
10.234.0.61 - - [30/Mar/2026 22:28:39] "GET / HTTP/1.1" 200 -
10.234.0.61 - - [30/Mar/2026 22:28:40] "GET / HTTP/1.1" 200 -
10.234.0.61 - - [30/Mar/2026 22:28:40] "GET / HTTP/1.1" 200 -
10.234.0.61 - - [30/Mar/2026 22:28:40] "GET / HTTP/1.1" 200 -5. Patch the Service object to set externalTrafficPolicy: Local
$ kubectl patch svc web-test-svc -p '{"spec":{"externalTrafficPolicy":"Local"}}'
service/web-test-svc patched
$ kubectl get svc web-test-svc -o yaml | grep externalTrafficPolicy
externalTrafficPolicy: Local6. Test endpoint access again via curl to ELB IP.
$ for i in {1..10}; do
curl -s $LB_IP | grep "DOCTYPE" && echo "Request $i: SUCCESS" || echo "Request $i: FAILED"
done
=== LOCAL policy (10 requests) ===
<!DOCTYPE HTML>
Request 1: SUCCESS
<!DOCTYPE HTML>
Request 2: SUCCESS
<!DOCTYPE HTML>
Request 3: SUCCESS
<!DOCTYPE HTML>
Request 4: SUCCESS
<!DOCTYPE HTML>
Request 5: SUCCESS
<!DOCTYPE HTML>$ kubectl logs -l app=web-test
67.208.231.219 - - [30/Mar/2026 22:28:41] "GET / HTTP/1.1" 200 -
67.208.231.219 - - [30/Mar/2026 22:33:36] "GET / HTTP/1.1" 200 -
67.208.231.219 - - [30/Mar/2026 22:33:36] "GET / HTTP/1.1" 200 -
67.208.231.219 - - [30/Mar/2026 22:33:37] "GET / HTTP/1.1" 200 -
67.208.231.219 - - [30/Mar/2026 22:33:37] "GET / HTTP/1.1" 200 -
67.208.231.219 - - [30/Mar/2026 22:33:37] "GET / HTTP/1.1" 200 -