Efficient Microservices Management with Azure DevOps: A Complete Guide
Table of contents
- Prerequisites
- Setting Up the Infrastructure
- Step-by-Step Process:
- Step-01: Create project in Azure DevOps
- Step-02: Clone the Repo in Azure DevOps
- Create/Configure a pipeline in Azure DevOps.
- Step-03: To configure Self-hosted Linux agents in Azure DevOps
- Step 04: Set Up ArgoCD
- Install ArgoCD
- Configure ArgoCD
- Step-05: Clean up the images and container registry using the pipeline.
- Environment Cleanup:
- Conclusion
In the world of DevOps, Continuous Integration (CI) is crucial for automating the testing and deployment of applications. Azure DevOps is a popular platform for managing these tasks. In this technical blog, we will guide you through the steps to migrate a GitHub-based CI pipeline to Azure DevOps, using Docker for containerization and Azure Container Registry (ACR) to store Docker images. This project will help streamline your development workflows by automating the build and push stages, ensuring consistency across different environments.
Prerequisites
Before diving into this project, here are some skills and tools you should be familiar with:
[x] Clone repository for terraform code
Note: Replace resource names and variables as per your requirement in terraform codeGenerate the ssh key in
id_rsa
format.Update
terraform.tfvars
.
[x] Azure Account: You’ll need an Azure account to create resources like virtual Machines, and AKS clusters, and manage pipelines.
[x] Terraform Knowledge: Familiarity with Terraform is needed to set up, manage, and remove infrastructure..
[x] Basic Kubernetes (AKS): A basic understanding of Kubernetes, especially Azure AKS, to deploy and manage containers.
[x] Docker Knowledge: Basic knowledge of Docker for containerizing applications.
[x] GitHub: Experience with GitHub for version control and managing repositories.
[x] Command-Line Tools: Basic comfort with using the command line for managing infrastructure and services.
[x] Basic CI/CD Knowledge: Some understanding of Continuous Integration and Deployment is recommended.
[x] Azure Container Registry (ACR): Set up ACR to store your Docker images.
[x] Linux VM: Docker must be installed on a Linux virtual machine to run containers.
Setting Up the Infrastructure
I have developed Terraform code to set up the entire infrastructure. This includes automatically installing the necessary applications, and tools, and creating the AKS cluster.
Note ⇒ AKS cluster
creation will take approx. 10 to 15 minutes.
⇒ Virtual machines will be created named as
"devopsdemovm"
⇒ Docker Install
⇒ Azure Cli Install
⇒ KubeCtl Install
⇒ AKS Cluster Setup
Virtual Machine creation
First, we'll create the necessary virtual machines using terraform
code.
Below is a terraform Code:
Once you clone repo and run the terraform command.
$ ls -l
Mode LastWriteTime Length Name
---- ------------- ------ ----
dar--l 26/12/24 7:16 PM pipeline
dar--l 23/12/24 3:38 PM scripts
-a---l 25/12/24 2:31 PM 600 .gitignore
-a---l 26/12/24 9:29 PM 6571 EC2.tf
-a---l 26/12/24 9:29 PM 892 main.tf
-a---l 26/12/24 9:29 PM 567 output.tf
-a---l 27/12/24 4:00 PM 26624 Project_Voting Apps.md
-a---l 26/12/24 9:29 PM 269 provider.tf
-a---l 26/12/24 9:30 PM 223 terraform.tfvars
-a---l 26/12/24 9:30 PM 615 variable.tf
You need to run the following terraform command.
Now, run the following command.
terraform init
terraform fmt
terraform validate
terraform plan
terraform apply
# Optional <terraform apply --auto-approve>
After running the Terraform command, we will verify the following to ensure everything is set up correctly using Terraform.
Inspect the Cloud-Init
logs:
Once connected to VM then you can check the status of the user_data
script by inspecting the log files
# Primary log file for cloud-init
sudo tail -f /var/log/cloud-init-output.log
or
sudo cat /var/log/cloud-init-output.log | more
If the user_data script runs successfully, you will see output logs and any errors encountered during execution.
If there’s an error, this log will provide clues about what failed.
Verify the Installation
- [x] Docker version
ubuntu@ip-172-31-95-197:~$ docker --version
Docker version 24.0.7, build 24.0.7-0ubuntu4.1
docker ps -a
ubuntu@ip-172-31-94-25:~$ docker ps
- [x] kubectl version
ubuntu@ip-172-31-89-97:~$ kubectl version
Client Version: v1.31.1
Kustomize Version: v5.4.2
- [x] Azure cli version
azureuser@devopsdemovm:~$ az version
{
"azure-cli": "2.67.0",
"azure-cli-core": "2.67.0",
"azure-cli-telemetry": "1.1.0",
"extensions": {}
}
Step-by-Step Process:
1. Setting up Azure DevOps Pipeline:
Create an Azure DevOps Organization: If you don’t have one already, create a new Azure DevOps organization where your repositories and pipelines will reside.
Set up Agent Pool: Define an agent pool in Azure DevOps, which will handle the execution of your pipelines.
Install Docker on the Agent: Docker needs to be installed on the machine that will run the pipeline. Without Docker, you won’t be able to build or push Docker images.
2. Creating the Pipeline for Build and Push:
Define Pipeline YAML: Write a YAML configuration file to define the pipeline. This file specifies stages like build and push, and Docker is used to automate the creation of images.
Configure Docker Build: In the build stage, Docker is used to build images from your Dockerfile. The push stage uploads these images to the Azure Container Registry (ACR).
Configure Pipeline Triggers: Set up the pipeline to trigger automatically when changes are made in specific directories, like results or worker. This helps in managing microservices by triggering pipelines only for the relevant components.
3. Testing the Pipeline:
Make Changes and Test: After setting up the pipeline, make minor changes to test whether the pipeline triggers as expected. For instance, adding a space to a Dockerfile or modifying a JavaScript file in the results directory should trigger a build for that microservice only.
Verify Docker Image Creation: Ensure the Docker images are being built and pushed to ACR without issues.
Handle Platform-Specific Builds: If the pipeline fails due to architecture issues, ensure the correct platform (Linux/ARM64) is specified in the Dockerfile.
Step-01: Create project in Azure DevOps
Open the Azure UI and DevOps portal
https://dev.azure.com/<name>
Create a new project
Step-02: Clone the Repo in Azure DevOps
Clone the repo ::
click on Imort a repository
Create/Configure a pipeline in Azure DevOps.
Click on Pipeline:
follow the below instruction
It will ask you to log in with your Azure account. Please use the same login credentials that you have set up for the Azure portal.
Select the container registry
Note: Key concept overview of pipeline.
you will see the following pipeline yaml and we have to modify accordingly.
We have to update the CI_pipeline as below
First, we will create a folder in the repo called 'scripts' and update the .sh file as shown below. We will create a shell script to get an updated image tag in case a new image is being created.
Don't forget to update the container registry name in the script file.
Step-03: To configure Self-hosted Linux agents in Azure DevOps
Built the pipeline but I got the below error message
Solution:
Need to configure Self-hosted Linux agents/integrate to Azure DevOps
Select the agent pools name, you can choose any name
devops-demo_vm
run the following command to install the agent.
mkdir myagent && cd myagent
sudo wget https://vstsagentpackage.azureedge.net/agent/4.248.0/vsts-agent-linux-x64-4.248.0.tar.gz
tar zxvf vsts-agent-linux-x64-4.248.0.tar.gz
azureuser@devopsdemovm:~/myagent$ ls -l
total 144072
drwxrwxr-x 26 azureuser azureuser 20480 Nov 13 10:54 bin
-rwxrwxr-x 1 azureuser azureuser 3173 Nov 13 10:45 config.sh
-rwxrwxr-x 1 azureuser azureuser 726 Nov 13 10:45 env.sh
drwxrwxr-x 7 azureuser azureuser 4096 Nov 13 10:46 externals
-rw-rw-r-- 1 azureuser azureuser 9465 Nov 13 10:45 license.html
-rw-rw-r-- 1 azureuser azureuser 3170 Nov 13 10:45 reauth.sh
-rw-rw-r-- 1 azureuser azureuser 2753 Nov 13 10:45 run-docker.sh
-rwxrwxr-x 1 azureuser azureuser 2014 Nov 13 10:45 run.sh
-rw-r--r-- 1 root root 147471638 Nov 13 12:22 vsts-agent-linux-x64-4.248.0.tar.gz
- Configure the agent
~/myagent$ ./config.sh
Type 'Y'
#Server URL
Azure Pipelines: https://dev.azure.com/{your-organization}
https://dev.azure.com/mrbalraj
Need to create a PAT Access Token-
- Go to azure devops user setting and click on PAT.
- Give any name for agent
devops-demo_vm
Agent is still offline.
- We have to Optionally run the agent interactively. If you didn't run as a service above:
~/myagent$ ./run.sh
Now, Agent is online ;-)
Rerun the pipeline and it works.
Rename the pipeline
Will create two more pipeline (microservices).
result
worker
Repository status in Container Registry.
Step 04: Set Up ArgoCD
K8s Cluster login
Argocd install
Configure Argocd
Go Azure UI and select the AKS cluster
Take putty session of Azure VM and perform the following instruction to login into auzre and K8s
- Azure login:
Missing Browser on Headless Servers, Use the --use-device-code flag to authenticate without a browser:
az login --use-device-code
https://microsoft.com/devicelogin Access this URL in a new browser and type the code that you see in cthe onsole.
To list out all the account
az account list --output table
- To get resource details
az aks list --resource-group "resourceGroupName" --output table
[x] Verify the AKS cluster.
To get credentials for AKS
az aks get-credentials --name "Clustername" --resource-group "ResourceGroupName" --overwrite-existing
kubectl config current-context
kubectl get nodes
kubectl get nodes -o wide
Install ArgoCD
kubectl create namespace argocd
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml
Configure ArgoCD
- Run the following commands to verify the
Pods
andservices type
kubectl get pods -n argocd
kubectl get svc -n argocd
- To get details of Pods in namespace "argocd"
kubectl get pods -n argocd
- To get the secrets for argoCd
kubectl get secrets -n argocd
- To get service details in argocd
kubectl get svc -n argocd
azureuser@devopsdemovm:~/myagent$ kubectl get svc -n argocd
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.0.199.83 <none> 7000/TCP,8080/TCP 6m17s
argocd-dex-server ClusterIP 10.0.236.32 <none> 5556/TCP,5557/TCP,5558/TCP 6m17s
argocd-metrics ClusterIP 10.0.231.144 <none> 8082/TCP 6m17s
argocd-notifications-controller-metrics ClusterIP 10.0.54.255 <none> 9001/TCP 6m16s
argocd-redis ClusterIP 10.0.38.40 <none> 6379/TCP 6m16s
argocd-repo-server ClusterIP 10.0.29.153 <none> 8081/TCP,8084/TCP 6m16s
argocd-server ClusterIP 10.0.216.42 <none> 80/TCP,443/TCP 6m16s
argocd-server-metrics ClusterIP 10.0.201.27 <none> 8083/TCP 6m16s
- Currently, it is set to
clusterIP
and we will change it toNodePort
kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "NodePort"}}'
- Review the service again
kubectl get svc -n argocd
azureuser@devopsdemovm:~$ kubectl get svc -n argocd
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.0.98.49 <none> 7000/TCP,8080/TCP 49m
argocd-dex-server ClusterIP 10.0.130.97 <none> 5556/TCP,5557/TCP,5558/TCP 49m
argocd-metrics ClusterIP 10.0.91.113 <none> 8082/TCP 49m
argocd-notifications-controller-metrics ClusterIP 10.0.83.161 <none> 9001/TCP 49m
argocd-redis ClusterIP 10.0.241.99 <none> 6379/TCP 49m
argocd-repo-server ClusterIP 10.0.38.142 <none> 8081/TCP,8084/TCP 49m
argocd-server NodePort 10.0.228.33 <none> 80:32648/TCP,443:31181/TCP 49m
argocd-server-metrics ClusterIP 10.0.124.90 <none> 8083/TCP 49m
- To get URL/IP address details
kubectl get nodes -o wide
azureuser@devopsdemovm:~/myagent$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
aks-agentpool-23873620-vmss000000 Ready <none> 54m v1.30.6 10.224.0.4 <none> Ubuntu 22.04.5 LTS 5.15.0-1075-azure containerd://1.7.23-1
Verify Kubernetes Config: Confirm that the argocd-server service has the correct NodePort
and is not misconfigured:
kubectl describe svc argocd-server -n argocd
azureuser@devopsdemovm:~$ kubectl get svc -n argocd
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
argocd-applicationset-controller ClusterIP 10.0.98.49 <none> 7000/TCP,8080/TCP 2m31s
argocd-dex-server ClusterIP 10.0.130.97 <none> 5556/TCP,5557/TCP,5558/TCP 2m31s
argocd-metrics ClusterIP 10.0.91.113 <none> 8082/TCP 2m31s
argocd-notifications-controller-metrics ClusterIP 10.0.83.161 <none> 9001/TCP 2m31s
argocd-redis ClusterIP 10.0.241.99 <none> 6379/TCP 2m31s
argocd-repo-server ClusterIP 10.0.38.142 <none> 8081/TCP,8084/TCP 2m31s
argocd-server NodePort 10.0.228.33 <none> 80:32648/TCP,443:31181/TCP 2m31s
argocd-server-metrics ClusterIP 10.0.124.90 <none> 8083/TCP 2m31s
azureuser@devopsdemovm:~$ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
aks-system-29381837-vmss000000 Ready <none> 26m v1.30.6 10.224.0.4 52.148.171.58 Ubuntu 22.04.5 LTS 5.15.0-1075-azure containerd://1.7.23-1
Then access it at http://52.148.171.58:32648
.
If page is not opening then we have to open a port in NSG.
On the Azure portal, go to the server with
VMSS
and select theVMSS
.
Now, we need to try to access it again http://PublicIPAddress:32648
.
- To retrive the password for argocd
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -d; echo
- To configure repo in argocd with token base.
(http://PublicIPAddress:32648)
Go to azure pipeline and click on setting and select "Personal Access Token"
https://<Accesstoken>@dev.azure.com/mrbalraj/balraj-devops/_git/balraj-devops
To create a application in argocd Once you access the ArgoCD URL and create an application
Application Name: vote-access-service
Project Name: default
Sync Policy: Automatic (Select Prune Resources and SelfHeal)
Repository URL: https://mrbalraj@dev.azure.com/mrbalraj/balraj-devops/_git/balraj-devops
Revision: main
Path: k8s-specifications (where Kubernetes files reside)
cluster URL: Select the default cluster
Namespace: default
by default 3 min to sync with argocd but it can be changed as below.
- Now, we will change the argocd default time (3 min) to 10 sec.
kubectl edit cm argocd-cm -n argocd
edit as below
Now, try to get all resources, and you will notice there is an error related to ImagePullBackoff
.
kubectl get all
I am getting the below error message.
Solution: As we are using private registory and we need to use 'imagepullsecrets'
Go to the Azure registry and get the password, which will be used in the command below.
- command to create
ACRImagePullSecret
kubectl create secret docker-registry <secret-name> \
--namespace <namespace> \
--docker-server=<container-registry-name>.azurecr.io \
--docker-username=<service-principal-ID> \
--docker-password=<service-principal-password>
Explanation of the Command:
kubectl create secret docker-registry:
- This creates a new Kubernetes secret of type docker-registry.
<secret-name>:
- The name of the secret being created. For example, acr-credentials.
--namespace <namespace>:
- Specifies the namespace in which the secret will be created. If omitted, it defaults to the default namespace.
Replace <namespace> with the desired namespace name.
--docker-server=<container-registry-name>.azurecr.io:
- The URL of your container registry. For Azure Container Registry (ACR), the format is <container-registry-name>.azurecr.io.
Replace <container-registry-name> with your ACR name.
--docker-username=<service-principal-ID>:
- The username to authenticate with the container registry. For Azure, this is typically a service principal's application (client) ID.
--docker-password=<service-principal-password>:
- The password (or secret) associated with the service principal used for authentication.
To get token, click on container registory
kubectl create secret docker-registry acr-credentials \
--namespace default \
--docker-server=aconregee7b05ba.azurecr.io \
--docker-username=aconregee7b05ba \
--docker-password=<token>
- Command to delete
secret
kubectl delete secret acr-credential --namespace default
now, we will update the vote-deployment.yaml as below:
Need to update in all other deployment as below:
here is the updated service status
Try updating anything in the vote folder in "
app.py
"
as shown below, and the pipeline should automatically trigger.
- To check the deployment
kubectl get deploy vote -o yaml
- Verify services and try to access the application
kubectl get svc
kubectl get node -o wide
kubectl describe svc argocd-server -n argocd
Now, we will open one more port in VMSS
Vote application is accessible now.
Congratulations :-) the application is working and accessible.
Step-05: Clean up the images and container registry using the pipeline.
First create Service Connection in Azure Devops.
Once you create a connection then note it down the connection ID, because that ID would be used in pipeline.
On agent machine, make sure login with azure login and connection is active, if not then login with following.
az login --use-device-code
Delete all the images along with repogitory.
Delete all images from result-app
Delete all images from vote-app
Delete all images from worker-app
Environment Cleanup:
As we are using Terraform, we will use the following command to delete
Delete all deployment/Service first
kubectl delete service/redis kubectl delete service/db kubectl delete service/resut kubectl delete service/result kubectl delete service/vote kubectl delete deployment.apps/db kubectl delete deployment.apps/redis kubectl delete deployment.apps/vote kubectl delete deployment.apps/worker kubectl delete deployment.apps/db kubectl delete deployment.apps/result kubectl delete service/db
Now, time to delete the AKS Cluster and Virtual machine
.
run the terraform command.
Terraform destroy --auto-approve
Conclusion
Migrating CI pipelines from GitHub to Azure DevOps can significantly improve your development process by automating the build and deployment stages. This blog covered the step-by-step process of setting up an Azure DevOps pipeline to build Docker images and push them to Azure Container Registry. It also provided insights into handling pipeline triggers for different microservices, ensuring that the correct pipelines run when changes are made. By adopting this approach, you’ll streamline your CI workflows and enhance your development productivity.
Ref Link: