Continuous Deployment with Kubernetes and Load Testing with JMeter

Challenge: Part 2 Continuous Deployment and Load Testing
Deploy the provided application to your chosen cloud provider using any service that runs the application as a Docker container. Then, create a test plan for the application's home page and generate a testing report using JMeter.
The application needs to:
Available for anyone with Internet access only during the challenge recording
Prerequisites
Azure Devops Account
Cloud Azure Account
Completed Challenge 1. This is a continuation of Series 1. Challenge 1 link: https://hashnode.com/edit/cm795upao000609js5scu0j9u
Step 1: Create Azure Container Registry and Azure Devops Connections
Create Azure Registry:
Go to the Azure portal.
Create a new resource group.
Click on "Container registries".
Click on "Create container registry".
On the "Create container registry" page, enter the following information:
Registry name - Enter mdcregistryID. # The name needs to be unique change the last two letters by the initials of your name
Region - Select the region where you want to create your registry.
Pricing tier - Select the pricing tier that you want to use for your registry.
Security - Select the security options that you want to use for your registry.
Choose the Resource Group you created earlier
Azure Devops Connections:
Navigate to Azure DevOps Service Connections
Sign in to Azure DevOps.
Select your organization and project.
In the left sidebar, go to Project Settings.
Under Pipelines, click Service Connections.
Click New Service Connection.
Choose Docker Registry
Authentication Type Select Service Principal
Enter your settings and click create
Step 2: Create Kubernetes
Log in to Azure
Log in to your Azure account via CLI:
az loginCreate the Kubernetes cluster:
az aks create --resource-group projeto-flask --name k8s-cluster --node-count 2 --enable-addons monitoring --generate-ssh-keysStep 3: Get ACR credentials and create a secret on Kubernetes
Get ACR name:
az acr list --query "[].{Name:name, ResourceGroup:resourceGroup}" --output tableGet Docker Server Credential:
az acr show --name Your_ACR_Name --query loginServer --output tsvGet Docker Username:
az acr credential show --name Your_ACR_Name --query username --output tsvGet Docker Password:
az acr credential show --name Your_ACR_Name --query passwords[0].value --output tsvAccess your Kubernetes:
az aks get-credentials --resource-group Your_Resource_Group_Name --name mdc-aksCreate Secret:
kubectl create secret docker-registry acr-secret \ --docker-server=Your_Docker_Server \ --docker-username=Your_Docker_Username \ --docker-password=Your_Docker_Password \Configure Assign AcrPull Role:
ACR_ID=$(az acr show --name mdcrepositorychiroli --query "id" -o tsv) AKS_ID=$(az aks show --resource-group projeto-flask --name k8scluster --query "identityProfile.kubeletidentity.objectId" -o tsv) az role assignment create --assignee $AKS_ID --role AcrPull --scope $ACR_ID
Step 4: Create Azure Resource Manager on Connections
Navigate to Azure DevOps Service Connections
Sign in to Azure DevOps.
Select your organization and project.
In the left sidebar, go to Project Settings.
Under Pipelines, click Service Connections.
Click New Service Connection.
Choose Azure Resource Manager
Enter your settings, you can use the default setting and click create.
Step 5: Create Dockerfile
Access Azure Repo
Go to:
assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0Edit Dockerfile
# Etapa de build
FROM node:15 AS builder
# Define o diretório de trabalho
WORKDIR /app
# Copia os arquivos necessários
COPY package.json package-lock.json ./
# Instala dependências
RUN npm install
# Copia o restante dos arquivos da aplicação
COPY . .
# Faz o build da aplicação (se necessário)
RUN npm run build
# Etapa de produção
FROM node:15
# Define o diretório de trabalho
WORKDIR /app
# Copia arquivos do estágio anterior
COPY --from=builder /app /app
# Instala as dependências de produção
RUN npm install --only=production
# Define o comando para iniciar a aplicação
CMD ["npm", "start"]
# Exposição de porta (opcional)
EXPOSE 3000
Step 6: Create Deployment and Load Balancer
Access Azure Repo
Access the repository on the same place where azure-pipelines.yml and create the file
deployment_service.ymlapiVersion: apps/v1 kind: Deployment metadata: name: nodejs-deployment spec: replicas: 1 selector: matchLabels: app: nodejs template: metadata: name: nodejs labels: app: nodejs spec: containers: - name: nodejsapp image: mdcrepositorychiroli.azurecr.io/node.js:latest ports: - containerPort: 3000 imagePullSecrets: - name: acr-secret --- apiVersion: v1 kind: Service metadata: name: nodejs-service labels: app: nodejs spec: type: LoadBalancer selector: app: nodejs ports: - port: 3000 targetPort: 3000
Step 7: Create a file for the Jmeter test
Access Azure Repo
Access the repository on the same place where azure-pipelines.yml and create the file
test.jmx<?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.6.3"> <hashTree> <!-- Test Plan --> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Basic Test Plan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> </TestPlan> <hashTree> <!-- Thread Group --> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Load Test Group" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <!-- Adicionando o Loop Controller --> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControllerGui" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <stringProp name="LoopController.loops">1</stringProp> </elementProp> <stringProp name="ThreadGroup.num_threads">10</stringProp> <stringProp name="ThreadGroup.ramp_time">5</stringProp> <boolProp name="ThreadGroup.scheduler">false</boolProp> </ThreadGroup> <hashTree> <!-- HTTP Sampler --> <HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy" testname="HTTP Request" enabled="true"> <stringProp name="HTTPSampler.domain">${__P(host, localhost)}</stringProp> <stringProp name="HTTPSampler.port">3000</stringProp> <stringProp name="HTTPSampler.protocol">http</stringProp> <stringProp name="HTTPSampler.path">/</stringProp> <stringProp name="HTTPSampler.method">GET</stringProp> </HTTPSamplerProxy> <hashTree/> </hashTree> </hashTree> </hashTree> </jmeterTestPlan>
Step 7: Configure the Pipeline
Access Azure Repo
Edit file
azure-pipelines.ymlWith the new configuration and the configuration of the last challenge the pipeline looks like this:
trigger:
- main
pr:
branches:
include:
- main
stages:
- stage: BuildAndTest
displayName: Build and Test Job
pool:
vmImage: 'ubuntu-latest'
jobs:
- job: Build
displayName: 'Build and Test Job'
steps:
- checkout: self
path: 'src'
displayName: 'Checkout code'
- task: UseNode@1
inputs:
version: '15.x'
displayName: 'Install Node.js'
- script: npm install
workingDirectory: $(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
displayName: 'Install dependencies'
- script: npm run lint
workingDirectory: $(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
displayName: 'Linter (ESLint)'
- script: npm install --save-dev prettier
workingDirectory: $(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
displayName: 'Install Formatter (Prettier)'
- script: npm run prettier -- --write
workingDirectory: $(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
displayName: 'Format Code (Prettier)'
- script: CI=true npm run test
workingDirectory: $(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
displayName: 'Test (Jest)'
- script: npm run build
workingDirectory: $(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
displayName: 'Run Build'
- task: Docker@2
inputs:
containerRegistry: 'MdcRegistry'
repository: 'Node.js'
command: 'buildAndPush'
Dockerfile: '$(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0/Dockerfile'
buildContext: '$(Build.SourcesDirectory)/assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0'
tags: 'latest'
displayName: 'Build and Push Docker Image'
continueOnError: true
- task: AzureCLI@2
inputs:
azureSubscription: 'MdcAzureRm'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
az aks get-credentials --resource-group projeto-flask --name k8scluster --overwrite-existing
kubectl apply -f $(Build.SourcesDirectory)/deployment_service.yml
kubectl get services
displayName: 'Execute Kubernetes'
continueOnError: true
- script: |
echo "Installing JMeter..."
sudo apt-get update -y
sudo apt-get install -y wget openjdk-11-jre # Install Java and wget
wget https://downloads.apache.org//jmeter/binaries/apache-jmeter-5.6.3.tgz
tar -xvzf apache-jmeter-5.6.3.tgz
sudo mv apache-jmeter-5.6.3 /opt/jmeter
# Adiciona JMeter ao PATH corretamente
echo "export PATH=/opt/jmeter/bin:\$PATH" | sudo tee -a /etc/profile
export PATH=/opt/jmeter/bin:$PATH # Atualiza PATH na sessão atual
echo "JMeter installed successfully."
displayName: 'Install JMeter'
- script: |
echo "Creating JMeter test file..."
cp $(Build.SourcesDirectory)/test.jmx /opt/jmeter/test.jmx
displayName: 'Create JMeter Test File'
- task: AzureCLI@2
inputs:
azureSubscription: 'MdcAzureRm'
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
NODEJS_IP=$(kubectl get svc nodejs-service -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo "##vso[task.setvariable variable=NODEJS_IP]$NODEJS_IP"
echo "Fetched IP: $NODEJS_IP"
displayName: 'Retrieve NodeJS Service External IP'
continueOnError: true
- script: |
export PATH=/opt/jmeter/bin:$PATH
jmeter -v
jmeter -n -t /opt/jmeter/test.jmx -l /opt/jmeter/results.jtl -j jmeter.log -Jhost=$NODEJS_IP
cat /opt/jmeter/results.jtl
cat jmeter.log
displayName: 'Run JMeter'
Step 8: Access the application
Log in to Azure
Log in to your Azure account via CLI:
az loginAccess your Kubernetes:
az aks get-credentials --resource-group Your_Resource_Group_Name --name mdc-aksExecute the command
az get servicesand access the page with the external IP

Step 8: See the Jmeter test results





