Monday, April 10, 2023

Azure Kubernetes Service: Enable Ingress using Application Gateway

In this post, let's see how we can enable ingress in an AKS cluster using Application Gateway. We can easily do that using Application Gateway Ingress Controller (AGIC). 

Let's get to it.

Make sure you have the latest Azure CLI installed, logged in, and have selected the correct subscription. I am using Azure CLI in Windows.

Here I am going to be doing a Greenfield deployment to keep things clear. You can also do a Brownfield deployment.

First I am creating a Resource Group for our AKS cluster.

az group create `
    --name rg-aks-appgw-demo-001 `
    --location eastus2
Now, I am creating the AKS cluster in the Resource Group we just created.
az aks create `
    --resource-group rg-aks-appgw-demo-001 `
    --node-resource-group rg-mc-aks-appgw-demo-001 <
# custom node resource group name #> `
    --name aks-appgw-demo-001 `
    --network-plugin azure 
<# only Azure CNI supports AGIC #> `
    --enable-managed-identity `
    --enable-addon ingress-appgw 
<# enable AGIC add-on #> `
    --appgw-name agw-aks-appgw-demo-001 
<# name of the Application Gateway #> `
    --appgw-subnet-cidr "10.225.0.0/16" `
    --generate-ssh-keys

Here I have,

  • Explicitly specified the node resource group name as a personal preference
  • Specified azure as the network plugin. This is a must because only Azure CNI (Container Networking Interface) supports AGIC.
  • Then enabled add-on ingress-appgw
  • Specified appgw-name. Since I don't have an Application Gateway created before, this will create an Application Gateway as part of the cluster deployment. Application Gateway will be placed on the node resource group. You can also use an existing Application Gateway if you have one already.
  • Since I am creating a new Application Gateway, I am providing a Subnet CIDR through appgw-subnet-cidr to be used for a new subnet created to deploy the Application Gateway. The address space must be within the AKS virtual network without overlapping with AKS subnet. Since we haven't defined any particular virtual network to be used, defaults will be used, which are:
    • AKS virtual Network: 10.224.0.0/12
    • AKS subnet: 10.224.0.0/12

Once the AKS is created, let's connect to it.

az aks get-credentials `
    --resource-group rg-aks-appgw-demo-001 `
    --name aks-appgw-demo-001

Now, I have the following K8s declarative configuration in a file named deployment.yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: customer-service
  name: customer-service
spec:
  replicas: 1
  selector:
    matchLabels:
      app: customer-service
  template:
    metadata:
      labels:
        app: customer-service
    spec:
      containers:
        - name: customer-service
          image: ravana.azurecr.io/aspnetcore/hello-world/api:latest
          imagePullPolicy: Always
          env:
            - name: ServiceName
              value: "Customer Service"

---

apiVersion: v1
kind: Service
metadata:
  name: customer-service
spec:
  selector:
    app: customer-service
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

---

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: application-ingress
  annotations:
    kubernetes.io/ingress.class: azure/application-gateway
    appgw.ingress.kubernetes.io/backend-path-prefix: "/"
spec:
  rules:
  - http:
      paths:
      - path: /api/customers/
        pathType: Prefix
        backend:
          service:
            name: customer-service
            port:
              number: 80

Here,

  • I have a deployment that will deploy a pod, containing a single container of an image of a simple ASP.NET Core Minimal API. I have the aspnetcore/hello-world/api image in my Azure Container Repository (which isn't public, unfortunately). You can find the sample code here. You can have it deployed to your ACR and attach the ACR to your AKS cluster. Or you can even use mcr.microsoft.com/dotnet/samples:aspnetapp image.
  • Then I have a Cluster IP service, which targets TCP port 80 on any pod with the app: customer-service label.
  • And finally the ingress Application Gateway Ingress Controller. I have a Prefix path mapping of /api/customers/ pointing to my service (important read: Behavioural Change Notice for  AGIC 1.5.1 for paths). And when I do any request starting with http://<INGRESS_IP>/api/customers/, the expectation is, all those requests should get routed to my service.  I have appgw.ingress.kubernetes.io/backend-path-prefix: "/" to rewrite the backend path specified in an ingress resource with "/".
Now let's apply this configuration.
kubectl apply -f .\deployment.yaml
kubectl apply -f .\deployment.yaml
Now I can get the ingress information as follows.
kubectl get ingress
kubectl get ingress
This is basically the Frontend public IP address of the Application Gateway that got created.
Frontend public IP address of the Application Gateway
Note down the IP address of the ingress. And I am doing 2 curl requests to make sure I can reach my service.
curl http://20.96.70.198/api/customers/
curl http://20.96.70.198/api/customers/fibonacci?number=5
Test the connectivity with curl
And it works.

Hope this helps.

You can find the complete code here:

Happy Coding.

Regards,
Jaliya

No comments:

Post a Comment