Monday, August 9, 2021

Multi-Stage AKS Deployment and Traffic Routing

Summary: Excellent articles on AKS and traffic routing. 

Ref: Multi-Stage AKS Deployment and Traffic Routing | by Amine Kaabachi | Azure Expert | Medium

Step 1: Create an AKS Cluster and push docker to AKS


az group create --name multi-stage-aks --location northeurope
az aks create --resource-group multi-stage-aks --name kube-cluster --node-count 2 --generate-ssh-keys -s Standard_DS4_v2 --disable-rbac

Create docker and execute

docker run -e ENV=dev -p 8080:8080 g0d3l/dummy-app
docker run -e ENV=prod -p 8080:8080 g0d3l/dummy-app

In this configuration it was explained how to manage dev and prod environment with single AKS cluster.

Step2 : AKS with Nginx Ingress Controller


Add help repo: 

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm repo update

Install Ingress

helm install single-ingress ingress-nginx/ingress-nginx --set rbac.create=false -n kube-system
NAME: single-ingress
LAST DEPLOYED: Sun Oct 4 04:22:36 2020
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

Ingress is now functional and is attached to an Azure Load Balancer with an external IP 

Above IP can be attached to DNS . Two ingress installations can be done for one for dev and another for prod. 

kubectl apply -f ingress.yml -n dev
ingress.extensions/cloudapp-ingress created

 Introduction: 

This tutorial will help you deploy your app to an AKS Cluster with multiple environments (Dev, QA, etc) and allow to access each app instance. using a separate FQDN (dev.mycloudapp.org, qa.mycloudapp.org, etc).

In fact, your requirements are the following:

  • Having the two apps in separate environments so that changes in the first do not affect the second.
  • Being able to access each instance of the application separately. i.e. dev.mycloudapp.org redirects to the dev instance and similarly prod.mycloudapp.org redirects to the prod one.
  • Being able to do it with only one AKS cluster.

If you can afford multiple clusters. It may be a better solution as it ensures that the apps will be separated physically. In the other case where you want to optimise your spendings, this article will will help you do it.

To solve this, we will use Kubernetes namespaces to separate and isolate stages.

Note: This article suppose. that you are familiar with the concepts of Kubernetes Service, Ingress and Ingress Controllers. If you want more basic topics, please let me know in the comments.

(Optional) Refresher on Services from KodeKloud.

Lab Setup

This section describes a Lab setup for those who want to go through the use-case without having a real scenario at hand. Feel free to skip it if your AKS is already setup and your apps are deployed in separate namespaces.

Create an AKS Cluster

Let’s start by creating a new resource group for our AKS Cluster deployment:

▶ az group create --name multi-stage-aks --location northeurope

Now, we can create a new AKS Cluster, we will also disable RBAC because we don’t need it in these examples:

▶ az aks create --resource-group multi-stage-aks --name kube-cluster --node-count 2 --generate-ssh-keys -s Standard_DS4_v2 --disable-rbac

This will create another internal resource group with the required Azure components that are needed for the AKS cluster:

The auto-created resource group for `kube-cluster` AKS.

Notice that it contains a VM scale set and a Load balancer. There is also a Public IP that is attached to the Load balancer.

We need to set “kube-cluster” as current context in ~/.kube/config file and configure the credentials. For that we can use the following command from az-cli:

▶ az aks get-credentials -g multi-stage-aks -n kube-cluster

Here is what the AKS Cluster get’s by default:

Default objects created on the AKS cluster.

To note that there is not ingresses setup by default and that would be something we need to do later.

Understanding the Example App

For the Lab we will use the following dummy-app. Lets have a look at the source code:

What you need to notice is mainly that it will append an env line with the value of ENV environment variable and that it listens to port 8080.

I already pushed the image to docker hub. So, you can run the two following commands and compare the result:

▶ docker run -e ENV=dev -p 8080:8080 g0d3l/dummy-app

And the if you change the ENV variable:

▶ docker run -e ENV=prod -p 8080:8080 g0d3l/dummy-app

Here is a preview of the service that will be running:

The dummy-app running with ENV=dev set.

Creating Namespaces and Deploying the App Instances

For this tutorial we will create two namespaces dev and prod. We will deploy an instance of the app in each namespace while changing the ENV from dev to prod.

Note that in a real use-case these steps should be done through a pipeline and preferably using a package manager like Helm.

Let’s start by creating the namespaces:

▶ kubectl create namespace dev
namespace/dev created
▶ kubectl create namespace prod
namespace/prod created

Then lets take a look at our Kubernetes objects definitions:

We have a deployment and a service that will target the created pods. The service should be accessible at port 80 and will target pods internally at port 8080.

Note that there is an ENV variable to be specified. It will allow us to easily create multiple instances of these objects per namespace:

▶ export ENV=dev && envsubst < objects.yml | kubectl apply -f -deployment.apps/app created
service/app-svc created

And finally we do the same thing with ENV=prod and you can test If everything is setup correctly by doing a local port forwarding on the two services:

▶ kubectl port-forward service/app-svc -n prod 8080:80

The prod service should be now accessible through http://localhost:8080.

We are now fully set.

AKS with Nginx Ingress Controller

As a requirement, we will need a custom domain name. I registered mycloudapp.org from Google to show you how to configure one.

But first let’s start by installing the Ingress controller. For this we need helm. If you don’t already have it installed, you can use this command:

▶ curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash

Installing the Ingress Controller

You need to add the Nginx ingress helm repo to the client database:

▶ helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx▶ helm repo update

Now let’s install the Ingress controller:

▶ helm install single-ingress ingress-nginx/ingress-nginx --set rbac.create=false -n kube-systemNAME: single-ingress
LAST DEPLOYED: Sun Oct 4 04:22:36 2020
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The ingress-nginx controller has been installed.It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status by running 'kubectl --namespace kube-system get services -o wide -w single-ingress-ingress-nginx-controller'

Running the suggested command gives us the following:

NAME                                      TYPE           CLUSTER-IP    EXTERNAL-IP    PORT(S)                      AGE    SELECTORsingle-ingress-ingress-nginx-controller   LoadBalancer   10.0.44.221   20.191.53.60   80:32306/TCP,443:31700/TCP   3m8s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=single-ingress,app.kubernetes.io/name=ingress-nginx

This confirms that our Ingress is now functional and is attached to an Azure Load Balancer with an external IP of 20.191.53.60.

Load balancer configuration in Azure Portal.

As you can see in the screenshot above a new Frontend IP was added to the Load balancer with two rules (corresponding to ports 80 and 443).

Configure DNS Records

Next step is to go to the generated IP and configure a DNS name label on it. For my case, I now have http://dummy- app.northeurope.cloudapp.azure.com/ pointing to the IP that is configured in the Load balancer.

Generated IP Configuration in Azure Portal.

Next, I need to add to CNAME records on my custom domain name. As you can see in the screenshot below both records point to the same FQDN.

Relevant DNS config for the custom domain.

Create Ingresses in Each Namespace

Let’s take a look at the ingress definition. We will only see the dev one but changes for Prod are very clear and minimal:

We can run the following command:

▶ kubectl apply -f ingress.yml -n dev
ingress.extensions/cloudapp-ingress created

Now, our service is accessible via http://dev.mycloudapp.org ! You apply the same command on the namespace prod and by changing the host on the definition, it will be accessible on the corresponding FQDN.

dummy-app accessed from the external FQDN dev.mycloudapp.org.

(Optional) Ingress Controller with Fixed IP

The IP was automatically generated when creating installing the Ingress Controller using Helm. This presents one disadvantage is that the IP is dynamic and If any changes happen to the Ingress-controller or cluster it will likely result in the IP changing.

The solution is to create the IP beforehand. You can refer to this complete Microsoft docs which is very detailed on the Topic. Do not hesitate to ask in the comments, if you got stack or if you had some issues completing this part.

Conclusion

This tutorial shows you how to create multi-stages AKS deployment and traffic routing. I hope this can help you solve your scenarios or better understand the Kubernetes ecosystem. Feel free to comment, provide or ask for help around this topic.

No comments:

Post a Comment