Continuous Deployment with Kubernetes and Load Testing with JMeter

Search for a command to run...

No comments yet. Be the first to comment.
Challenge: Part 1 Continuous integration Set up a new repository and CI pipeline using any code version provider The CI steps should be created. The pipeline should run the following steps: Install dependencies npm install Linter (ESLint) npm run l...
Recentemente, ao ler o livro "Manual de DevOps", me deparei com um capítulo dedicado à telemetria em DevOps que expandiu significativamente minha compreensão sobre o tema. O autor apresenta a telemetria como um pilar fundamental da computação moderna...

Introdução Nos dois últimos artigos publicados, exploramos a auto-instrumentação e a instrumentação utilizando o OpenTelemetry Operator no Kubernetes. Agora, vamos abordar um caso de teste prático usando a instrumentação manual do OpenTelemetry. A p...

Introdução: Anteriormente, realizamos a instrumentação manual da nossa aplicação. Neste artigo, vamos explorar a auto-instrumentação utilizando o OpenTelemetry Operator, uma funcionalidade que simplifica significativamente o processo de instrumentaçã...

Introdução: Vamos começar fazendo a instrumentação de uma aplicação em Python que salva os dados em um banco de dados Postgresql. O que esse tutorial vai abordar: Vou compartilhar a aplicação em Python utilizada Criação do Dockerfile Criação do Do...

OpenTelemetry é uma estrutura (biblioteca) de observabilidade open-source que fornece um conjunto unificado de APIs, SDKs e ferramentas para coletar, processar e exportar dados de telemetria (métricas, logs e traces) de aplicações e serviços. Princip...

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
Azure Devops Account
Cloud Azure Account
Completed Challenge 1. This is a continuation of Series 1. Challenge 1 link: https://hashnode.com/edit/cm795upao000609js5scu0j9u
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
Log in to Azure
Log in to your Azure account via CLI: az login
Create the Kubernetes cluster: az aks create --resource-group projeto-flask --name k8s-cluster --node-count 2 --enable-addons monitoring --generate-ssh-keys
Step 3: Get ACR credentials and create a secret on Kubernetes
Get ACR name: az acr list --query "[].{Name:name, ResourceGroup:resourceGroup}" --output table
Get Docker Server Credential: az acr show --name Your_ACR_Name --query loginServer --output tsv
Get Docker Username: az acr credential show --name Your_ACR_Name --query username --output tsv
Get Docker Password: az acr credential show --name Your_ACR_Name --query passwords[0].value --output tsv
Access your Kubernetes: az aks get-credentials --resource-group Your_Resource_Group_Name --name mdc-aks
Create 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
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.
Access Azure Repo
Go to: assessment-cc-sre-kubernetes-sr-01/codebase/rdicidr-0.1.0
Edit 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
Access Azure Repo
Access the repository on the same place where azure-pipelines.yml and create the file deployment_service.yml
apiVersion: 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
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>
Access Azure Repo
Edit file azure-pipelines.yml
With 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'
Log in to Azure
Log in to your Azure account via CLI: az login
Access your Kubernetes: az aks get-credentials --resource-group Your_Resource_Group_Name --name mdc-aks
Execute the command az get services and access the page with the external IP

