Kubernetes - How ingress routing works - kubernetes

I saw some example where the Kubernetes cluster is installed with ingress controller and then the ingress class is added with annotations and host as below.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- host: testsvc.k8s.privatecloud.com
http:
I am not sure which service is installed and which IP is configured with the DNS "k8s.privatecloud.com" so as to route requests?
How the DNS routing "k8s.privatecloud.com" routes requests to Kubernetes cluster? How the ingress to kubernetes bridging works?
Also, There could be many services configured with the hosts rule like,
testsvc.k8s.privatecloud.com
testsvc1.k8s.privatecloud.com
testsvc2.k8s.privatecloud.com
How the subdomain routing works here when we hit the service testsvc.k8s.privatecloud.com or testsvc1.k8s.privatecloud.com ...
Thanks

The DNS for all the hostnames in your given example (e.g. testsvc.k8s.privatecloud.com) would point to the machine or load-balancer through which traffic will reach the Ingress controller's nginx, as is described in the kuberetes Ingress documentation
Subdomain routing is traditionally done via "virtual-hosting", sometimes called "v-host-ing", and the nginx ingress uses the HTTP Host: header to know which backend service should receive that traffic. Some Ingress controllers are able to use SNI for that same trick over https.

In addition to #Matthew L Daniel answer.
The kubernetes Ingress works as a proxy between external network and your cluster. The behavior of the ingress is explained in the object ingress. For example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: foo.bar.com
http:
paths:
- path: /foo
backend:
serviceName: s1
servicePort: 80
- path: /bar
backend:
serviceName: s2
servicePort: 80
Above it`s explained how to route traffic between 2 backends s1 and s2. Ingress does not hold any information about services except its name and port, every time it needs more details it would need to be requested from the api-server.

Related

How add define a rule in ingress resource to route a request from specific domain to specific service in Kubernetes?

I was reading about ingress controller and ingress resource to route the incoming request to Kubernetes cluster to specific service.
Ingress resource file will be similar to:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-myservicea
spec:
rules:
- host: myservicea.foo.org
http:
paths:
- path: /v1/myapp/health
pathType: Prefix
backend:
service:
name: myservice
port:
number: 80
ingressClassName: nginx
My understanding from above ingress is, all incoming request(url like: https://myservicea.foo.org/v1/myapp/health) to ingress controller will be redirected to the service "myservice" on port 80. No matter request is coming from which domain(app, client, host, IP or localhost).
Here my question is, How can we add rules in ingress resource to specify, request coming from specific domain(app, client, host or IP) will be routed to specific service("myservice") based on path. If it is coming from any other domain, request will be simply discarded.
What example you have shared above is host-based routing. Where you have a different Host or Domain and based on traffic gets forwarded to service. example.com
you can also do the path-based routing with an ingress controller where regex might be used. /v1/myapp
Ingress controller if you are using the nginx you won't be able to route based on IP address. You can whitelist the IPs addresses, only certain IP can access the Ingress else will be blocked but based on IP you can not forward request to service.
However there is always way around so if you are already have Nginx config you can also do same in ingress also.
You have to try and test a few blocks based on that you might be able to achieve what you are looking for.
You can leverage the server-snippet or configuration-snippet to create the blocks.
For example if /preview 302 redirect it
annotations:
nginx.ingress.kubernetes.io/configuration-snippet: |
rewrite /preview https://test.app.example.com$uri permanent;
Another example based on server_name same you can check for header values and based on that you can do routing.
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/server-snippet: |
server_name ~^(?<subdomain>\w+)\.example\.io$;
nginx.ingress.kubernetes.io/rewrite-target: /proxy/$subdomain/$1
name: nginx-forward
spec:
rules:
- http:
paths:
- backend:
service:
name: service
port:
number: 8080
path: /(.*)
pathType: Prefix
Considering here nginx ingress controller here you can setup different CRDs also from the opensource project or install plugins if using Kongs baed on the requirement.
Read more server-snippet : https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#server-snippet
Read more configuration-snippet : https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md#configuration-snippet

Kubernetes Ingress and Service object

I have a deployment which is WEB API. I apply it to Kubernetes. Then add service.yml file to expose it. It is working. I have 12 microservices. All of them have service and deployment .yaml files.
So what is Ingress controller. Why should I use it?
(Except sidecar proxy like istio. Its perfect for resilince and metrics.)
In order for the Ingress resource to work, the cluster must have an ingress controller running. The controller can be for example Nginx Ingress Controller and it can be adjusted in various ways. After you have deployed the controller, all you need is an Ingress resource object deployed in K8s.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-sample
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: web-api
port:
number: 80
service.name: web-api is the place where you specify link between the ingress and the service.

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

IP whitelisting in google container engine with ingress not working

I am trying to whitelist IPs that can access my application. I created http-balancer by following this tutorial. https://cloud.google.com/kubernetes-engine/docs/tutorials/http-balancer
After creating the service with NodePort I created an ingress.yaml file that looks like the one below. I have created a global static ip and setup a domain name.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: <global-static-ip>
spec:
rules:
- host: <domain_name>
- http:
paths:
- path: /*
backend:
serviceName: nginx
servicePort: 80
This above yaml file works fine and I am able to access the "Welcome to Nginx" page.
But when I add the IPs to be whitelisted it does not seem to work and still allows other IPs that are not whitelisted.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: nginx-ingress
annotations:
kubernetes.io/ingress.global-static-ip-name: <global-static-ip>
ingress.kubernetes.io/whitelist-source-range: "xx.xx.xx.xxx/32"
spec:
rules:
- host: <domain_name>
- http:
paths:
- path: /*
backend:
serviceName: nginx
servicePort: 80
Reference:
http://container-solutions.com/kubernetes-quick-tip/
https://docs.giantswarm.io/guides/advanced-ingress-configuration/
I have not worked with Ingress but as per normal nginx rules you need to deny all and then allow the whitelist IPS
`location / {
proxy_pass https://xxx.xx.xx.xx:8080
allow xx.xx.xx.xxx/32;
deny all;
allow xx.xx.xx.xxx/32;
}`
Which inturn wont allow your non-Whitelisted IP's.
The references you provided use the Nginx-based ingress controller.
Ingress on GKE uses http(s) load balancer. Currently the http(s) load balancer on GCP does not support the firewall rules to allow or deny traffic by IPs.
You can:
Block the source ip in web server or application by yourself.
Or
Try to install nginx-based ingress controller.

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.