How to strip the path prefix in Kubernetes Traefik ingress? - kubernetes

I'm using k3s v1.22.7 on Ubuntu 20.04. I want /bar/xyz to be /xyz to the pods. Without the middleware I'm properly routed to the pods, with it I get 404 from Traefik as though the stripping from replacePathRegex/stripPrefix happens before the Ingress path evaluation. Examples online all have it like that though...
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: strip-prefix
spec:
#replacePathRegex:
# regex: ^/(?:[^/]+)/(.*)
# replacement: /$1
stripPrefix:
prefixes:
- /bar
- /baz
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: foo-ingress
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.middlewares: strip-prefix#kubernetescrd
spec:
rules:
- host: example.org
http:
paths:
- path: /bar
pathType: Prefix
backend:
service:
name: foo-service
port:
number: 5001
- path: /baz
pathType: Prefix
backend:
service:
name: foo-service
port:
number: 5002

Looks like the middleware needs the namespace prefixed, so either
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: strip-prefix
# No namespace defined
spec:
stripPrefixRegex:
regex:
- ^/[^/]+
---
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/router.middlewares: default-strip-prefix#kubernetescrd
or
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: strip-prefix
namespace: example # Namespace defined
spec:
stripPrefixRegex:
regex:
- ^/[^/]+
---
kind: Ingress
metadata:
annotations:
traefik.ingress.kubernetes.io/router.middlewares: example-strip-prefix#kubernetescrd
should work.
(Source)

Related

traefik ingress StripPrefix

Using traefik as the ingress controller and looking for a way to stripping path prefixing. as these prefixed path section is "forwarded" to the service unless the service is also listening on a same path, the service will hit a 404. it was not very clear on the docs how to remove the forwarded paths, any pointers?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: azure-vote-route
namespace: azure-vote
spec:
rules:
- host: <>.<>.cloudapp.azure.com
http:
paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: azure-vote-front
# port:
# number: 80
- path: /foo
pathType: Prefix
backend:
service:
name: azure-vote-front
port:
number: 80
found the answers
option 1
kind: Ingress
and using a Middleware from traefik to strip the prefix. and this middleware is refereed using an annotation on the Ingress definition
<namespace-of-middlewear>-<name-of-middlewear>
eg
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: ingress-stripprefix
namespace: azure-vote
spec:
stripPrefix:
prefixes:
- /foo
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-a
namespace: azure-vote
annotations:
traefik.ingress.kubernetes.io/router.middlewares: azure-vote-ingress-stripprefix#kubernetescrd
spec:
rules:
- host: <>.<>.cloudapp.azure.com
http:
paths:
- path: /foo
pathType: Prefix
backend:
service:
name: azure-vote-front
port:
number: 80
option 2
kind: IngressRoute (which is a traefik specific ingress implementation.)
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: ingressroute-middle
namespace: azure-vote
spec:
entryPoints:
- web
routes:
- match: Host(`<>.cloudapp.azure.com`) && PathPrefix(`/test`)
kind: Rule
services:
- name: azure-vote-front
port: 80
middlewares:
- name: testmiddle
- match: Host(`<>.cloudapp.azure.com`)
kind: Rule
services:
- name: azure-vote-front
port: 80
middlewares:
- name: testmiddle
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: testmiddle
namespace: azure-vote
spec:
stripPrefix:
prefixes:
- /test

PathPrefixStrip is ignored on ingress

Traefik version 2.5.6
I have the following ingress settings:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/app-root: /users
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
name: users
spec:
rules:
- host: dev.[REDUCTED]
http:
paths:
- backend:
service:
name: users-service
port:
number: 80
path: /users
pathType: Prefix
But when I call:
curl -i http://dev.[REDUCTED]/users/THIS-SHOUD-BE-ROOT
I get in the pod, serving the service:
error: GET /users/THIS-SHOUD-BE-ROOT 404
What can be the reason for that?
Try to use Traefik Routers as in the example below:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: users
namespace: default
spec:
entryPoints:
- web
routes:
- match: Host(`dev.[REDUCTED]`) && PathPrefix(`/users`)
kind: Rule
services:
- name: users-service
port: 80

How do I get traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip to work?

I have the following kubernetes manifest
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: traefik-external
traefik.ingress.kubernetes.io/router.entrypoints: websecure, web
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
name: ingressname
namespace: thenamespace
spec:
rules:
- host: my.host
http:
paths:
- backend:
serviceName: theservice
servicePort: 8080
path: /api
Havin an service, theservice, that listens to / I would expect the url my.host/api/something/anotherthing match to /something/anotherthing in theservice. That doesn't happen for me though, I get a 404 back.
Any ideas what might be wrong?
During the transition from v1 to v2, a number of internal pieces and components of Traefik were rewritten and reorganized. As such, the combination of core notions such as frontends and backends has been replaced with the combination of routers, services, and middlewares.
With v2 transforming the URL path prefix of incoming requests is configured with middlewares object, after the routing step with router rule PathPrefix.
With v1 it is defined at ingress level:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: traefik
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/rule-type: PathPrefixStrip
spec:
rules:
- host: company.org
http:
paths:
- path: /admin
backend:
serviceName: admin-svc
servicePort: admin
With v2 you have define also middleware object alongside ingress-route:
apiVersion: traefik.containo.us/v1alpha1
kind: IngressRoute
metadata:
name: http-redirect-ingressroute
namespace: admin-web
spec:
entryPoints:
- web
routes:
- match: Host(`company.org`) && PathPrefix(`/admin`)
kind: Rule
services:
- name: admin-svc
port: admin
middlewares:
- name: admin-stripprefix
---
apiVersion: traefik.containo.us/v1alpha1
kind: Middleware
metadata:
name: admin-stripprefix
spec:
stripPrefix:
prefixes:
- /admin
More information can be found here:
Frontends and Backends Are Dead...
... Long Live Routers, Middlewares, and Services

Kubernetes Ingress to External Service?

Say I have a service that isn't hosted on Kubernetes. I also have an ingress controller and cert-manager set up on my kubernetes cluster.
Because it's so much simpler and easy to use kubernetes ingress to control access to services, I wanted to have a kubernetes ingress that points to a non-kubernetes service.
For example, I have a service that's hosted at https://10.0.40.1:5678 (ssl required, but self signed certificate) and want to access at service.example.com.
You can do it by manual creation of Service and Endpoint objects for your external server.
Objects will looks like that:
apiVersion: v1
kind: Service
metadata:
name: external-ip
spec:
ports:
- name: app
port: 80
protocol: TCP
targetPort: 5678
clusterIP: None
type: ClusterIP
---
apiVersion: v1
kind: Endpoints
metadata:
name: external-ip
subsets:
- addresses:
- ip: 10.0.40.1
ports:
- name: app
port: 5678
protocol: TCP
Then, you can create an Ingress object which will point to Service external-ip with port 80:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: external-service
spec:
rules:
- host: service.example.com
http:
paths:
- backend:
serviceName: external-ip
servicePort: 80
path: /
So I got this working using ingress-nginx to proxy an managed external service over a non-standard port
apiVersion: v1
kind: Service
metadata:
name: external-service-expose
namespace: default
spec:
type: ExternalName
externalName: <external-service> # eg example.example.com
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: external-service-expose
namespace: default
annotations:
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" #important
spec:
rules:
- host: <some-host-on-your-side> # eg external-service.yourdomain.com
http:
- path: /
pathType: Prefix
backend:
service:
name: external-service
port:
number: <port of external service> # eg 4589
tls:
- hosts:
- external-service.yourdomain.com
secretName: <tls secret for your domain>
of-course you need to make sure that the managed url is reachable from inside the cluster, a simple check can be done by launching a debug pod and doing
curl -v https://example.example.com:4589
If your external service has a dns entry configured on it, you can use kubernetes externalName service.
---
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: myexternal.http.service.com
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: externalNameservice
namespace: prod
spec:
rules:
- host: service.example.com
http:
paths:
- backend:
serviceName: my-service
servicePort: 80
path: /
In this way, kubernetes create cname record my-service pointing to myexternal.http.service.com
I just want to update #Moulick answer here according to Kubernetes version v1.21.1, as for ingress the configuration has changed a little bit.
In my example I am using Let's Encrypt for my nginx controller:
apiVersion: v1
kind: Service
metadata:
name: external-service
namespace: default
spec:
type: ExternalName
externalName: <some-host-on-your-side> eg managed.yourdomain.com
ports:
- port: <port of external service> eg 4589
---
kind: Ingress
apiVersion: networking.k8s.io/v1
metadata:
name: external-service
namespace: default
annotations:
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/proxy-body-size: 100m
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS" #important
spec:
tls:
- hosts:
- <some-host-on-your-side> eg managed.yourdomain.com
secretName: tls-external-service
rules:
- host: <some-host-on-your-side> eg managed.yourdomain.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: external-service
port:
number: <port of external service> eg 4589

Forward to ExternalName with traefik in kubernetes as the documenation suggests

Following the Official Guide I got to the section onForwarding to ExtternalNames. Where it says:
When specifying an ExternalName, Træfik will forward requests to the given host accordingly
which points to the docs from kubernetes services without selectors
Which led me to create a service
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
externalName: my.database.example.com
Of which Traefik happily ignores when I point to it:
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-service
namespace: kube-system
spec:
rules:
- host: my-service.example.com
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 4080
I have also tried as an endpoint.
---
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: kube-system
spec:
ports:
- protocol: TCP
port: 80
targetPort: 4080
---
kind: Endpoints
apiVersion: v1
metadata:
name: my-service
subsets:
- addresses:
- ip: 10.0.0.3
ports:
- port: 4080
Does anyone know how to get traefik to point to an externalname as the documentation suggests?
As I see, you missed at least one line in your Ingress object - traefik.frontend.passHostHeader: "false".
Also, you need to create an Ingress object in a same Namespace with your Service.
So, your Ingress should be like:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-service
namespace: prod
annotations:
traefik.frontend.passHostHeader: "false"
spec:
rules:
- host: my-service.example.com
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 4080
And service:
kind: Service
apiVersion: v1
metadata:
name: my-service
namespace: prod
spec:
type: ExternalName
ports:
- name: app-port
port: 4080
externalName: my.database.example.com