Categories
Cloud Linux

Configure path-based routing with Kubernetes ingress (AKS)

Aim:

Building on my last blog post https://ianstacey.net/2022/01/10/deploy-web-app-in-azure-kubernetes-service-aks-updated/ I wanted to enable path based routing in my cluster. Requests made to different path will be routed to different backend pods/services as shown below:

Path based routing

Create Kubernetes Deployments and Objects:

Created four different deployments and services, as stored in GitHub at https://github.com/iastac84/ltfc-sample-webapp, one of the deployments below:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: ltfckenny
  namespace: luton
  labels:
    app: ltfckenny
spec:
  replicas: 1
  selector:
      matchLabels:
        app: ltfckenny
  template:
    metadata:
      labels:
        app: ltfckenny
    spec:
      containers:
      - name: ltfckenny
        image: nginx
        volumeMounts:
        - name: kenny-index
          mountPath: /usr/share/nginx/html/index.html
          subPath: index-kenny.html
        - name: images
          mountPath: /usr/share/nginx/html/images
          subPath: images
      volumes:
      - name: kenny-index
        azureFile:
          secretName: azure-secret
          shareName: isnginxlt
          readOnly: false
      - name: images
        azureFile:
          secretName: azure-secret
          shareName: isnginxlt
          readOnly: false

---

apiVersion: v1
kind: Service
metadata:
  name: ltfckenny
  namespace: luton
spec:
  selector:
    app: ltfckenny
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

Note the use of subPath in the volumesMounts section, I did this so I would only require one Azure File share, one place to upload the index-*.html and images files.

Created the deployments with kubectl apply -f as below:

kubectl apply -f luton-power-deployment.yaml 
kubectl apply -f luton-kenny-deployment.yaml 
kubectl apply -f luton-scenes-deployment.yaml 
kubectl apply -f luton-wembley-deployment.yaml

Create the Ingress:

Using https://github.com/iastac84/ltfc-sample-webapp/blob/main/ingress.yaml and created with kubectl apply -f ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway
    appgw.ingress.kubernetes.io/backend-path-prefix: "/"
  generation: 1
  name: ltfc-ingress
  namespace: luton
spec:
  rules:
  - http:
      paths:
      - path: /kenny
        pathType: Exact
        backend:
          service:
            name: ltfckenny
            port:
              number: 80
      - path: /power
        pathType: Exact
        backend:
          service:
            name: ltfcpwercrt
            port:
              number: 80
      - path: /wembley
        pathType: Exact
        backend:
          service:
            name: ltfcwembley
            port:
              number: 80
      - path: /scenes
        pathType: Exact
        backend:
          service:
            name: ltfcscenes
            port:
              number: 80
      - path: /
        pathType: Exact
        backend:
          service:
            name: ltfcscenes
            port:
              number: 80

Note the annotation of appgw.ingress.kubernetes.io/backend-path-prefix: “/” , this is required as the paths defined above do not exist on the backends, without this annotation we will receive 502 Bad Gateway errors.

$ kubectl get all -n luton
NAME                               READY   STATUS    RESTARTS   AGE
pod/ltfckenny-57df74c5d-xw8pd      1/1     Running   0          138m
pod/ltfcpwercrt-59f8df7768-h29pn   1/1     Running   0          137m
pod/ltfcpwercrt-59f8df7768-lzq8r   1/1     Running   0          137m
pod/ltfcscenes-5f858456f8-zqdns    1/1     Running   0          137m
pod/ltfcwembley-764696f5c8-dwc99   1/1     Running   0          137m

NAME                  TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/ltfckenny     ClusterIP   10.0.171.202   <none>        80/TCP    4h16m
service/ltfcpwercrt   ClusterIP   10.0.158.150   <none>        80/TCP    4h23m
service/ltfcscenes    ClusterIP   10.0.173.150   <none>        80/TCP    4h14m
service/ltfcwembley   ClusterIP   10.0.79.15     <none>        80/TCP    4h12m

NAME                          READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/ltfckenny     1/1     1            1           4h16m
deployment.apps/ltfcpwercrt   2/2     2            2           4h23m
deployment.apps/ltfcscenes    1/1     1            1           4h14m
deployment.apps/ltfcwembley   1/1     1            1           4h12m

NAME                                     DESIRED   CURRENT   READY   AGE
replicaset.apps/ltfckenny-57df74c5d      1         1         1       4h16m
replicaset.apps/ltfcpwercrt-59f8df7768   2         2         2       4h23m
replicaset.apps/ltfcscenes-5f858456f8    1         1         1       4h14m
replicaset.apps/ltfcwembley-764696f5c8   1         1         1       4h12m


$ kubectl describe ingress ltfc-ingress -n luton
Name:             ltfc-ingress
Labels:           <none>
Namespace:        luton
Address:          52.164.122.170
Default backend:  default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
  Host        Path  Backends
  ----        ----  --------
  *           
              /kenny     ltfckenny:80 (10.10.20.36:80)
              /power     ltfcpwercrt:80 (10.10.20.10:80,10.10.20.39:80)
              /wembley   ltfcwembley:80 (10.10.20.50:80)
              /scenes    ltfcscenes:80 (10.10.20.17:80)
              /          ltfcscenes:80 (10.10.20.17:80)
Annotations:  appgw.ingress.kubernetes.io/backend-path-prefix: /
              kubernetes.io/ingress.class: azure/application-gateway
Events:       <none>

Update Application Gateway:

Lastly, I updated the Application Gateway (AGW) via the Azure portal, creating a new HTTPS listeners, uploading my SSL cert, updating the rules and creating a redirect for HTTP to HTTPS. Doing this manually is not ideal as if the ingress is updated (for instance with another apply) these changes will be lost as the ingress automatically updates the AGW.

Testing

Resources: