Multiple ingress controllers using same host - kubernetes

I have two ingress controllers (for public/internal traffic), what I would like is for all endpoints to use the public ingress except for /metrics, which should be internal, all using the same host.
E.g.
example.com/ -> public ingress
example.com/metrics -> internal ingress
This is what I have tried:
internal ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-metrics-ingress
annotations:
kubernetes.io/ingress.class: ingress-internal
spec:
rules:
- host: example.com
http:
paths:
- path: /metrics
backend:
serviceName: example-servicename
servicePort: 80
and public ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: example.com
http:
paths:
- path:
backend:
serviceName: example-servicename
servicePort: 80
The internal ingress is currently being ignored when I visit example.com/metrics (it uses the public one instead).
If I change the internal ingress to use the same ingress controller as the public one and change the service port to 81 (as an example), this provides an error (which is expected), this shows that the two different ingresses are being used. However, as soon as I use two different ingress controllers, then the one ingress' rules are not being picked up.
How can I configure my ingresses to achieve my desired result?

When running multiple ingress-nginx controllers, it will only process an unset class annotation if one of the controllers uses the default --ingress-class value (see IsValid method in internal/ingress/annotations/class/main.go), otherwise the class annotation become required.
If --ingress-class is set to the default value of nginx, the controller will monitor Ingresses with no class annotation and Ingresses with annotation class set to nginx. Use a non-default value for --ingress-class, to ensure that the controller only satisfied the specific class of Ingresses.
In your case use the combination of the annotation kubernetes.io/ingress.class: "EXTERNAL|INTERNAL" and the flag --ingress-class=EXTERNAL|INTERNAL allows you to filter which Ingress rules should be picked by the nginx ingress controller.
Take a look: multiple-ingress, ingress-nginx-traffic.

I have had an issue like that on AKS (K8s version 1.22.4). I have two Nginx Ingress Controllers, Internal and External.
Only one worked at a time, Internal or external.
After specifying a unique election-id for each one the problem was fixed.
The following post may help: https://stackoverflow.com/a/72591382/4049017

Related

How to point to a service in a different ns than the ingress

i am looking at creating an alb using https://github.com/kubernetes-sigs/aws-load-balancer-controller
Lets say i have two namespaces kubernetes-dashboard and otherns.
In the first namespace i have a service called kubernetes-dashboard and in the second namespace i have a service called otherservice
Would the below ingress work?
ingress.yml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: general-ingress
namespace: default
annotations:
kubernetes.io/ingress.class: alb
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/listen-ports: '[{"HTTP":80,"HTTPS": 443}]'
alb.ingress.kubernetes.io/certificate-arn: <redacted>
alb.ingress.kubernetes.io/tags: Environment=staging,Team=dev
alb.ingress.kubernetes.io/healthcheck-path: /health
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '300'
spec:
rules:
- host: k8s.acme.com
http:
paths:
- path: /*
backend:
serviceName: kubernetes-dashboard.kubernetes-dashboard
servicePort: 8080
- host: otherservice.acme.com
http:
paths:
- path: /*
backend:
serviceName: otherservice.otherns
servicePort: 80
I found there is two solutions to this problem.
The second solution did not work for me because i am using a library which does not support that. https://github.com/kubernetes-sigs/aws-load-balancer-controller
Create multiple ingress files delcaring the same group.name.
https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/ingress/annotations/#ingressgroup
IngressGroup feature enables you to group multiple Ingress resources
together. The controller will automatically merge Ingress rules for
all Ingresses within IngressGroup and support them with a single ALB.
In addition, most annotations defined on a Ingress only applies to the
paths defined by that Ingress.
Use an externalName service
https://kubernetes.io/docs/concepts/services-networking/service/#externalname
You can create an ExternalName service in the same namespace as your ingress, your ingress will then point to this special ExternalName service
Namespaces are security boundaries. An Ingress resource in a namespace cannot direct traffic to a service in a different namespace. If that would be possible, users could hijack traffic to services.
In the first namespace i have a service called kubernetes-dashboard and in the second namespace i have a service called otherservice
What you need to do in this case is to use two different Ingress-resources. You can still use the same Application Load Balancer.

How to allow multiple IPs only on ingress

I have number of IPs and I want only to allow those IP into my ingress
I know I can do this with in my ingress annotations,
nginx.ingress.kubernetes.io/whitelist-source-range: 10.0.0.0/16
But what I want is that I have multiple IPS and not only 10.0.0.0/16
So If for example I have IPs like 178.1.0.2/17,10.0.0.0/16,178.2.0.3/18 and I only want to allow this IPs to my ingress then how can I acheive that.
If you are using Nginx Ingress you can do it adding specific annotation whitelist-source-range.
nginx.ingress.kubernetes.io/whitelist-source-range
You can specify allowed client IP source ranges through the nginx.ingress.kubernetes.io/whitelist-source-range annotation. The value is a comma separated list of CIDRs, e.g. 10.0.0.0/24,172.10.0.1.
To configure this setting globally for all Ingress rules, the whitelist-source-range value may be set in the NGINX ConfigMap.
Also keep in mind that:
Adding an annotation to an Ingress rule overrides any global restriction.
Also if you would like to use Ingress Whitelist IP for Path you can check this thread.
Example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: frontend
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/whitelist-source-range: 10.0.0.0/16,178.2.0.3/18,178.1.0.2/17
spec:
rules:
- host: something.something.com
http:
paths:
- path: /app1
backend:
serviceName: app1
servicePort: 80
- path: /api
backend:
serviceName: api
servicePort: 8000
ingress.extensions/frontend created

How to implement multiple service in one ingress controller?one they gave in docs is not understandable

I created a service and each service is creating a new load balancer, I don't want to create a new load balancer for each service. For that, I found solution ingress controller but it's not happening.
I will try to describe the objects you need in just words.
You don't need to create a load balancer for each service. When you're using an ingress controller (like nginx), the ingress controller itself will be the type load balancer. All your other services need to be something like ClusterIP type.
Afterwards you can decide how to link your ClusterIP services with the Nginx LoadBalancer: create an ingress for each service or one ingress that exposes each service based on some rule (like paths as #harsh-manvar shows in the post above).
When you say "it's not happening", it would be good if you could provide details on your setup.
In order for Nginx ingress controller to work, it needs to be defined either as a NodePort or LoadBalancer service type. The examples provided in the nginx documentation are using LoadBalancer. However, LoadBalancer only works when your cluster supports this object (that means running in most cloud providers like AWS/GCP/Azure/DigitalOcean or newer versions of minikube). On the other hand, NodePort will expose the ingress controller on the Kubernetes node where it runs (when using minikube, that usually means a VM of sorts which then needs to be port forwarded to be accessible).
To use ingress in a local environment, you can look into minikube. All you need is to run minikube addons enable ingress and it will deploy an nginx controller for you. Afterwards, all you need to do is define an ingress and depending on your setup you may need to use kubectl port-forward to port forward port 80 on an nginx controller pod to a local port on your machine.
There are different types of services: ClusterIP, NodePort, LoadBalancer and ExternalName. You can specify it in spec.type. Actually the default one, when not specified is not LoadBalancer, but ClusterIP, so in your case, simply leave away the type: LoadBalancer definition and use your serviceName as backend in your ingress resource. Example:
spec:
rules:
- host: your.fully.qualified.host.name
http:
paths:
- backend:
serviceName: your-internal-service-name
servicePort: 80
path: /
Keep in mind that for some cloud providers there's also the possibility to use an internal LoadBalancer without a public IP. This is done by adding an annotation to the service configuration. For Azure AKS it looks like this:
metadata:
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
For Google's GKE the annotation is cloud.google.com/load-balancer-type: "Internal"
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: "nginx"
certmanager.k8s.io/cluster-issuer: wordpress-prod
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- test.test.com
secretName: prod
rules:
- host: test.test.com
http:
paths:
- path: /service-1
backend:
serviceName: service-1
servicePort: 80
- path: /service-2
backend:
serviceName: service-2
servicePort: 5000
Sharing here documentation for ingress to target multiple services you can redirect to multi-service.
Using this you can access services like
https://test.test.com/service-1
https://test.test.com/service-2
Following documentation you should do the following.
More information: kubernetes.github.com
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
For example, the ingress definition above will result in the following rewrites:
rewrite.bar.com/something rewrites to rewrite.bar.com/
rewrite.bar.com/something/ rewrites to rewrite.bar.com/
rewrite.bar.com/something/new rewrites to rewrite.bar.com/new

Add a custom header per rule on Kubernetes Ingress with Traefik

I'm moving to kubernetes using traefik as my Ingress Controller.
I have a single backend that should respond to 3000+ websites. Depending on the host, I need to add a custom header to the request before proxy passing it to the backend.
I can use the ingress.kubernetes.io/custom-request-headers annotation to add a custom header to the request but it's an annotation for the whole Ingress, so I would need to create 3000+ Ingresses, one for each website.
Is there another way to do this? Creating 3000+ Ingresses is the same thing as creating one Ingress with 3000+ rules?
Yes, you need to create one Ingress object per one host, if you want different headers her host.
You can do it by Traefik:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: traeffic-custom-request-header
annotations:
ingress.kubernetes.io/custom-request-headers: "mycustomheader: myheadervalue"
spec:
rules:
- host: custom.configuration.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
Also, the same thing you can do by Nginx Ingress Controller.
It has the support for configuration snipper. Here is an example of using it to set a custom header per Ingress object:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-configuration-snippet
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Request-Id: $request_id";
spec:
rules:
- host: custom.configuration.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /
BTW, you can use several different ingress controllers on your cluster, so it does not need to migrate everything to only one type of Ingress.

Rewrite all request targets in istio ingress controller

In the process of testing out Istio I'm in need of rewriting all incomming requests on the Istio ingress controller in the same manner as with Kubernetes's own ingress controller, where I use the rewrite-target annotation.
# Existing Kubernetes ingress configuration
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: api
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: some.host.com
http:
paths:
- path: /svc
backend:
serviceName: svc
servicePort: 80
This makes all requests, e.g. http://some.host.com/svc/endpoint hit the service with /endpoint instead of /svc/endpoint
How can I effectively do the same with Istio's ingress controller?
The Route rules object can handle rewrites, but is only available as a per destination manner, i.e. I have to create a route rule for every service.
You are right. You need a route rule per service to do setup the rewrite targets. See https://istio.io/docs/reference/config/traffic-rules/routing-rules.html#httprewrite for an example.