Allow Azure Application Gateway to route all sub paths in AKS - kubernetes-ingress

I have AKS configured with Azure Application Gateway as my ingress.
I am trying to deploy a .net core Angular app to a path within the cluster. I would like to access the app on http://<cluster ip>/app1.
My kubernetes deployment (including ingress settings) is as follows:
apiVersion: v1
kind: Pod
metadata:
name: web-app-1
labels:
app: web-app-1
spec:
containers:
- image: "xxx.azurecr.io/web-app-1:latest"
name: web-app-1
imagePullPolicy: Always
ports:
- containerPort: 80
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
name: web-app-1
spec:
selector:
app: web-app-1
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: web-app-1
annotations:
kubernetes.io/ingress.class: azure/application-gateway
spec:
rules:
- http:
paths:
- path: /app1
backend:
serviceName: web-app-1
servicePort: 80
In the Angular app itself, I have left <base href="/" /> in index.html. However, I have amended the build to now be ng build --base-href /app1/"
Issue
When this is deployed and I browse to http://<cluster ip>/app1 then it loads the index.html file. However it returns a 404 for all the additional scripts e.g. 404 on http://<cluster ip>/app1/main-es2015.9ae13a2658e759db61f5.js
The issue could be with how I've configured Angular, but browsing to http://<cluster ip>/app1/index.html returns a 404 when I know it can be accessed just using /app1/.
I believe the issue is that Application Gateway is not routing requests properly for anything after /app1/. How can I get it to allow sub routes through (i.e. the scripts)?
Thanks

Got this working now. If I looked at the 404 response headers it says it was from kestrel, so was hitting the dotnet core api, so it needs configuring there. All the changes I made were:
Client:
Leave the base href as / e.g.
Add the base href to the build argument e.g. ng build --base-href /app1/"
In Configure of Startup.cs, add app.UsePathBase("/app1"); I do this in the else of env.IsDevelopment().
Application Gateway:
Change the path for the rules to - path: /app1*. I didn't have the asterisk so wasn't routing all subsequent routes.

You could also do something like this
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: appgw-ingress
annotations:
kubernetes.io/ingress.class: azure/application-gateway
appgw.ingress.kubernetes.io/backend-path-prefix: "/"
spec:
rules:
- http:
paths:
- path: /api/*
....
Where you are updating the routing prefix form "/" to "/api/*" . Specifically this annotation
appgw.ingress.kubernetes.io/backend-path-prefix: "/"

Related

Exposing AKS cluster application using ingress

I am trying to expose my application inside the AKS cluster using ingress:
It creates a service and an ingress but somehow does not assign an address to the ingress. What could be a possible reason for this?
apiVersion: apps/v1
kind: Deployment
metadata:
name: dockerdemo
spec:
replicas: 1
selector:
matchLabels:
app: dockerdemo
template:
metadata:
labels:
app: dockerdemo
spec:
nodeSelector:
"kubernetes.io/os": linux
containers:
- name: dockerdemo
image: devsecopsacademy/dockerapp:v3
env:
- name: ALLOW_EMPTY_PASSWORD
value: "yes"
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 250m
memory: 256Mi
ports:
- containerPort: 80
name: redis
apiVersion: v1
kind: Service
metadata:
name: dockerdemo-service
spec:
type: ClusterIP
ports:
port: 80
selector:
app: dockerdemo
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress15
annotations:
kubernetes.io/ingress.class: addon-http-application-rounting
spec:
rules:
host: curefirsttestapp.cluster15-dns-c42b65ee.hcp.westeurope.azmk8s.io
http:
paths:
path: /
pathType: Prefix
backend:
service:
name: dockerdemo-service
port:
number: 80
Well, first make sure your application is up and functionning inside your K8s Cluster using a port-forword to your localhost
kubectl -n $NAMESPACE port-forward svc/$SERVICE :$PORT
if app is reachable and your call are getting back 200 Status, you can now move to the ingress part:
Make sure ingress controller is well installed under your services
kubectl -n $NAMESPACE get svc
Add a DNS record in your DNS zone which maps your domain.com to ingress controller $EXTERNAL_IP
Take a look at the ingress you created for your $SERVICE
kubectl -n $NAMESPACE get ingress
At this stage, if you application is well running and also the the ingress is well set, the app should be reachable trough domain.com, otherwise we'll need further debugging.
Make sure you have an ingress controller deployed. This is a load balancer service which can have either a public or private ip depending on your situation.
Make sure you have an ingress definition which has a rule to point to your service. This is the metadata which will tell your ingress controller how to route requests to its ip address. These routing rules can contain how to handle paths like strip, exact, etc....

Azure Kubernetes loadbalancer with Ingress and path based routing

I am trying to create a basic path based routing ingress controller with an AKS managed Load Balancer. Trouble is figuring out how to route from the Load Balancer to the Ingress controller.
Here is my ingress controller yml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-cpr
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- http:
paths:
- path: /green/
pathType: Prefix
backend:
service:
name: nginx-green-clusterip-service
port:
number: 80
- path: /red/
pathType: Prefix
backend:
service:
name: nginx-red-clusterip-service
port:
number: 80
As you can see, the ingress controller is responsible to send to the appropriate app based on the incoming path.
But how do I get this connected to a managed Load Balancer?
apiVersion: v1
kind: Service
metadata:
name: loadbal-service
spec:
type: LoadBalancer
ports:
- port: 80
selector:
app: ingress-cpr
I know this line isnt correct "-app: ingress-cpr". But what do I have to do so that the LoadBalancer forwards to the ingress controller?
Thanks in advance,
Jake.
In the service manifest the app's selector should be pointing to the backend service name of the ingress. In this particular case instead of ingress-cpr in the service manifest should be either of the two backends (nginx-green-clusterip-service or nginx-red-clusterip-service). Any traffic via external IP of the managed LB on port 80 should be routed to one of the backend defined in the ingress then.
There is also Microsoft example about creation of basic ingress controller in AKS.

How to visualize my web application with browser using Kubernetes Nginx Ingress?

I am following this web site to develop an API with Nginx Ingress. When I use curl command it works !
curl -v -k -H "Host: myServiceA.foo.org" http:<IP_ADDRESS_INGRESS_NGINX>:80
Now I would like to use a browser like Chrome or Firefox but I don't find any way to do it knowing that http:<IP_ADDRESS_INGRESS_NGINX>:80 doesn't work without header.
Do you know how to do please ?
Regards
It's not working because you've configured the host field in ingress yaml.
Using the same yaml from Nginx docs you've posted:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: ingress-myServiceA
annotations:
# use the shared ingress-nginx
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: myServiceA.foo.org <== HERE
http:
paths:
- path: /
backend:
serviceName: myServiceA
servicePort: 80
The ingress will only accept the connection and forwarding the request to your service if the request contains the host myServiceA.foo.org.
You could test it editing the /etc/hosts of your machine e pointing to the nginx ingress ip:
File /etc/hosts
<INGRESS_IP> myServiceA.foo.org
Or another option is remove the field host in this way the ingress will accept requests coming from the Nginx ingress ip, like this yaml:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: example-ingress
spec:
rules:
- http:
paths:
- path: /
backend:
serviceName: echo-svc
servicePort: 80

How to set up ingress in Kubernetes for http and https backend

Let's imagine I have a simple website and I want to run it on Kubernetes. Website should listen HTTP and HTTPS protocols.
In Kubernetes I've set up for it deployment, service and ingress. If I try only port 80, everything works well, but If I want to extend it with HTTPS, everything fails and I'm receiving 404 error from ingress controller. HTTPS traffic should be forwarded directly to backend. How can I do it?
I tried to extend my ingress controller daemon set with --enable-ssl-passthrough=true option (directly in Daemon Set config), but then ingress controller's pod didn't start. I found article in the Internet, that to enable --enable-ssl-passthrough, ingress controller should be installed with that flag: see this page. By the way, how can I "install" ingress controller with that flag?
I tried to add 80 and 443 ports in ingress rules, but without success too.
Kubernetes: v1.14.3
Ingress controller: documentation
Please see my service and ingress:
apiVersion: v1
kind: Service
metadata:
name: {{ container_service_ingress }}-service
labels:
cms: "{{ cms }}"
namespace: "default"
spec:
selector:
website: "{{ domain }}"
cms: "{{ cms }}"
ports:
- name: http
port: 80
- name: https
port: 443
type: NodePort
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: {{ container_service_ingress }}-ingress
# I tried this annotation, but it didn't help:
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
labels:
website: "{{ domain }}"
spec:
rules:
- host: {{ domain }}
http:
paths:
- backend:
serviceName: {{ container_service_ingress }}-service
servicePort: 80
- backend:
serviceName: {{ container_service_ingress }}-service
servicePort: 443
And in this case ingress controller can't start as it says about duplicated location "/" in config file
Can someone help me with it?
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tls-ingress
spec:
tls:
- hosts:
- ssl.example.com
secretName: test-tls
rules:
- host: ssl.example.com
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 80
You need to use the tls section to achieve your requirement.

Different ingress in different Namespace in kubernetes

I have created two different namespaces for different environment. one is devops-qa and another is devops-dev. I created two ingress in different namespaces. So while creating ingress of qa env in devops-qa namespace, the rules written inside ingress of qa is working fine. Means I am able to access the webpage of qa env. The moment I will create the ingress of dev env in devops-dev namespace, I will be able to access the webpage of dev env but wont be able to access the webpage of qa. And when I delete the dev ingress then again I will be able to access the qa env website
Below is the ingree of both dev and qa env.
Dev Ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: cafe-ingress-dev
namespace: devops-dev
spec:
tls:
- hosts:
- cafe-dev.example.com
secretName: default-token-drk6n
rules:
- host: cafe-dev.example.com
http:
paths:
- path: /
backend:
serviceName: miqpdev-svc
servicePort: 80
QA Ingress
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: "nginx"
name: cafe-ingress-qa
namespace: devops-qa
spec:
tls:
- hosts:
- cafe-qa.example.com
secretName: default-token-jdnqf
rules:
- host: cafe-qa.example.com
http:
paths:
- path: /greentea
backend:
serviceName: greentea-svc
servicePort: 80
- path: /blackcoffee
backend:
serviceName: blackcoffee-svc
servicePort: 80
The token mentioned in the ingress file is of each namespace. And the nginx ingress controller is running in QA namespace
How can i run both the ingress and will be able to get all the websites deployed in both dev and qa env ?
I actually Solved my problem. I did everything correct. But only thing I did not do is to map the hostname with the same ip in Route53. And instead of accessing the website with hostname, I was accessing it from IP. Now after accessing the website from hostname, I was able to access it :)
Seems like you posted here and got your answer. The solution is to deploy a different Ingress for each namespace. However, deploying 2 Ingresses complicates matters because one instance has to run on a non-standard port (eg. 8080, 8443).
I think this is better solved using DNS. Create the CNAME records cafe-qa.example.com and cafe-dev.example.com both pointing to cafe.example.com. Update each Ingress manifest accordingly. Using DNS is somewhat the standard way to separate the Dev/QA/Prod environments.
Had the same issue, found a way to resolve it:
you just need to add the "--watch-namespace" argument to the ingress controller that sits under the ingress service that you've linked to your ingress resource. Then it will be bound only to the services within the same namespace as the ingress service and its pods belong to.
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
namespace: my-namespace
name: nginx-ingress-controller
spec:
replicas: 1
selector:
matchLabels:
name: nginx-ingress-lb
template:
metadata:
labels:
name: nginx-ingress-lb
spec:
serviceAccountName: ingress-account
containers:
- args:
- /nginx-ingress-controller
- "--default-backend-service=$(POD_NAMESPACE)/default-http-backend"
- "--default-ssl-certificate=$(POD_NAMESPACE)/secret-tls"
- "--watch-namespace=$(POD_NAMESPACE)"
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
name: nginx-ingress-controller
image: "quay.io/kubernetes-ingress-controller/nginx-ingress-controller:0.24.1"
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
ports:
- containerPort: 80
name: http
protocol: TCP
- containerPort: 443
name: https
protocol: TCP
---
apiVersion: v1
kind: Service
metadata:
namespace: my-namespace
name: nginx-ingress
spec:
type: LoadBalancer
ports:
- name: https
port: 443
targetPort: https
selector:
name: nginx-ingress-lb
You can create nginx ingress cotroller in kube-system namespace instead of creating it in QA namespace.