Kubernetes ingress - access to web service container subpaths - kubernetes

I have a web service (dashboard-service) running in a container. The service provides the required webpages at:
http://192.168.1.100:3000/page2/
http://192.168.1.100:3000/page3/
etc
I have the dashboard-service running in a kubernetes cluster, and want to use ingress to control access like this:
so that I can access at: http://192.168.1.100:3000/dashboard/1
http://192.168.1.100:3000/dashboard/2
etc
I've tried the following ingress setup, but am getting "404 Not Found"
Is there some way of adding routes to subpaths?
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: dashboard-service
namespace: db
annotations:
ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- http:
paths:
- path: /dashboard/
pathType: Prefix
backend:
service:
name: dashboard-service
port:
number: 3000

First of all, there is no below configuration in ingress
backend:
service:
name: dashboard-service
port:
number: 3000
You should use next instead..
- backend:
serviceName: dashboard-service
servicePort: 3000
Next, I would propose you install, configure and use nginx ingress controller instead of regular kubernetes-ingress. Please note also, if you use nginx controller, your annotation should be nginx.ingress.kubernetes.io/rewrite-target: , not ingress.kubernetes.io/rewrite-target:
As per NGINX Ingress Controller rewrite documentation, your ingress should look like
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /page$2
name: dashboard-service
namespace: db
spec:
rules:
http:
paths:
- backend:
serviceName: dashboard-service
servicePort: 3000
path: /dashboard(/|$)(.*)
I tested regex and capture groups for you here: https://regex101.com/r/3zmz6J/1

Related

Dynamic Routing by Hostname only - Kubernetes Ingress Rules

I have a K8s cluster with multiple different services deployed and would like to use a single Ingress to route each incoming request to the appropriate service via a unique hostname DNS.
Currently, I've only been able to resolve a request when using the root path i.e. service-123.app.com.
As soon as I try to make a request with a path it doesn't resolve. The paths are valid paths to each service. For example, service-123.app.com/page/12345 would be expected by the application.
I might not fully understand how K8s Ingress rules are expected to work, but I hoped that it would match based on hostname only and simply forward on the path to the appropriate service.
Am I missing something very simple here? Any help is much appreciated. Thanks!
Here are my config files.
Ingress.yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
......
name: app-name
namespace: default
spec:
rules:
- host: service-123.app.com
http:
- path: "/*"
backend:
serviceName: service-123
servicePort: 80
- host: service-456.app.com
http:
paths:
- path: "/*"
backend:
serviceName: service-456
servicePort: 80
service.yaml
---
apiVersion: v1
kind: Service
metadata:
annotations: {}
labels:
app: service-123
name: service-123
namespace: default
spec:
ports:
- name: port8080
port: 80
targetPort: 8080
selector:
app: service-123
type: NodePort
Not sure which K8s and ingress controller you are using, but in the later K8s you can specify the pathType which takes care of path wildcards more nicely.
You would have something like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
......
name: app-name
namespace: default
spec:
rules:
- host: service-123.app.com
http:
- path: /
pathType: Prefix
backend:
serviceName: service-123
servicePort: 80
- host: service-456.app.com
http:
paths:
- path: /
pathType: Prefix
backend:
serviceName: service-456
servicePort: 80
If you are using an nginx ingress controller a good way to see the right nginx configuration is by looking at the actual nginx.conf generated by the ingress controller.
$ kubectl cp <nginx-ingress-controller-pod>:nginx.conf nginx.conf
$ cat nginx.conf

Do I have to define an ingress per service with Linkerd?

Looking at the linkerd ingress documentation here it says that I need to create an ingress with an annotation of
ingress.kubernetes.io/custom-request-headers: l5d-dst-override:web-svc.emojivoto.svc.cluster.local:80
this annotation is specific to a single service, which makes it sound like there must be a new ingress with it's own annotation for every service. I couldn't have something like the following for example:
spec:
rules:
- host: example.com
http:
paths:
- path: /path-one
backend:
serviceName: service-1
servicePort: 80
- path: /path-two
backend:
serviceName: service-2
servicePort: 80
where I could define paths to different services in a single ingress class.
Is my reading of these docs accurate? or am I missing something? I am hoping to avoid creating an ingress for every service I run in linkerd.
Yes, unfortunately you understood correctly about creating separate ingress for each service if you want use ingress.kubernetes.io/custom-request-headers.
Yes, if you would have 1000 services - you should create 1000 ingresses to make it work properly.
Ingress1:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
namespace: marcus
annotations:
kubernetes.io/ingress.class: "traefik"
ingress.kubernetes.io/custom-request-headers: l5d-dst-override:service1.marcus.svc.cluster.local:80
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: service1
servicePort: 80
path: /
Ingress2:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-ingress
namespace: marcus
annotations:
kubernetes.io/ingress.class: "traefik"
ingress.kubernetes.io/custom-request-headers: l5d-dst-override:service2.marcus.svc.cluster.local:80
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: service2
servicePort: 80
path: /
Traefik is a great solution, and in this case it would be great if it had the option to dynamically set the service in a header.
There is an open issue on this in the traefik project that has been open for a while. The last update is to use an Ingress per service in these scenarios.
Here's similar question.

Can I use ip address in Kubernetes Ingress instead of domain name?

I am using Traefik as Kubernetes Ingress and I would like to know if I can use an IP address instead of a domain name. Example:
http://ipaddress/service1
http://ipdadress/service2
My ingress configuration:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: service1
namespace: staging
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefixStrip
spec:
rules:
- host: mydomain.dev
http:
paths:
- path: /service1
backend:
serviceName: service1
servicePort: 3000
Since it is a Layer 7 Load Balancer you can't use IP address directly. But if you use nip.io and for example 192-168-1-1.nip.io as your hostname it would work and you can do all the things you can regularly do with normal hostnames such as redirect app1.192-168-1-1.nip.io to app1 and 192-168-1-1.nip.io/app2 to app2 etc.
I have done this with kong but i believe it should also work with traefik, by simply removing the host. unfortunately now you can't access it with the domain name
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: service1
namespace: staging
annotations:
kubernetes.io/ingress.class: traefik
traefik.frontend.rule.type: PathPrefixStrip
spec:
rules:
# - host: mydomain.dev
- http:
paths:
- path: /service1
backend:
serviceName: service1
servicePort: 3000
Hope it helps!

ERR_TOO_MANY_REDIRECTS for Minio via NGINX Ingress Controller

I have a Minio ClusterIP service running in a Kubernetes cluster. And on top of it, I have a NGINX Ingress Controller. NGINX Ingress needs to forward Minio traffic to the Minio service, and other traffic to their corresponding services.
My Ingress configuration looks like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /app/?(.*)
backend:
serviceName: app-service
servicePort: 3000
- path: /minio/?(.*)
backend:
serviceName: minio-service
servicePort: 9000
Once deployed, the app works fine. However, the Minio page has problem, complaining:
This page isn’t working
example.mysite.com redirected you too many times.
Try clearing your cookies.
ERR_TOO_MANY_REDIRECTS
And indeed, the requests are kept redirecting. Here is the screenshot from Chrome DevTools' Network console.
Any ideas?
As Minio always redirects to /minio/, you need to keep /minio in the path and pass it on to the Minio service.
When I change its path rule to - path: /(minio/.*), it works. Now the Ingress configuration looks like below:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-service
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /app/?(.*)
backend:
serviceName: app-service
servicePort: 3000
- path: /(minio/.*)
backend:
serviceName: minio-service
servicePort: 9000
And I've got the Minio service working in the browser:
Hope it is helpful.

How to whitelist only one path in kubernetes nginx ingress controller

Using the Nginx Ingress Controller, we would like to expose different paths of a Kubernetes service, with different security requirements.
/ is open to the public
/white-list only allows connections from a specific IP Address
/need-key requires an API key
I'm running in AWS EKS. Kubernetes version is as follows:v1.12.6-eks-d69f1b.
If we use Annotations, they apply to the entire service. Ideally I would like to apply an Annotation only to a path.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myServiceA.foo.org
http:
paths:
- path: /
backend:
serviceName: myServiceA
servicePort: 80
- path: /white-list
backend:
serviceName: myServiceA
servicePort: 80
**NEED SOMETHING HERE TO WHITELIST**
- path: /need-key
backend:
serviceName: myServiceA
servicePort: 80
**NEED SOMETHING HERE TO USE API-KEY**
The results I've been having end up applying to all the paths.
I can live without API-Key as I can code that out, but ideally, I'd rather have it managed outside of the container.
Has anyone accomplished this with NGINX Ingress controller?
To apply annotation for each path, you could write one ingress rule for each path you want to apply. Nginx Ingress Controller will collect those ingress rules by itself and apply accordingly.
For example:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA-root
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myServiceA.foo.org
http:
paths:
- path: /
backend:
serviceName: myServiceA
servicePort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA-white-list
annotations:
kubernetes.io/ingress.class: "nginx"
ingress.kubernetes.io/whitelist-source-range: X.X.X.X/32
spec:
rules:
- host: myServiceA.foo.org
http:
paths:
- path: /white-list
backend:
serviceName: myServiceA
servicePort: 80
...