Reputation: 379
My requests are being proxied through Cloudflare which sets a header indicating the country in a http header based on the IP address. I want to redirect the requests with certain paths based on this header in Nginx ingress controller. How do I do this?
Upvotes: 1
Views: 9618
Reputation: 9877
Currently Ingress
resource definition for nginx-ingress
does not support header based routing.
I found a workaround to route a request by it's header (I've included the steps below) with following annotation:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }
Other possible solutions/workarounds:
Traefik
: Docs.traefik.io: Routing: RoutersAmbassador
: Getambassador.io: Docs: Using: HeadersIstio
: Istio.io: Traffic management: Request routingnginx-ingress
to nginx pod/deployment/daemonset with header based routing logic included: Stackoverflow.com: How to have a header routing logic with nginx ingress-controller?
(last comment under the answer)As for a workaround:
Assuming that (for example purposes):
hello
,goodbye
hello-service
, goodbye-service
The Ingress
resource will be configured in a way that hello
should always answer, but with the addition of configuration-snippet
the traffic will be redirected to goodbye
.
Responses of this deployments:
| hello | goodbye |
|----------------|----------------|
| Hello, world! | Hello, world! |
| Version: 2.0.0 | Version: 1.0.0 | # notice the version
Example of hello
deployment with a service attached to it:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello
spec:
selector:
matchLabels:
app: hello
replicas: 1
template:
metadata:
labels:
app: hello
spec:
containers:
- name: hello
image: "gcr.io/google-samples/hello-app:2.0"
env:
- name: "PORT"
value: "50001"
---
apiVersion: v1
kind: Service
metadata:
name: hello-service
spec:
selector:
app: hello
ports:
- name: hello-port
port: 5678 # IMPORTANT
targetPort: 50001
type: NodePort
To get the goodbye
deployment please substitute the hello
for goodbye
and change the image version to 1.0
.
Ingress definition to reroute the request by a header looks like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: hello-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }
spec:
rules:
- host:
http:
paths:
- path: /
backend:
serviceName: hello-service
servicePort: hello-port
By default this Ingress definition without the configuration-snippet
would always route the traffic to hello-service
and then to hello
pods. By adding the:
nginx.ingress.kubernetes.io/configuration-snippet: |
if ($http_LocationHeader = "PL") { proxy_pass http://goodbye-service.default.svc.cluster.local:5678; }
it will check if the header named LocationHeader
is present and if it matches PL
. If it does it will send the request to goodbye-service
by it's DNS name.
Focusing on:
http://goodbye-service.default.svc.cluster.local:5678
http://service_name.namespace.svc.cluster.local:port
(dns name without values)After applying this Ingress
resource you should be able to send a request with LocationHeader=PL
(with Postman for example) and get the response:
Hello, world!
Version: 1.0.0
Hostname: goodbye-5758448754-wr64c
When I tried to use
map
directive I was getting following messages:
nginx: [emerg] "map" directive is not allowed here in /tmp/nginx-OMMITED
Upvotes: 17