Building micro services through Event Driven Architecture part23 : Azure Kubernetes Services

Building micro services through Event Driven Architecture part23 : Azure Kubernetes Services

This tutorial is the 23th part of a series : Building microservices through Event Driven Architecture.

Azure Kubernetes Service (AKS) manages your hosted Kubernetes environment and makes it simple to deploy and manage containerized applications in Azure. Your AKS environment is enabled with features such as automated updates, self-healing, and easy scaling. The Kubernetes cluster master is managed by Azure and is free. You manage the agent nodes in the cluster and only pay for the VMs on which your nodes run.

To learn more about azure kubernetes services, you can follow this link : https://learn.microsoft.com/en-us/training/modules/intro-to-azure-kubernetes-service/

In this tutorial I will use  terraform to deploy an azure azure kubernetes services cluster , an azure sql database with private endpoint and an azure container registry

Deploy infrastructure

To enable kubernetes, I just need to download and install docker for desktop and activate it

Workflow

  1. The web application gateway receives an HTTP request from the internet and should requires an API call to the Azure SQL Database.

  2. The web api connects to the virtual network through a virtual interface mounted in the aksSubnet of the virtual network LogCorner.EduSync.Speech.Vnet
  3. Azure Private Link sets up a private endpoint for the Azure SQL Database in the databaseSubnet of the virtual network.

  4. The web api sends a query for the IP address of the Azure SQL Database. The query traverses the virtual interface in the aksSubnet. The CNAME of the Azure SQL Database directs the query to the private DNS zone. The private DNS zone returns the private IP address of the private endpoint set up for the Azure SQL Database.

  5. The web api connects to the Azure SQL Database through the private endpoint in the databaseSubnet.

  6. The Azure SQL Database firewall allows only traffic coming from the databaseSubnet to connect. The database is inaccessible from the public internet.

Components

This scenario uses the following Azure services:

  • Azure Web Application Gateway distribute incoming traffic across the kubernetes cluster ensuring high availability and scalability

  • Azure kubernetes services : hosts web api, allowing autoscale and high availability without having to manage infrastructure.  for now the ask cluster have a public ip address and I will disable it on upcoming tutorials
  • Azure container registry : hosts docker images deployed in the kubernetes cluster. for now the azure container registry have  public access and I will disable it on upcoming tutorials
  • Azure SQL Database is a general-purpose relational database managed service that supports relational data, spatial data, JSON, and XML.

  • Azure Virtual Network is the fundamental building block for private networks in Azure. Azure resources like virtual machines (VMs) can securely communicate with each other, the internet, and on-premises networks through Virtual Networks.

  • Azure Private Link provides a private endpoint in a Virtual Network for connectivity to Azure PaaS services like Azure Storage and SQL Database, or to customer or partner services.

  • Azure DNS hosts private DNS zones that provide a reliable, secure DNS service to manage and resolve domain names in a virtual network without the need to add a custom DNS solution.

  • Azure virtual machine : used to connect and manage sql server database through the private endpoint  
  • Azure bastion Host : used to connect securely to the azure virtual machine 

The terraform files to deploy the infrastrcuture can be found here : .\LogCorner.EduSync.Speech.Command\iac

#terraform init is a command used to initialize a new or existing Terraform working directory. This command is typically run at the beginning of a new project, or when you want to update the provider plugins used by an existing project.

terraform init

#terraform plan is a command used to create an execution plan for a Terraform configuration. This command will show you what changes Terraform will make to your infrastructure based on the current configuration. The -var-file flag is used to specify a file containing input variables for the configuration.

terraform plan -var-file="dev.tfvars"

# terraform apply is a command used to apply the changes defined in a Terraform configuration to your infrastructure. This command will create or update any resources necessary to bring your infrastructure in line with the desired state defined in your configuration.

terraform apply -var-file="dev.tfvars" --auto-approve

Build docker images

To deploy application in kubernetes, we need to dockerize the application and build docker image.

So, you can run the following command to build the images, locate the docker-compose.yml file under (\LogCorner.EduSync.Speech.Command\src)

# Build the images using my docker-compose.yml file
docker-compose build

The build will produce 2 images : logcornerhub/logcorner-edusync-speech-command  and logcornerhub/logcorner-edusync-speech-mssql-tools

for deployment to azure kubernetes services, i will not use logcornerhub/logcorner-edusync-speech-mssql-tools image because i will deploy to azure sql database

Tag and push image to azure container registry

# define variables
$resourceGroupName ="LOGCORNER.EDUSYNC.SPEECH.RG"
$azureContainerRegistryName ="logcorneredusyncregistry"
$subscriptionId="{{your_azure_subscriptionId}}"

# login to azure using az login or service principal
az login
az account set --subscription $subscriptionId

# login to the azurecontainer registry
az acr login --name $azureContainerRegistryName

# tag
docker tag logcornerhub/logcorner-edusync-speech-command  "$azureContainerRegistryName.azurecr.io/logcorner-edusync-speech-command:1.0.0"

# push 
docker push "$azureContainerRegistryName.azurecr.io/logcorner-edusync-speech-command:1.0.0"

Build kubernetes configuration files

login to your azure account and set your Azure default Subscription

az login 
az account set --name [your subscriptionId ou subscriptionName ]

in ths tutorial, I will use docker-desktop and enable kubernetes.

If you have many kubernetes clusters in your kubeconfig file, please run the following commands to use docker-desktop as your default kubernetes cluster.

# Define variables
$resourceGroupName ="LOGCORNER.EDUSYNC.SPEECH.RG"
$aksName="LogCornerEduSyncSpeechCluster"
# Get the kubeconfig to log into the cluster
az aks get-credentials  --resource-group $resourceGroupName   --name $aksName
# set context
kubectl config get-contexts 
kubectl config use-context  $aksName
kubectl cluster-info

Deploy api configuration files


inside folder \LogCorner.EduSync.Speech.Command\kubernetes\aks\CommandApi  you can find the kubernetes configuration files of the command http api : the deployment configuration file and the service configuration file
# deploy configuration files from CommandApi folder
kubectl apply -f command-api-deployment.yml
# get all pods
kubectl get pods

kubectl apply -f command-api-service.yml
# get all services
kubectl get services

Note the service load balancer public ip (20.23.189.10) I will need it to test the web api : http://52.137.56.112/swagger/index.html

Setup sql server database

To setup the sql server database, I should connect to the bastion visrtual machine deployed on management. Note that I can connect to the database using a virtual machine that can reach the SQL Server using its private endpoint.

Dowload and install a tool to help me for managing and administering SQL Server databases like SQL Server Management Studio (SSMS) that i can found here : https://learn.microsoft.com/en-us/sql/ssms/download-sql-server-management-studio-ssms?view=sql-server-ver16

you can aslo use your another tool : azure data studio, etc…

Connect to the database and run the scripts to create the database schema.

you can find the scripts inside the github repository folder : .\LogCorner.EduSync.Speech.Command\src\LogCorner.EduSync.Speech.Database\dbo\Tables

USE LogCorner.EduSync.Speech.Database
GO
CREATE TABLE [dbo].[EventStore] (
    [Id]          INT              IDENTITY (1, 1) NOT NULL,
    [Version]     BIGINT           NOT NULL,
    [AggregateId] UNIQUEIDENTIFIER NOT NULL,
    [Name]        NVARCHAR (250)   NOT NULL,
    [TypeName]    NVARCHAR (250)   NOT NULL,
    [OccurredOn]  DATETIME         NOT NULL,
    [PayLoad]     TEXT             NOT NULL,
    CONSTRAINT [PK__EventStore] PRIMARY KEY CLUSTERED ([Id] ASC)
);


GO
PRINT N'Creating Table [dbo].[MediaFile]...';


GO
CREATE TABLE [dbo].[MediaFile] (
    [ID]       UNIQUEIDENTIFIER NOT NULL,
    [Url]      NVARCHAR (250)   NULL,
    [SpeechID] UNIQUEIDENTIFIER NOT NULL,
    PRIMARY KEY CLUSTERED ([ID] ASC)
);


GO
PRINT N'Creating Table [dbo].[Speech]...';


GO
CREATE TABLE [dbo].[Speech] (
    [ID]          UNIQUEIDENTIFIER NOT NULL,
    [Title]       NVARCHAR (250)   NOT NULL,
    [Description] NVARCHAR (MAX)   NOT NULL,
    [Url]         NVARCHAR (250)   NOT NULL,
    [Type]        INT              NOT NULL,
    [IsDeleted]   BIT              NULL,
    CONSTRAINT [PK_Presentation] PRIMARY KEY CLUSTERED ([ID] ASC)
);


GO
PRINT N'Creating Default Constraint unnamed constraint on [dbo].[Speech]...';


GO
ALTER TABLE [dbo].[Speech]
    ADD DEFAULT (newid()) FOR [ID];


GO
PRINT N'Creating Default Constraint unnamed constraint on [dbo].[Speech]...';


GO
ALTER TABLE [dbo].[Speech]
    ADD DEFAULT ((1)) FOR [Type];


GO
PRINT N'Creating Default Constraint unnamed constraint on [dbo].[Speech]...';


GO
ALTER TABLE [dbo].[Speech]
    ADD DEFAULT ((0)) FOR [IsDeleted];


GO
PRINT N'Creating Foreign Key [dbo].[FK_MediaFile_Speech]...';


GO
ALTER TABLE [dbo].[MediaFile]
    ADD CONSTRAINT [FK_MediaFile_Speech] FOREIGN KEY ([SpeechID]) REFERENCES [dbo].[Speech] ([ID]);

GO

Test api deployment

Open a browser, http://20.23.189.10/swagger/index.html where 20.23.189.10 is the public ip address of the service . you can get it by running kubectl get services :

speech-command-http-api-service LoadBalancer 10.4.4.36 20.23.189.10 80:30155/TCP,443:30171/TCP

Create a post request (/api/speech), the body of the post request should look like this :

http://localhost:30124/swagger/index.html
{
  "title": "this is a title",
  "description": "Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.",
  "url": "http://test.com",
  "typeId": 1
}

We should have a new record in the database

Code source is available here : 

Thanks for reading, if you have any feedback, feel free to post it

Support us

BMC logoBuy me a coffee