英文:
kubernetes ingress-nginx ignore special characters in path
问题
I'm trying to have a rule listening to a specific path containing a dollar sign like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: metadata-ingress
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-regex: "false"
spec:
ingressClassName: public
tls:
- hosts:
- mydomain.com
rules:
- host: mydomain.com
http:
paths:
- path: /api/v2/$metadata
pathType: Prefix
backend:
service:
name: busybox
port:
number: 8280
I don't want any url rewrite or anything fancy, just want this specific path to be caught and forwarded to this service.
Without the "$" it works.
I thought disabling regex with use-regex: "false"
would fix it, but no.
I also tried using the url encoded value for $ : %24metadata but it doesn't help either.
I also tried to use "exact" instead of "prefix" as the pathType but no.
英文:
I'm trying to have a rule listening to a specific path containing a dollar sign like this:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: metadata-ingress
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/use-regex: "false"
spec:
ingressClassName: public
tls:
- hosts:
- mydomain.com
rules:
- host: mydomain.com
http:
paths:
- path: /api/v2/$metadata
pathType: Prefix
backend:
service:
name: busybox
port:
number: 8280
I don't want any url rewrite or anything fancy, just want this specific path to be caught and forwarded to this service.
Without the "$" it works.
I thought disabling regex with use-regex: "false"
would fix it, but no.
I also tried using the url encoded value for $ : %24metadata but it doesn't help either.
I also tried to use "exact" instead of "prefix" as the pathType but no.
答案1
得分: 1
I can't reproduce your problem, but I thought I walk through my test setup and you can tell me if anything is different. For the purpose of testing different paths, I have two deployments using the traefik/whoami
image (this just provides a useful endpoint that shows us -- among other things -- the hostname and path involved in the request).
That looks like:
apiVersion: v1
kind: Service
metadata:
labels:
app: example
component: app1
name: example-app1
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: example
component: app1
---
apiVersion: v1
kind: Service
metadata:
labels:
app: example
component: app2
name: example-app2
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: example
component: app2
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: example
component: app1
name: example-app1
spec:
selector:
matchLabels:
app: example
component: app1
template:
metadata:
labels:
app: example
component: app1
spec:
containers:
- image: docker.io/traefik/whoami:latest
name: whoami
ports:
- containerPort: 80
name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: example
component: app2
name: example-app2
spec:
selector:
matchLabels:
app: example
component: app2
template:
metadata:
labels:
app: example
component: app2
spec:
containers:
- image: docker.io/traefik/whoami:latest
name: whoami
ports:
- containerPort: 80
name: http
I've also deployed the following Ingress resource, which looks mostly like yours, except I've added a second paths
config so that we can compare requests that match /api/v2/$metadata
vs those that do not:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: house
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: example
spec:
ingressClassName: nginx
rules:
- host: example.apps.infra.house
http:
paths:
- backend:
service:
name: example-app1
port:
name: http
path: /
pathType: Prefix
- backend:
service:
name: example-app2
port:
name: http
path: /api/v2/$metadata
pathType: Prefix
tls:
- hosts:
- example.apps.infra.house
secretName: example-cert
With these resources in place, a request to https://example.apps.infra.house/
goes to app1
:
$ curl -s https://example.apps.infra.house/ | grep Hostname
Hostname: example-app1-596fcf48bd-dqhvc
Whereas a request to https://example.apps.infra.house/api/v2/$metadata
goes to app2
:
$ curl -s https://example.apps.infra.house/api/v2/\$metadata | grep Hostname
Hostname: example-app2-8675dc9b45-6hg7l
So that all seems to work.
We can, if we are so inclined, examine the nginx configuration that results from that Ingress. On my system, the nginx ingress controller runs in the nginx-ingress
namespace:
$ kubectl -n nginx-ingress get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 8d
The configuration lives in /etc/nginx/nginx.conf
in the container. We can cat
the file to stdout and look for the relevant directives:
$ kubectl -n nginx-ingress exec deploy/ingress-nginx-controller cat /etc/nginx/nginx.conf
...
location /api/v2/$metadata/ {
...
}
...
Based on your comment, the following seems to work:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: "/$2"
cert-manager.io/cluster-issuer: house
spec:
ingressClassName: nginx
tls:
- hosts:
- example.apps.infra.house
secretName: example-cert
rules:
- host: example.apps.infra.house
http:
paths:
- path: /app1(/|$)(.*)
pathType: Prefix
backend:
service:
name: example-app1
port:
name: http
# Note the use of single quotes (') here; this is
# important; using double quotes we would need to
# write `\\$` instead of `\$`.
- path: '/api/v2/\$metadata'
pathType: Prefix
backend:
service:
name: example-app2
port:
name: http
The resulting location
directives look like:
location ~* "^/api/v2/\$metadata" {
...
}
location ~* "^/app1(/|$)(.*)" {
...
}
And a request for the $metadata
path succeeds.
英文:
I can't reproduce your problem, but I thought I walk through my test setup and you can tell me if anything is different. For the purpose of testing different paths, I have two deployments using the traefik/whoami
image (this just provides a useful endpoint that shows us -- among other things -- the hostname and path involved in the request).
That looks like:
apiVersion: v1
kind: Service
metadata:
labels:
app: example
component: app1
name: example-app1
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: example
component: app1
---
apiVersion: v1
kind: Service
metadata:
labels:
app: example
component: app2
name: example-app2
spec:
ports:
- name: http
port: 80
targetPort: http
selector:
app: example
component: app2
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: example
component: app1
name: example-app1
spec:
selector:
matchLabels:
app: example
component: app1
template:
metadata:
labels:
app: example
component: app1
spec:
containers:
- image: docker.io/traefik/whoami:latest
name: whoami
ports:
- containerPort: 80
name: http
---
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: example
component: app2
name: example-app2
spec:
selector:
matchLabels:
app: example
component: app2
template:
metadata:
labels:
app: example
component: app2
spec:
containers:
- image: docker.io/traefik/whoami:latest
name: whoami
ports:
- containerPort: 80
name: http
I've also deployed the following Ingress resource, which looks mostly like yours, except I've added a second paths
config so that we can compare requests that match /api/v2/$metadata
vs those that do not:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
cert-manager.io/cluster-issuer: house
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
name: example
spec:
ingressClassName: nginx
rules:
- host: example.apps.infra.house
http:
paths:
- backend:
service:
name: example-app1
port:
name: http
path: /
pathType: Prefix
- backend:
service:
name: example-app2
port:
name: http
path: /api/v2/$metadata
pathType: Prefix
tls:
- hosts:
- example.apps.infra.house
secretName: example-cert
With these resources in place, a request to https://example.apps.infra.house/
goes to app1
:
$ curl -s https://example.apps.infra.house/ | grep Hostname
Hostname: example-app1-596fcf48bd-dqhvc
Whereas a request to https://example.apps.infra.house/api/v2/$metadata
goes to app2
:
$ curl -s https://example.apps.infra.house/api/v2/\$metadata | grep Hostname
Hostname: example-app2-8675dc9b45-6hg7l
So that all seems to work.
We can, if we are so inclined, examine the nginx configuration that results from that Ingress. On my system, the nginx ingress controller runs in the nginx-ingress
namespace:
$ kubectl -n nginx-ingress get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
ingress-nginx-controller 1/1 1 1 8d
The configuration lives in /etc/nginx/nginx.conf
in the container. We can cat
the file to stdout and look for the relevant directives:
$ kubectl -n nginx-ingress exec deploy/ingress-nginx-controller cat /etc/nginx/nginx.conf
...
location /api/v2/$metadata/ {
...
}
...
Based on your comment, the following seems to work:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: example
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/rewrite-target: "/$2"
cert-manager.io/cluster-issuer: house
spec:
ingressClassName: nginx
tls:
- hosts:
- example.apps.infra.house
secretName: example-cert
rules:
- host: example.apps.infra.house
http:
paths:
- path: /app1(/|$)(.*)
pathType: Prefix
backend:
service:
name: example-app1
port:
name: http
# Note the use of single quotes (') here; this is
# important; using double quotes we would need to
# write `\\$` instead of `\$`.
- path: '/api/v2/\$metadata'
pathType: Prefix
backend:
service:
name: example-app2
port:
name: http
The resulting location
directives look like:
location ~* "^/api/v2/\$metadata" {
...
}
location ~* "^/app1(/|$)(.*)" {
...
}
And a request for the $metadata
path succeeds.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论