Configure Kubernetes Traefik Ingress with different path rewrites for each service - nginx

I'm in the process of migration of our application from single instance Docker-compose configuration to Kubernetes. I currently have the following example NGINX configuration, running as a reverse proxy of my application:
server {
server_name example.com;
ssl_certificate /etc/nginx/certs/${CERT_NAME};
ssl_certificate_key /etc/nginx/certs/${KEY_NAME};
listen 443 ssl;
keepalive_timeout 70;
access_log /var/log/nginx/access.log mtail;
ssl_protocols xxxxxx
ssl_ciphers xxxxxx
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
rewrite_log on;
resolver 127.0.0.11 ipv6=off;
location /push/ {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/htpasswd;
rewrite /push/(.*) /index.php/$1 break;
proxy_pass pushinterface:3080;
}
location /flights/ {
rewrite /flights/(.*) /$1 break;
proxy_pass flightstats:3090;
}
location /api/ {
proxy_pass $api;
}
location /grafana/ {
access_log off;
log_not_found off;
proxy_pass http://grafana:3000;
rewrite ^/grafana/(.*) /$1 break;
}
}
My initial plans for the reverse proxy part was implementing an ingress with NGINX ingress controller, but I saw that my configuration can be created as Ingress only with NGINX Plus. That's why I decided to try with Traefik, but I'm not sure if it's still possible to have different rewrites of the path for each service.
I tried the following Ingress configuration, but it seems it's not working:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-traefik
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: ReplacePathRegex
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: pushinterface
servicePort: 80
path: /push/(.*) /index/$1
- backend:
serviceName: flights
servicePort: 80
path: /flights/(.*) /$1
- backend:
serviceName: api
servicePort: 80
path: /api
- backend:
serviceName: grafana
servicePort: 80
path: /grafana/(.*) /$1
I will appreciate any help for solving this task

After several hours of unsuccessful attempts to solve my issue, I did it with Nginx ingress controller and it works great! Here's the ingress configuration:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite /push/(.*) /index/$1 break;
rewrite /flights/(.*) /$1 break;
rewrite /grafana/(.*) /$1 break;
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: pushinterface
servicePort: 80
path: /push
- backend:
serviceName: flights
servicePort: 80
path: /flights
- backend:
serviceName: api
servicePort: 80
path: /api
- backend:
serviceName: grafana
servicePort: 80
path: /grafana
Thanks to everyone for the answers! :)

Using ReplacePathRegex rule type in your example does not guarantee that incoming requests will be forwarded to the target backends, as mentioned in Traefik Documentation.
In order to route requests to the endpoints, use Matcher instead of Modifiers rules, as they are designed for that purpose.
Find a separate discussion on the similar issue here.

Related

Nginx 503 ingress controller k8s

I have an application running on nginx port 9000, and a service attached to it. If I put service as a LoadBalancer, I can open IP:PORT/app/pages in my browser (ClusterIP and NodePort with nginx doesn't work). Created Ingress controller with ALB, and A record to point to app.mydomain.com, but I keep getting 503 or 404 errors, even 400 sometimes (tried couple of ports/paths etc). Can someone point me to what should I look at? I want to be able to open https://app.mydomain.com/app/pages. cert-manager is complaining with 400 errors also when retrieving the certificate.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-app-dev
namespace: app-dev
annotations:
cert-manager.io/issuer: letsencrypt-nginx
ingress.kubernetes.io/rewrite-target: /
# ingressclass.kubernetes.io/is-default-class: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- app.mydomain.com
secretName: letsencrypt-nginx
rules:
- host: app.mydomain.com
http:
paths:
- pathType: Prefix
backend:
service:
name: app-service
port:
number: 8080
path: /
apiVersion: v1
kind: Service
metadata:
name: app-service
namespace: app-dev
spec:
type: LoadBalancer
ports:
- port: 9090
protocol: TCP
targetPort: 8080
selector:
app: app
IP of Ingress is added as a A record to DNS (app.mydomain.com). This is my nginx conf in the docker image
bash-5.1# cat /etc/nginx/conf.d/default.conf
server {
listen 8080 ssl;
ssl_certificate /ssl/cert;
ssl_certificate_key /ssl/key;
location / {
root /www;
autoindex off;
add_header 'Access-Control-Allow-Origin' '*';
}
location /healthz {
return 200 'ok';
}
}

kubernetes nginx ingress error with configuration-snippet

I have following ingress.yaml file
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/configuration-snippet: |
location /base/path/v1/api/update {
deny all;
return 404;
}
spec:
rules:
- http:
paths:
- path: /base/path(/|$)(.*)
backend:
serviceName: myApi
servicePort: 8080
But when I send a request to https:///base/path/v1/api/update it succeeds and I got following error in nginx ingress controller
Error: exit status 1
2020/08/06 18:35:07 [emerg] 1734#1734: location "/base/path/v1/api/update" is outside location "^/base/path(/|$)(.*)" in /tmp/nginx-cfg008325631:2445
nginx: [emerg] location "/base/path/v1/api/update" is outside location "^/base/path(/|$)(.*)" in /tmp/nginx-cfg008325631:2445
nginx: configuration file /tmp/nginx-cfg008325631 test failed
Can somebody help?
The configuration-snippet is to add configs to locations.
If you want to add a custom location to the server context, you should use the server-snippet instead:
Using the annotation nginx.ingress.kubernetes.io/server-snippet it is
possible to add custom configuration in the server configuration
block.
You also need to use some modifiers and regex to make it work (~* and ^).
The following config should work:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/server-snippet: |
location ~* "^/base/path/v1/api/update" {
deny all;
return 403;
}
spec:
rules:
- http:
paths:
- path: /base/path(/|$)(.*)
backend:
serviceName: myApi
servicePort: 8080
The final nginx.config should end like this:
$ kubectl exec -n kube-system nginx-ingress-controller-6fc5bcc8c9-chkxf -- cat /etc/nginx/nginx.conf
[...]
location ~* "^/base/path/v1/api/update" {
deny all;
return 403;
}
location ~* "^/base/path(/|$)(.*)" {
[...]
}

Rewrite with nginx-ingress controller

I am running celery flower on port inside Kubernetes with nginx-ingress controller
I want to do a rewrite where requests to /flower/(.*) request goes to /$1 according to their documentation:
https://flower.readthedocs.io/en/latest/config.html?highlight=nginx#url-prefix
server {
listen 80;
server_name example.com;
location /flower/ {
rewrite ^/flower/(.*)$ /$1 break;
proxy_pass http://example.com:5555;
proxy_set_header Host $host;
}
}
I have come up with the following ingress.yaml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: backend-airflow-ingress
namespace: edna
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/use-regex: "true"
ingress.kubernetes.io/rewrite-target: /$2
# nginx.ingress.kubernetes.io/app-root: /flower
spec:
rules:
- host:
http:
paths:
- path: /flower(/|$)(.*)
backend:
serviceName: airflow-flower-service
servicePort: 5555
Inside POD running flower, I successfully get
curl localhost:5555/dashboard
However if get into the POD running Nginx controller, then it fails.
curl localhost/flower/dashboard
I get response by the flower:
<div class="span12">
<p>
Error, page not found
</p>
</div>
this is what I see inside nginx.conf in nginx-controller pod
server {
server_name _ ;
listen 80 default_server reuseport backlog=511 ;
listen 443 default_server reuseport backlog=511 ssl http2 ;
set $proxy_upstream_name "-";
ssl_certificate_by_lua_block {
certificate.call()
}
location ~* "^/flower(/|$)(.*)" {
set $namespace "edna";
set $ingress_name "backend-airflow-ingress";
set $service_name "";
set $service_port "";
set $location_path "/flower(/|${literal_dollar})(.*)";
rewrite_by_lua_block {
lua_ingress.rewrite({
force_ssl_redirect = false,
ssl_redirect = true,
force_no_ssl_redirect = false,
use_port_in_redirects = false,
})
balancer.rewrite()
plugins.run()
}
# be careful with `access_by_lua_block` and `satisfy any` directives as satisfy any
# will always succeed when there's `access_by_lua_block` that does not have any lua code doing `ngx.exit(ngx.DECLINED)`
# other authentication method such as basic auth or external auth useless - all requests will be allowed.
#access_by_lua_block {
#}
header_filter_by_lua_block {
lua_ingress.header()
plugins.run()
}
body_filter_by_lua_block {
}
Ok figured this out
ingress.kubernetes.io/rewrite-target: /$2
should be in my case a different annotation
nginx.ingress.kubernetes.io/rewrite-target: /$2

Nginx ingress kubernetes Proxy Pass

I need configure a proxy pass in a nginx ingress.
The rule must be:
%USER%.test.domain.com to app.test.domain.com/%USER%
*It must be a proxy pass NOT a redirect
I created this Ingress but it does not work
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test02-ingress
annotations:
kubernetes.io/ingress.class: nginx
kubernetes.io/tls-acme: 'true'
nginx.ingress.kubernetes.io/rewrite-target: /
nginx.ingress.kubernetes.io/server-snippet: |
server_name ~^(?<subdomain>.+)\.test\.domain\.it;
location = / {
proxy_pass https://app.test.domain.it/$subdomain/;
proxy_set_header Host $subdomain.test.domain.it;
}
spec:
rules:
- host: "*.test.domain.it"
http:
paths:
- path: /
backend:
serviceName: test01-svc
servicePort: 80
``

NGINX Container Not Loading Static Files using Traefik / Kubernetes

I am running the Traefik Ingress Controller on Kubernetes (AKS). I've successfully deployed my Django application using the Traefik Ingress but it's not currently loading any static files (and therefore the styling isn't working).
Static files are served from a custom NGINX container with /static. So if my domain name is xyz.com, static is served from xyz.com/static.
apiVersion: v1
kind: Service
metadata:
name: nginxstaticservice
labels:
app: nginxstatic
spec:
selector:
k8s-app: traefik-ingress-lb
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
selector:
app: nginxstatic
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginxstatic-ingress
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefixStrip
# traefik.ingress.kubernetes.io/frontend-entry-points: http,https
spec:
rules:
- host: xyz.com
http:
paths:
- path: /static
backend:
serviceName: nginxstaticservice
servicePort: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginxstatic-deployment
labels:
app: nginxstatic
spec:
replicas: 1
selector:
matchLabels:
app: nginxstatic
template:
metadata:
labels:
app: nginxstatic
spec:
containers:
- name: nginxstatic
image: nginxstatic:latest
ports:
- containerPort: 80
imagePullSecrets:
This is the default.conf running on the NGINX container (this was previously working in a Website configuration.
server {
listen 80;
server_name _;
client_max_body_size 200M;
set $cache_uri $request_uri;
location = /favicon.ico { log_not_found off; access_log off; }
location = /robots.txt { log_not_found off; access_log off; }
ignore_invalid_headers on;
add_header Access-Control-Allow_Origin *;
location /static {
autoindex on;
alias /static;
}
location /media {
autoindex on;
alias /media;
}
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
}
Resolved in comments, PathPrefixStrip was used incorrectly which caused Nginx to see different paths than expected.

Resources