I'm trying to proxy_pass the traffic based on user-agent. Tried to use server-snippet / configuration-snippet for it, but ingress doesn't allow me. (Forbids to use proxy_pass in server-snippet and argues about duplicates in configuration-snippet)
I can't just use the "backend" as I have to dynamically pass the traffic myself based on user-agent. Any chances I could do it? Not working configuration example below (without user-agent yet)
apiVersion: extensions/v1beta1
kind: Ingress
spec:
rules:
- host: m-rm-qa.yadayadayada
http:
paths:
- path: /
backend:
serviceName: frontend-svc
servicePort: 80
metadata:
name: rm-frontend-ingress
namespace: rm-qa
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/server-snippet: |
proxy_pass http://prerender-service:3000;
rewrite .* /$scheme://$host$request_uri? break;
I've tried to reproduce your scenario using Nginx Ingress but without success using server-snippet
and configuration-snippet
.
I did some researches and see that Nginx Plus
there's a snippet called location-snippet
that should work. See here.
Alternatively, I've created a custom Nginx deployment with a Service type LoadBalancer
and created a configMap
with a custom Nginx configuration, and it's works!
If you want to try, you need to create a configMap
with your custom default.conf
file, it's looks like this:
I'm using the namespace:
default
for this example, but you can create a custom namespace if you want.
nginx-custom-config.yaml:
---
apiVersion: v1
kind: ConfigMap
metadata:
name: custom-nginx-config
namespace: default
data:
default.conf: |
upstream my-svc {
server echo-svc.default.svc.cluster.local;
}
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
if ($http_user_agent ~* "iPhone|iPad" ) {
add_header X-Vendor "Apple";
proxy_pass http://my-svc;
}
if ($http_user_agent ~ Chrome ) {
add_header X-Vendor "OpenSource";
proxy_pass http://my-svc;
}
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
Apply to Kubernetes:
kubectl apply -f nginx-custom-config.yaml
upstream
called my-svc
pointing to my destination service echo-svc.default.svc.cluster.local
.location: /
there's a condition that matches the User-agent
, in this case, if a request was made from a Apple device "iPhone|iPad"
a header named X-Vendor
with value Apple
will be created and redirected the request to my destination service my-svc
. The same will happen if the request was made from "Chrome", but the header will be X-Vendor: "OpenSource"
.After that you need to create a deployment
of a Nginx image mounting our configMap
as a file inside the containers, like this:
custom-nginx-deployment.yaml:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: custom-nginx
spec:
selector:
matchLabels:
app: custom-nginx
template:
metadata:
labels:
app: custom-nginx
spec:
containers:
- name: custom-nginx
image: nginx
volumeMounts:
- name: custom-nginx-config
mountPath: /etc/nginx/conf.d
ports:
- name: http
containerPort: 80
imagePullPolicy: IfNotPresent
volumes:
- name: custom-nginx-config
configMap:
name: custom-nginx-config
kubectl apply -f custom-nginx-deployment.yaml
And finally, creating a LoadBalancer
Service to received the requests:
custom-nginx-svc.yaml:
---
apiVersion: v1
kind: Service
metadata:
name: custom-nginx-svc
labels:
app: custom-nginx
spec:
selector:
app: custom-nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
type: LoadBalancer
kubectl apply -f custom-nginx-svc.yaml
You can check if the container and service was successfully deployed using the commands:
kubectl get pods -l app=custom-nginx
kubectl get svc -l app=custom-nginx
Hope that helps!