© The Author(s), under exclusive license to APress Media, LLC, part of Springer Nature 2023
A. Satapathi, A. MishraDeveloping Cloud-Native Solutions with Microsoft Azure and .NET https://doi.org/10.1007/978-1-4842-9004-0_4

4. Building a Microservice Using .NET and Azure Kubernetes Service

Ashirwad Satapathi1   and Abhishek Mishra2
(1)
Gajapati, Odisha, India
(2)
Navi MUmbai, India
 

Microservices-based applications are widely adopted today. You can build a purely distributed application with loosely coupled components. You can manage the design concerns like availability, reliability, scalability, and availability for each application component independently and more efficiently. Development, testing, deployment, and maintenance of the application components become easy. Each application component can be containerized as Docker images and run on a container orchestration platform like Azure Kubernetes Service (AKS).

In this chapter, you will learn how to host a microservices-based application on Azure Kubernetes Service and become familiar with the basics of Azure Kubernetes Service.

In this chapter, we will explore the following topics related to microservices and Azure Kubernetes Service:
  • Introduction to Azure Kubernetes Service and Azure Container Registry

  • Build a microservice using .NET

  • Create Azure Kubernetes Service and an Azure container registry

  • Containerize the microservice and push it to the Azure container registry

  • Run the microservice on Azure Kubernetes Service

After studying this chapter, you will understand the fundamentals of Azure Kubernetes Service and how to host .NET-based microservices on Azure Kubernetes Service.

Let’s start things off with an introduction to Azure Kubernetes Service and Azure Container Registry.

Introduction to Azure Kubernetes Service and Azure Container Registry

You develop and deploy an application across multiple environments, including development, test, user acceptance, and production. Once the application is ready, you host it on a virtual machine or a physical server. Traditionally (prior to containerization), before hosting the application, you install all necessary hosting software and dependencies required by the application to run. You may debug and troubleshoot installation and setup issues while preparing the hosting environment. The entire process takes a reasonable amount of time. You must repeat this process for the other hosting environments and expend the same effort.

With the introduction of containers, you no longer need to set up a hosting environment. Containers make the process much simpler and reusable. Instead, you can package all your application dependencies and hosting software along with the application in a Docker container image, keep it in a container registry, and run the container image in the target environment. You pull the image from the container registry and run it in the target environment. You may externalize configurations based on the environment and keep them in a database or some configuration store.

Managing a single container hosting a single monolith application is easy. You may choose to have multiple containers running application copies and sitting behind a load balancer. If one container crashes, you have other containers to serve the application. However, microservices consist of multiple services each running in a separate container. You may end up having hundreds of containers. You must manage the availability, reliability, security, and other architectural challenges of these services inside the containers. This approach can become challenging. To make life easy here, we have container orchestrators like Docker Swarm and Kubernetes. They orchestrate, manage, monitor, and execute the containers. They guarantee high availability, reliability, fault tolerance, security, and many other architectural concerns.

Kubernetes is a container orchestrator developed by Google. It is one of the most widely used container orchestrators. The Kubernetes cluster has a master node (a.k.a. control plane) that manages and runs containers on the worker nodes. The containers run inside pods in the worker nodes. A worker node can have multiple pods, and a pod usually has a single container. However, in some complex scenarios, you can have a container running as a sidecar along with the application container. You define a Kubernetes manifest that specifies the container images to run and other cluster specifications. You use utilities like kubectl and provide the instruction to the control plane to install the manifest. The control plane interprets the manifest, runs the container, and sets up the cluster based on the information provided in the manifest file.

The control plane consists of the following components:
  • API server

  • Scheduler

  • Controller manager

  • Etcd

You work with the Azure Kubernetes Service using the API server. Once you have the Kubernetes manifest ready, you pass it to the API server. The controller manager gets the Kubernetes manifest from the API server. The scheduler determines the worker nodes on which it can run the pods. The controller manager manages the replication of pods, deployment, and many more such activities. Etcd is a key-value store that can store all the cluster data along with secret values used in the Kubernetes cluster.

The worker nodes consist of the following components:
  • kubelet

  • Pod

  • kube-proxy

The kubelet is a communication agent and facilitates communication between the control plane and the worker nodes. It makes the worker nodes discoverable to the control plane. The Pod runs the container inside it. The kube-proxy takes care of the cluster networking. You usually define replica sets for your pods. A replica set consists of replicas or identical pods running the exact copy of the container. If one replica goes down, the other replicas can serve the requests until another replica is created to replace the failed replica. The pods communicate with each other inside the cluster and with components outside the cluster using services.

The following are the services available in the Kubernetes cluster:
  • Cluster IP

  • Node Port

  • Load Balancer

The pods sitting behind the Cluster IP can communicate within the cluster. They are not accessible by components outside the cluster. Pods behind the Node Port and the Load Balancer can communicate with the external world. The Load Balancer operates on a standard HTTP port, but the Node Port services operate using ports within the range 30000 to 32767.

Setting up a Kubernetes control plane can be tricky sometimes, and you may need days to set it up. To make life easy, cloud vendors offer managed Kubernetes where they create and manage the control plane, and the control plane is abstracted from you. You have no control over the control plane in the case of managed Kubernetes. Azure Kubernetes Service is a managed Kubernetes offering on Azure. You create the control plane and the worker nodes when creating an Azure Kubernetes Service. You can manage the worker nodes but have no control over the control plane.

You build the containers and push them to the container registry. The worker nodes pull the container images from the container registry and run them inside the pods. The container registry can either be a private registry or a public registry. In the case of a private registry, only those with access to the container registry can pull the image. In the case of a public container registry, anyone can pull the image as the access is anonymous. Azure Container Registry is a private container registry on Azure.

Note

You build Kubernetes manifest files that define the Kubernetes cluster’s state and how the application will run in the cluster. The control plane ensures that the cluster state is always maintained as defined in the manifest file. If there are any changes, a pod dies. For example, a new pod gets created to replace the pod that died. You use the kubectl command to deploy this manifest file. If you have a bunch of Kubernetes manifest files, you can package them in a Helm Chart and deploy the Helm Chart.

Build a Microservice Using .NET

Now let’s build a simple Math Microservice with three services, as depicted in Figure 4-1. The Math API receives the user request to perform either an addition or a subtraction action and then sends it to the Add or Subtract API. The Add or Subtract API performs the operation and returns the result to the Math API, and the Math API sends it back to the user.
Figure 4-1

Math Microservice architecture

We’ll build the APIs using Visual Studio. Open Visual Studio and click Create a new project as shown in Figure 4-2.
Figure 4-2

Create a new project

We need to create microservices using ASP.NET Core Web API. Search for Web API and click ASP.NET Core Web API as shown in Figure 4-3.
Figure 4-3

Select ASP.NET Core Web API

Give the project the name MathAPI as shown in Figure 4-4. Click Next. Provide the folder location where you want to create the solution.
Figure 4-4

Provide a project name

We need to containerize the API and run it on the Azure Kubernetes Service Cluster. Ensure you generate the Docker file as shown in Figure 4-5. Click Create. The MathAPI project in the MathAPI solution will get created.
Figure 4-5

Enable Docker support

We need to create two more Web API projects for the Add API and the Subtract API. Right-click the solution in the Solution Explorer, click Add, and then click New Project as shown in Figure 4-6. Create a new Web API project with the name AddAPI.
Figure 4-6

Create Add API

Similarly, create another Web API project and name it SubtractAPI. Ensure you generate the Docker file for both projects while creating them.

Now go to the AddAPI project and add a new controller. Right-click the Controllers folder, click Add, and then click Controller as shown in Figure 4-7.
Figure 4-7

Add a new controller

Select MVC Controller – Empty as shown in Figure 4-8. We will add the controller code later. Name the controller AddController.
Figure 4-8

Add API controller

Replace the code in the AddController.cs file you created with the code in Listing 4-1.
using Microsoft.AspNetCore.Mvc;
namespace AddAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class AddController : Controller
    {
        [HttpGet]
        public int Add(int a, int b)
        {
            return a + b;
        }
    }
}
Listing 4-1

AddController.cs

Now go to the SubtractAPI project and add a new controller named SubtractController. Add the code in Listing 4-2 to the SubtractController.cs file you created.
using Microsoft.AspNetCore.Mvc;
namespace SubtractAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class SubtractController : Controller
    {
        [HttpGet]
        public int Add(int a, int b)
        {
            return a - b;
        }
    }
}
Listing 4-2

SubtractController.cs

Build the solution and make sure that there is no error. Make sure you delete the additional code for the WeatherController generated by default. This makes our codebase look clean. We will work with the MathAPI project once we have deployed the AddAPI and SubtractAPI to the Azure Kubernetes Service. The AddAPI and SubtractAPI should not be accessible from outside the cluster and should be accessible only to the MathAPI. We need the IP address of the ClusterIP service for both the AddAPI and SubtractAPI so that the MathAPI can access these services. So, we need to defer working on the MathAPI once the SubtractAPI and the AddAPI are up and running in the Azure Kubernetes Cluster.

Note

There are better ways to manage the service discovery and ingress using Open Service Mesh (OSM) or Istio. We will configure a ClusterIP for both services to prevent exposing these APIs outside the AKS cluster. However, to keep things simple for first-time learners, we will be accessing the AddAPI and SubtractAPI from the MathAPI using the IP address of their ClusterIP. We will expose the MathAPI to the user using the LoadBalancer service. We will discuss the detailed deployment architecture for the microservices before deploying them to the Azure Kubernetes Service cluster.

Create Azure Kubernetes Service and Azure Container Registry

Let’s go to the Azure portal and create an Azure container registry. We will push the containerized API services here. The Azure Kubernetes Service will pull these images and orchestrate the API services from this container registry. Once you have opened the Azure portal, click Create a resource, as shown in Figure 4-9.
Figure 4-9

Create a resource

You will be navigated to the Azure Marketplace. Click Container Registry in the Containers tab as shown in Figure 4-10. This takes you to the screen where you can provide the basic details for the container registry.
Figure 4-10

Click Container Registry

Provide the subscription details, resource group, registry name, location, and SKU for the container registry in the corresponding fields, as shown in Figure 4-11. We have selected the Basic SKU, which is the cheapest among other available tiers like Standard and Premium. Click Review + create as shown in Figure 4-11.
Figure 4-11

Click Review + create

Click Create as shown in Figure 4-12. Your container registry will get created.
Figure 4-12

Click Create

Now that we have created the container registry, let’s create the Azure Kubernetes Service, where we will run the microservice. Go to the Azure portal and click Create a resource as shown in Figure 4-13.
Figure 4-13

Create a resource

Click Kubernetes Service on the Containers tab as shown in Figure 4-14. You will be navigated to a screen where you can provide the basic details for the Kubernetes Service cluster.
Figure 4-14

Click Kubernetes Service

Provide the subscription details, resource group, cluster name, location, and cluster preset configuration for the Kubernetes Service in the corresponding fields, as shown in Figure 4-15. We have selected the Dev/Test as the cluster preset configuration here, which will save cost for us. The nodes that will get created for us will be virtual machines of lower configuration that are best suited for development and test activities. We need to integrate the Azure container registry we created earlier with the Kubernetes cluster. The pods in the cluster should be able to pull the image from the container registry. You can achieve this in the Integrations tab. Click the Integrations tab.
Figure 4-15

Provide basic cluster details

On the Integrations tab, select the container registry and click Review + create as shown in Figure 4-16.
Figure 4-16

Click Review + create

Click Create as shown in Figure 4-17, and the Azure Kubernetes Service will get created.
Figure 4-17

Click Create

Containerize the Microservice and Push It to the Azure Kubernetes Service

Now let’s containerize the Add API and the Subtract API we created earlier. To follow the steps in this section you should have Docker Desktop installed on your system. Go to the Add API and copy the generated Docker file to the folder where the .NET solution file (.sln) is present, as shown in Figure 4-18.
Figure 4-18

Dockerfile location

As a prerequisite, you should have the Azure command-line interface (CLI) installed. Open the command prompt and execute the command in Listing 4-3 to log in to Azure.
az login
az account set -s "[Provide your Subscription Name or Subscription ID]."
Listing 4-3

Log In to Azure and Select Your Subscription

You will be prompted to provide your credentials as shown in Figure 4-19. Provide the credentials and sign in.
Figure 4-19

Sign in to Azure

To containerize the API, we will use the Azure CLI command to build the image and push it to the Azure container registry. We need not run any Docker command to achieve it. However, as a prerequisite, you should have the Docker desktop installed on your system. Navigate to the .NET solution (.sln) folder in the command prompt where you have copied the Docker file for the Add API. Execute the command shown in Listing 4-4. The Add API will get containerized and pushed to the Azure container registry. In the command, replace acr01mcrsvc with the name of your container registry (acr01mcrsvc is the name of the container registry created earlier in this demonstration).
az acr build -t add:ver01 -r acr01mcrsvc .
Listing 4-4

Containerize and Push Add API

Now we can containerize the Subtract API. Copy the generated Docker file to the folder where the solution file (.sln) is present and execute the command shown in Listing 4-5. The Subtract API will get containerized and pushed to the Azure container registry. In the command, replace acr01mcrsvc with the name of your container registry (again, acr01mcrsvc is the name of the container registry created in this demonstration).
az acr build -t sub:ver01 -r acr01mcrsvc .
Listing 4-5

Containerize and Push Subtract API

You can verify if the images are pushed in the Repositories tab of the Container Registry as shown in Figure 4-20.
Figure 4-20

Add API and Subtract API images in the container registry

We will deal with the Math API later once we have the Add API and the Subtract API running inside the Azure Kubernetes Service Cluster.

Run the Microservice on Azure Kubernetes Service

Now that we have containerized the Add API and the Subtract API, let’s create a Kubernetes manifest file and deploy the Add API. Listing 4-6 depicts the manifest file for Add API. Ensure that you specify the correct container registry and the image name you created. We are adding a service named add, which is a Cluster IP service. The Add API container pod will not be accessible outside the cluster. However, it will be accessible inside the cluster. You can save the manifest file as kubernetes-manifest-add.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
 name: add
 labels:
   app: add
spec:
 selector:
   matchLabels:
     app: add
 replicas: 1
 template:
   metadata:
     labels:
       app: add
   spec:
     containers:
     - name: add
       image: acr01mcrsvc.azurecr.io/add:ver01
       resources:
         requests:
           cpu: 100m
           memory: 100Mi
         limits:
           cpu: 200m
           memory: 200Mi
       ports:
       - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
 name: add
spec:
 ports:
 - port: 80
 selector:
   app: add
---
Listing 4-6

Kubernetes-manifest-add.yaml

Listing 4-7 depicts the manifest file for the Subtract API. You can save the manifest file as kubernetes-manifest-subtract.yaml. Make sure you specify the right container registry and the image name for the Subtract API.
apiVersion: apps/v1
kind: Deployment
metadata:
 name: subtract
 labels:
   app: subtract
spec:
 selector:
   matchLabels:
     app: subtract
 replicas: 1
 template:
   metadata:
     labels:
       app: subtract
   spec:
     containers:
     - name: subtract
       image: acr01mcrsvc.azurecr.io/sub:ver01
       resources:
         requests:
           cpu: 100m
           memory: 100Mi
         limits:
           cpu: 200m
           memory: 200Mi
       ports:
       - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
 name: subtract
spec:
 ports:
 - port: 80
 selector:
   app: subtract
---
Listing 4-7

Kubernetes-manifest-subtract.yaml

Now let’s apply these manifest files to the AKS cluster. Open a command prompt or bash prompt and execute the command shown in Listing 4-8 to log in to Azure. You will be prompted to provide your credentials. Provide the credentials and sign in.
az login
az account set -s "[Provide your Subscription Name or Subscription ID]"
Listing 4-8

Log In to Azure and Select Your Subscription

Execute the command shown in Listing 4-9 to get the Kubernetes cluster credentials locally so that you can access the cluster.
az aks get-credentials -n [Provide AKS Name] -g [Provide Resource Group Name]
Listing 4-9

Get AKS Credentials

Execute the commands shown in Listing 4-10 to apply the Kubernetes manifest files we created to the AKS cluster.
kubectl apply -f kubernetes-manifest-add.yaml
kubectl apply -f kubernetes-manifest-subtract.yaml
Listing 4-10

Apply Kubernetes Manifest to AKS Cluster

Execute the command shown in Listing 4-11 to check if the Add and Subtract pods are running successfully. It may take some time for the pods to transition from Pending to Running state.
kubectl get pods
Listing 4-11

Get Pods

You can see in Figure 4-21 that the add and subtract pods are in the Running state.
Figure 4-21

kubectl get pods

Execute the command shown in Listing 4-12 to get the Cluster IP addresses for the add and subtract pods. We will need this information while creating the Math API. The Math API will access the Add API and Subtract API using these IP addresses.
kubectl get services
Listing 4-12

Get Services

Figure 4-22 depicts the services running in the cluster. You need to copy the CLUSTER-IP values for the add service and the subtract service. We will use it in the Math API .NET controller code.
Figure 4-22

kubectl get services

Now let’s modify the MathAPI project. Create a new controller named MathController.cs. Replace the code in MathController.cs with the code in Listing 4-13. Make sure you replace the IP address in the Add and the Subtract API URL with the cluster IP address of the Add and Subtract API running in the AKS cluster.
using Microsoft.AspNetCore.Mvc;
using System.Net;
using System.Net.Http.Headers;
using System.Text;
namespace MathAPI.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class MathController : Controller
    {
        [HttpGet("Get")]
        public string Get(string ops, int a,int b)
        {
            string result = "";
            string url = "";
            string queryStr = "?a=" + a + "&b=" + b;
            if (ops == "add")
            {
                url = "http://10.0.156.137/add" + queryStr;
            }
            else
            {
                url = "http://10.0.143.214/subtract" + queryStr; ;
            }
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            WebResponse response = request.GetResponse();
            using (Stream responseStream = response.GetResponseStream())
            {
                StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
                result = reader.ReadToEnd();
            }
            return result;
        }
    }
}
Listing 4-13

MathController.cs

Now we can containerize the Math API. Copy the generated Docker file to the folder where the solution file (.sln) is present and execute the command shown in Listing 4-14. The Math API will get containerized and pushed to the Azure container registry. In the command, replace acr01mcrsvc (the name of the container registry created earlier) with the name of your container registry.
az acr build -t math:ver01 -r acr01mcrsvc .
Listing 4-14

Containerize and Push Math API

Listing 4-15 depicts the manifest file for the Math API. Make sure you specify the right container registry and the image name for the Subtract API. You can save the manifest file as kubernetes-manifest-math.yaml.
apiVersion: apps/v1
kind: Deployment
metadata:
 name: math
 labels:
   app: math
spec:
 selector:
   matchLabels:
     app: math
 replicas: 1
 template:
   metadata:
     labels:
       app: math
   spec:
     containers:
     - name: math
       image: acr01mcrsvc.azurecr.io/math:ver01
       resources:
         requests:
           cpu: 100m
           memory: 100Mi
         limits:
           cpu: 200m
           memory: 200Mi
       ports:
       - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
 name: math
spec:
 type: LoadBalancer
 ports:
 - port: 80
 selector:
   app: math
---
Listing 4-15

Kubernetes-manifest-math.yaml

Execute the command shown in Listing 4-16 to apply the Math API Kubernetes manifest file we created to the AKS cluster.
kubectl apply -f kubernetes-manifest-math.yaml
Listing 4-16

Apply Kubernetes Manifest File to AKS Cluster

Now let’s check if the math pod is running. To check the pod state, execute the command shown in Listing 4-17.
kubectl get pods
Listing 4-17

Get Pods

You can see in Figure 4-23 that the add, subtract, and math pods are in the Running state.
Figure 4-23

kubectl get pods

Let’s copy the External-IP address for the Load Balancer service for the Math API. Execute the command shown in Listing 4-18 to list the services in the cluster.
kubectl get services
Listing 4-18

Get Services

Figure 4-24 depicts the services running in the cluster. You need to copy the EXTERNAL-IP value for the math service. We will use it to browse the Math API from the browser. Pods behind the Load Balancer service are exposed outside the cluster.
Figure 4-24

kubectl get service

Now let’s browse the URL as shown in Listing 4-19. Replace [EXTERNAL-IP] with the EXTERNAL-IP address of the math API running in the cluster. We are adding two numbers, 3 and 5.
http://[EXTERNAL-IP]/math/get?ops=add&a=3&b=5
Listing 4-19

Browse Math API for Add Operation

Figure 4-25 depicts the output in the browser. The browser renders the addition result.
Figure 4-25

Add operation output

Now browse the URL as shown in Listing 4-20. Replace [EXTERNAL-IP] with the EXTERNAL-IP address of the math API running in the cluster. We are subtracting two numbers, 3 and 5.
http://[EXTERNAL-IP]/math/get?ops=subtract&a=3&b=5
Listing 4-20

Browse Math API for Subtract Operation

Figure 4-26 depicts the output in the browser. The browser renders the subtract result.
Figure 4-26

Subtract operation output

Summary

In this chapter, you learned the basic concepts of Kubernetes. We explored Azure Kubernetes Service and Azure Container Registry. Then, we created a simple Math microservice and containerized it. We created an Azure container registry and pushed the containerized microservice to it. We created an Azure Kubernetes Service and hosted the microservices containers in its worker nodes.

In the next chapter you will learn how to secure the microservice running inside AKS using Azure AD.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset