Getting Started with Azure Managed Kubernetes - Deploy your first asp.net core 2.0 app in AKS

Well Microsoft released AKS aka *new* Azure Container Service aka Azure Kubernetes Service (fully managed) a few months back, still in public preview though. This guide will help you to get started with AKS. We are going to deploy our first asp.net core 2.0 App in AKS and then do some cool stuff like scaling up & down.
Following are the steps we are going to perform.
  • Create a docker image (in linux) from a simple asp.net core 2.0 app
  • Publish the same in Azure Container Registry (ACR)
  • Create a Kubernetes cluster using AKS in Azure
  • Deploy our application in the cluster
  • Scale up/down
  • [Optional] Create a public/private SSH key

Prerequisites

A development computer running:
  • Visual Studio 2017 (mine is v15.5.2)
  • Docker for Windows. Get Docker CE for Windows (stable). After installing and starting Docker, right-click on the tray icon and select Switch to Linux containers (if already not). My current version is v17.12.0-ce-win47 (15139)
  • An Azure subscription
  • Google Cloud SDK for windows. Not mandatory, we can use PowerShell or Bash etc. But let's just use this today.
  • Install kubectl, the Kubernetes command-line tool. This is needed to manage your Kubernetes cluster once it in published on Azure.
  • [Optional] Enable Bash for Windows.

Create a docker image (in Linux) from a simple asp.net core 2.0 app

We are not going to go into details about all the steps here. You can read more if you want to learn about creating an image in a previous article. Below is my api controller file and the docker file. You can get these files from github too. Just take a note of the Linux image tags in the docker file to be downloaded from docker hub. We are using latest Linux images here.
[Route("api/[controller]")]
    public class QuotesController : Controller
    {
        private static readonly string[] ListOfQuotes;

        static QuotesController()
        {
            ListOfQuotes = JsonConvert.DeserializeObject<QuoteList>(System.IO.File.ReadAllText("quotes.json")).Quotes;
        }

        [HttpGet]
        public IActionResult Get() => Ok(ListOfQuotes[new Random().Next(ListOfQuotes.Length)]);

        [HttpGet("{count}")]
        public IActionResult GetMany(int count)
        {
            if (count < 0 || count > ListOfQuotes.Length)
                return BadRequest($"number of quotes must be between 0 and {ListOfQuotes.Length}");

            var r = new Random();
            return Ok(ListOfQuotes.OrderBy(_ => r.Next(ListOfQuotes.Length)).Take(count).Select(x => $"{Environment.MachineName}-{x}"));
        }

        private class QuoteList
        {
            public string[] Quotes { get; set;  }
        }
    }
#BUILD PHASE
FROM microsoft/aspnetcore-build:2.0.5-2.1.4-jessie AS build-env
WORKDIR /app
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o out

#RUN PHASE
FROM microsoft/aspnetcore:2.0.5-jessie
WORKDIR /app
COPY --from=build-env /app/out .

ENTRYPOINT ["dotnet", "DockerWebTestApp.dll"]
Now open Google Cloud SDK Shell (for rest of this article we shall be using this only, you can use Bash for Windows, Git Bash, PowerShell or even a CMD shell too). Change directory to your web project's base folder (where the dockerfile is also located). Now create the docker image by executing the following 'docker build' command. You can take a guess why we are choosing a name like 'sanjaysrepo.azurecr.io/quotesgenerator:linux'. Well you guessed it right. We are going to create an Azure Container Repository named 'sanjaysrepo' to push this image in the next step. Also the tag 'linux' is just to identify it. You can leave it blank & default 'latest' tag will be used in that case.
docker build -t sanjaysrepo.azurecr.io/quotesgenerator:linux .
You should be able to see the locally created image now

Publish the image in Azure Container Registry (ACR)

Now we can publish this image (which is still in your local dev box) to some container registry like Docker Hub or Google Cloud or ACR. For this article let's choose ACR. In your open Google cloud shell (or any other) execute the following commands one after another to publish the image to Azure. All these steps are self explanatory.
// Login into your azure subscription
az login 

// Change to proper subscription if you have more than one
az account set --subscription <<subscription id>> 

// Create a resource group called dockerrepo. You can use any existing too as needed
az group create --name dockerrepo --location eastus 

// Create an ACR called 'sanjaysrepo' under the RG
az acr create --resource-group dockerrepo --name sanjaysrepo --sku Basic --admin-enabled true 

// Login into the ACR instance once created
az acr login --name sanjaysrepo

// Push the locally created image to ACR
docker push sanjaysrepo.azurecr.io/quotesgenerator:linux

Create a Kubernetes cluster using AKS in Azure

Let's create a Kubernetes cluster of two VMs in Azure. Please execute the following steps to provision the cluster. 
// Enabling AKS preview for your Azure subscription if not done already. Don't worry about the warning after execution, it's actually done already!
az provider register -n Microsoft.ContainerService

// Create a RG in East US location (many of the azure DCs don't support AKS fully till now, EUS is still the most reliable :))
az group create --name kubernetes --location eastus

// Create the AKS cluster with 2 VM's in the same RG created above. Half of your job is done here :)
az aks create --resource-group kubernetes --name quotesservice --node-count 2 --generate-ssh-keys
The last command is going to take some time obviously :) At the end it should show you a few important details about the cluster as well as the generated SSH keys (with location), The AD App created to generate service principle etc. You should see something like below (click on the images for details).
Congratz, your first AKS linux cluster is deployed. Now lets see how we can communicate with it from my dev machine.

Deploy our application in the cluster

Before we dig into deploying our application, let's take a moment to first understand the deployed cluster & how can we as developers or release managers can communicate with the cluster.
If you now open up your Azure portal you will actually see two resource groups created for you. One is 'kubernetes' as you asked for. But there is another one automatically created by Microsoft called 'MC_kubernetes_quotesservice_eastus' for you. The naming conversion used my Microsoft for the 2nd one seems pretty straight forward. MC most probably stands for 'Managed Cluster', and then your specified RG name, cluster name and at last location to make it unique. If you open up the first RG you will see something like below. It has exactly one resource and it is called 'Container service managed'. This is actually the pointer to the master nodes for Kubernetes, totally managed by Microsoft (like patching, upgrade etc.). You don't have access to the actual Kubernetes control plane or cluster or the master nodes. 


But if you open up the 2nd RG created by Microsoft you should see lots of resources created, like the vnet, node VMs, virtual network interfaces per node, route tables, availability sets, NSG etc. These are the resources you have fully access to. Kubernetes clusters are mainly managed by a command line tool called 'kubectl', that you already installed as a perquisite if you are following till now. So we are going to use this tool to deploy/manager applications/services to these nodes. You also need to understand a bit about YAML file that Kubernetes uses to deploy applications/services. You can read more here.
To make sure 'kubectl' can communicate to our newly created Azure AKS cluster, lets execute the following command that ideally will configure 'kubectl' to communicate to your cluster securely. You should see an output like 'Merged "quotesservice" as current context in C:\Users\sanjayd\.kube\config'.
az aks get-credentials --resource-group kubernetes --name quotesservice
Once this is done, we can now execute any 'kubectl' command to validate the cluster. A few examples below.
Also a few commonly used commands are listed below.
// get all the nodes
kubectl get nodes 
// get cluster component statuses
kubectl get cs 
// get all services
kubectl get svc 
// get all pods
kubectl get pods 
// get all configs
kubectl config view 
// get all latest events
kubectl get events 
// get all deployments
kubectl get deployments 
// get logs from a pod
kubectl logs your-pod-name 
// get details about a pod
kubectl describe pod your-pod-name 
// get details about a node VM
kubectl describe node your-node-name 
// get overall cluster info
kubectl cluster-info 
Now as we are good to talk to out nodes, let's see how we can deploy our docker image in the cluster. As we saw earlier 'cubectl' generally uses YAML file to deploy one or more resources inside a cluster. So lets first create one. In the same solution (or any place you want) add a 'quotes.yaml' file and replace the content below.
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  name: quotes
spec:
  replicas: 1
  strategy:
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  minReadySeconds: 5 
  template:
    metadata:
      labels:
        app: quotes
    spec:
      containers:
      - name: quotes
        image: sanjaysrepo.azurecr.io/quotesgenerator:linux
        ports:
        - containerPort: 80
        resources:
          requests:
            cpu: 250m
          limits:
            cpu: 500m
      imagePullSecrets:
      - name: quotesregistrykey
---
apiVersion: v1
kind: Service
metadata:
  name: quotes
spec:
  type: LoadBalancer
  ports:
  - port: 80
  selector:
    app: quotes
While you can read more about how this works, in short we are creating a template to create a single replica deployment and then a service from that deployment. That deployment we are going to create is going to use an image located at 'sanjaysrepo.azurecr.io/quotesgenerator:linux'. Now to access the image AKS needs a credential. Here we are providing the name of the credential as 'quotesregistrykey'. To create the named credential execute the below command after fetching your ACR's user credentials.
kubectl create secret docker-registry quotesregistrykey --docker-server=https://sanjaysrepo.azurecr.io --docker-username=your-ACR-registry-user-name --docker-password=your-ACR-registry-user-password --docker-email=whatever@whatever.com
Once this is done we are good to deploy our application in the cluster. So lets go back to shell & execute this command
kubectl create -f quotes.yaml
While the service is being created you can watch the status by executing the below command. Wait until a public IP is added in the <EXTERNAL_IP> column (press Ctrl+C to get out of the waiting mode).
kubectl get service quotes --watch

So ideally now Azure is creating two new resources for you, one is a load balancer and another one is a public IP to expose your service over port 80 (specified in the YAML file).
 Once you see that an external IP is assigned, we are done :). Go ahead and try to browse/fiddler the url 'http://<<public-ip>>/api/quotes/12', you should see output with a 200 status.
So we just deployed an instance of our app and its running a single replica as of now (though we have created 2 nodes for our service). If you execute the url from fiddler multiple times you will always see only a single machine name in the output in all the 5 requests that we did below.
So now let's scale up it a bit.

Scale up/down

Easiest way to scale up the instances is to execute the below command
// create 5 replicas of the app/pods
kubectl scale deployment quotes --replicas=5 
// output: deployment "quotes" scaled
Now you can check the deployment & see all 5 instances are up & running (after a few moments)
To verify just go back to fiddler and fetch the same url quickly multiple times. Ideally you should see different machine names now.
Now just for curiosity you can actually use 'kubectl describe pod pod-name' against all 5 pods that we just created & check their distribution among the 2 VM nodes.
Cool! We are almost done. Last few commands for daily uses.
// scale up/down a deployment to create 2 replicas
kubectl scale deployment your-deployment-name --replicas=2 

// delete a deployment
kubectl delete deployments/your-deployment-name 

// delete a service
kubectl delete services/your-service-name 

// increase/scale the actual VM counts
az aks scale --resource-group=kubernetes --name=quotesservice --node-count 3 

// deletes the AKS deployment altogether
az aks delete --name quotesservice --resource-group kubernetes --no-wait

[Optional] Create a public/private SSH key

If you remember we used '--generate-ssh-keys' param as part of 'az aks create' command. To use your own/previously created SSH, you can make use of '--ssh-key-value' param. Here we shall see how easily we can create an SSH key by using Bash for Windows. So first fire up Bash for Windows and navigate to root directory then simply execute the following command. You can provide a path and secret when prompted else just keep pressing enter.
ssh-keygen -t rsa -C "whatever@whatever.com"

Hope we have learnt something about AKS (and a few other stuff :)) today. Let me know if you face any issues or you have any suggestions/questions.

Quick tip before we close. To manage the cluster using a web UP use the following command. This command essentially creates a proxy between your dev machine and the Kubernetes API, and opens a web browser to the Kubernetes Dashboard.
az aks browse --resource-group kubernetes --name quotesservice


SanjayD

Author & Editor

Just another technology enthusiast. Working on various Microsoft technologies for past 11+ years. Started from classic asp and VB and now moved on to Azure & IoT scenarios. Love to explore new ideas & concepts.

4 comments:

  1. Information is very informative also you get same from the author, this is the great resource to get such type of information.

    ReplyDelete
  2. Its very informative blog and useful article thank you for sharing with us , keep posting learn
    .NET Online Course

    ReplyDelete
  3. I am unquestionably making the most of your site. You unquestionably have some extraordinary knowledge and incredible stories. Arinda Managed IT

    ReplyDelete

 
biz.