kubernetes ingress server-alias only applies to one ingress host - nginx

According to this doc (https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#server-alias), I'm able to add additional server_name to the nginx config file.
However, it adds the extra server_name to all of my hosts, which cause conflicts for sure.
Is there a way to add server-alias only for one of my hosts? Say I only want to add 10.10.0.100 to my test1 host.
Ingress example:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: test-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/server-alias: 10.10.0.100
spec:
rules:
- host: test1.com
http:
paths:
- path: /
backend:
service:
name: test1-service
port:
number: 8000
pathType: Prefix
- host: test2.com
http:
paths:
- path: /
backend:
service:
name: test2-service
port:
number: 8000
pathType: Prefix

TL;DR
You can split your Ingress resource on multiple objects (which will work together) to add Annotations to only specific hosts.
Annotations can only be set on the whole kubernetes resource, as they are part of the resource metadata. The ingress spec doesn't include that functionality at a lower level.
-- Stackoverflow.com: Questions: Apply nginx-ingress annotations at path level
Extending on the answer to give an example of how such setup could be created. Let's assume (example):
All required domains pointing to the Service of type LoadBalancer of nginx-ingress-controller:
hello.kubernetes.docker.internal - used in host .spec
hello-two.kubernetes.docker.internal - used in annotations .metadata
--
goodbye.kubernetes.docker.internal - used in host .spec
goodbye-two.kubernetes.docker.internal- used in annotations .metadata
Skipping the Deployment and Service definitions, the Ingress resources should look like below:
hello-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "hello-two.kubernetes.docker.internal"
spec:
rules:
- host: hello.kubernetes.docker.internal # <-- IMPORTANT
http:
paths:
- path: /
backend:
service:
name: hello-service
port:
number: 80
pathType: Prefix
goodbye-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: goodbye-ingress
annotations:
nginx.ingress.kubernetes.io/server-alias: "goodbye-two.kubernetes.docker.internal"
spec:
rules:
- host: goodbye.kubernetes.docker.internal # <-- IMPORTANT
http:
paths:
- path: /
backend:
service:
name: goodbye-service
port:
number: 80
pathType: Prefix
Above definitions will create 2 Ingress resources that will be merged:
hello-service will respond for:
hello.kubernetes.docker.internal
hello-two.kubernetes.docker.internal
goodbye-service will respond for:
goodbye.kubernetes.docker.internal
goodbye-two.kubernetes.docker.internal
Running:
$ kubectl get ingress:
NAME CLASS HOSTS ADDRESS PORTS AGE
goodbye-ingress <none> goodbye.kubernetes.docker.internal localhost 80 36m
hello-ingress <none> hello.kubernetes.docker.internal localhost 80 36m
Additional resources:
Kubernetes.io: Docs: Concepts: Services networking: Ingress
Kubernetes.github.io: Ingress NGINX: Annotations: Server alias

Related

Kubernetes ingress nginx route to same path (different service; different port)

I have some simple deployments, pods, services and nginx ingress in Kubernetes. I want to use ingress to route to the services (cluster-ip).
However, there are 2 services for 2 pods with the same path (i.e /abc/def). After I applied the ingress.yaml file, I got an error message saying "nginx: [emerg] duplicate location "/abc/def/" in /tmp/nginx/nginx-cfg728288520:2893".
May I know how to let ingress accepts the same paths with different service and different port?
Here is the ingress.yaml file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
name: ingress-nginx-default
namespace: default
spec:
rules:
- host:
http:
paths:
- path: /abc/def/
pathType: Prefix
backend:
service:
name: service1
port:
number: 8090
- path: /abc/def
backend:
service:
name: service2
port:
number: 8068
pathType: Prefix
ingressClassName: nginx
"nginx: [emerg] duplicate location "/abc/def/" in /tmp/nginx/nginx-cfg728288520:2893". This error indicates the same host with two same paths which is a duplicate location.
You can use simple fanout based on path or name based virtual hosting.
In order to do this you need to have two hosts that need to be mentioned in the ingress.
based on your example you'd most likely want to have something like foo.bar.com and bar.foo.com. Here's the example from the Kubernetes docs:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: name-virtual-host-ingress
spec:
rules:
- host: foo.bar.com
http:
paths: #path_name
- backend:
serviceName: service1
servicePort: 80
- host: bar.foo.com
http:
paths: #path_name
- backend:
serviceName: service2
servicePort: 80

Ingress rewrite to two different services from one DNS

I am trying to reach out to two services from my DNS.
Example:- myportal.com
myportal.com/app1
I have my SSO and SSL implementation on "myportal.com" and on the home page I have a button which calls a service "myportal.com/app1". I have tried multiple things but I am not able to configure both properly.
From below ingress config I am able to redirect to "myportal.com/app1" but its not working properly for "myportal.com". I have tried multiple thing including default backend and its not working for me. When I use default backend then "myportal.com" works but it stops redirecting to /app1.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myportal-ingress-test
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
rules:
- host: myportal.com
http:
paths:
- pathType: Prefix
path: /
backend:
service:
name: portal-service
port:
number: 8097
- pathType: Prefix
path: /app1(/|$)(.*)
backend:
service:
name: app-ui-service
port:
number: 8087
I am fairly new to kubernetes and I am not sure if it's the correct way to implement such things. I am open to new implementation too if it's using ingress and routing to different services using same dns on different path.
Thanks in advance for the help!
I was able to resolve this issue. The redirect in an ingress file would work for all the paths, so I created a separate ingress for each path with individual redirects.
Ingress 1 - myportal.com (with SSO and SSL)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gcpportal-service-test
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/x-forwarded-prefix: /myportal-service
nginx.ingress.kubernetes.io/ssl-redirect: 'true'
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
defaultBackend:
service:
name: myportal-service
port:
number: 80
rules:
- host: myportal.com
Ingress 2 - myportal.com/app1 (application deployed)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: gcpportal-service-test-1
namespace: appspace
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- myportal.com
secretName: secret
rules:
- host: myportal.com
- pathType: Prefix
path: /app1(/|$)(.*)
backend:
service:
name: app1-ui-service
port:
number: 8087
This helped me to resolve this issue. I also verified that this way is also a standard way and is provided in one of the documentation of nginx.
https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/

Handle overlapping ingress paths

I have one ingress which handles all requests to my-domain.example.com/api and forwards them to backend-service/api:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: default-backend
spec:
ingressClassName: nginx
rules:
- host: my-domain.example.com
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 8080
Now I added this second ingress, which should only handle the sub-path my-domain.example.com/api/log and forward it to logger-service/api:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: logger
annotations:
ingress.kubernetes.io/rewrite-target: /log/$2
spec:
ingressClassName: nginx
rules:
- host: my-domain.example.com
http:
paths:
- path: /api/log(/|$)(.*)
pathType: Prefix
backend:
service:
name: logger-service
port:
number: 8080
But this doesn't work reliable. The log of the ingress controller tells me, that the request to my-domain.example.com/api/log was forwarded to the backend-service. I guess the overlapping paths make it unpredictable.
How do I have to configure my ingresses if I have one service which should handle all defaults (/api/) and some other services which should handle specific sub-paths (/api/log)?
Each path in an Ingress is required to have a corresponding path type. Paths that do not include an explicit pathType will fail validation.
The only supported wildcard character for the path field of an Ingress is the * character. The * character must follow a forward slash (/) and must be the last character in the pattern. For example, /, /foo/, and /foo/bar/* are valid patterns, but , /foo/bar, and /foo//bar are not.A more specific pattern takes precedence over a less specific pattern. If you have both /foo/ and /foo/bar/, then /foo/bar/bat is taken to match /foo/bar/.For more information about path limitations and pattern matching, see the URL Maps documentation.
Suggestion : For second ingress try by mentioning the path as /api/log .*
As shown below
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /
name: logger
spec:
ingressClassName: nginx
rules:
-
host: my-domain.example.com
http:
paths:
-
backend:
service:
name: logger-service
port:
number: 8080
path: /api/log*
pathType: Prefix
Above YAML is working, find below Screenshot :
Additional reference doc :
Link1
Link2

NGINX Ingress Routing based on Header

I have an nginx-ingress calling a custom auth-service before sending requests to the backend service, using this simple ConfigMap and Ingress:
apiVersion: v1
kind: ConfigMap
metadata:
...
data:
global-auth-url: auth-service-url:8080/authenticate
global-auth-method: GET
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
...
spec:
rules:
- host: host1
http:
paths:
- backend:
serviceName: backend-service
servicePort: 8080
Now I need something different.
How can I send requests, all with the same "Host" header, through different flows, one with auth-service and connected to backend-service1 and the other without any authentication and connecting to backend-service2?
To be clear, and using the custom header "Example-header: test"
If "Example-header" is "test", authenticate via my auth-service before sending to backend-service, as it's done now.
If "Example-header" is not defined, I want to send requests to a different backend service and do not use auth-service in the process.
I tried a couple of things, namely having 2 Ingresses, one with global-auth-url and the other with nginx.ingress.kubernetes.io/enable-global-auth: "false" but the auth-service is always called.
Can I do this with NGINX, or do I have to use Istio or Ambassador?
One way you can achieve this behavior is by abusing the canary feature.
For your backend-service, create a normal Ingress, e. g.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-backend
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: backend-service
port:
number: 80
Create a second Ingress for you auth-service with enabled canary and set the header name and value, e. g.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-auth
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-by-header: Example-header
nginx.ingress.kubernetes.io/canary-by-header-value: test
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: auth-service
port:
number: 80
Now, every request with Example-header: test routes to auth-service. Any other value, e. g. Example-header: some-value, will not route to auth-service but rather go to your backend-service.

Enable rewrite for a particular host in ingress nginx configuration

I have below ingress-nginx configuration file.
It rewrites request for one.example.com. I have added another domain, but I don't want rewrite to happen for other domain.
I went through doc, but there is now rewrite example for multiple host setup.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$1
certmanager.k8s.io/cluster-issuer: "letsencrypt-example-prod"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
tls:
- hosts:
- one.example.com
- two.example.com
secretName: super-secret
rules:
- host: one.example.com
http:
paths:
- path: /customer/?(.*)
pathType: Prefix
backend:
service:
name: customer-srv
port:
number: 3000
host: two.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kube-prometheus-grafana
port:
number: 80
I could create two separate ingress files for each host.
What will happen in that case it will create two load balancers with different dns?
(cluster is hosted on aws)
You can create two separate ingress.
In that case, nothing will change your ingress controller IP would be same only for DNS.
What will happen in that case it will create two load balancers with
different dns?
No, it won't create two load balancers.

Resources