Home

Awesome


page_type: sample languages:


ATTENTION: This project was archived. Please consider using Azure Load Testing service.

Load Testing Pipeline with JMeter, ACI and Terraform

This project is a load testing pipeline that leverages Apache JMeter as an open source load and performance testing tool and Terraform to dynamically provision and destroy the required infrastructure on Azure.

Key concepts

Architecture

The flow is triggered and controlled by an Azure Pipeline on Azure DevOps. The pipeline contains a set of tasks that are organized logically in SETUP, TEST, RESULTS and TEARDOWN groups.

Task groupTasks
SETUP<li>Check if the JMeter Docker image exists</li><li>Validate the JMX file that contains the JMeter test definition</li><li>Upload JMeter JMX file to Azure Storage Account File Share</li><li>Provision the infrastructure with Terraform</li>
TEST<li>Run JMeter test execution and wait for completion</li>
RESULTS<li>Show JMeter logs</li><li>Get JMeter artifacts (e.g. logs, dashboard)</li><li>Convert JMeter tests result (JTL format) to JUnit format</li><li>Publish JUnit test results to Azure Pipelines</li><li>Publish JMeter artifacts to Azure Pipelines</li>
TEARDOWN<li>Destroy all ephemeral infrastructure with Terraform</li>

On the SETUP phase, JMeter agents are provisioned as Azure Container Instance (ACI) using a custom Docker image on Terraform. Through a Remote Testing approach, JMeter controller is responsible to configure all workers, consolidating all results and generating the resulting artifacts (dashboard, logs, etc).

The infrastructure provisioned by Terraform includes:

On the RESULTS phase, a JMeter Report Dashboard and Tests Results are published in the end of each load testing execution.

Prerequisites

You should have the following tools installed:

You should have the following Azure resources:

Getting Started

1. Importing this repository to Azure DevOps

Log in to Azure through Azure CLI:

az login

NOTE: Make sure you are using the correct subscription. You can use az account show to display what is the current selected one and az account set to change it.

Configure Azure DevOps CLI with your organization/project settings:

ORGANIZATION_URL=https://dev.azure.com/your-organization
PROJECT_NAME=YourProject

az devops configure --defaults organization=$ORGANIZATION_URL project=$PROJECT_NAME

Import this repository on your Azure DevOps project:

REPOSITORY_NAME=jmeter-load-test
REPOSITORY_URL=https://github.com/Azure-Samples/jmeter-aci-terraform

az repos create --name $REPOSITORY_NAME
az repos import create --git-source-url $REPOSITORY_URL --repository $REPOSITORY_NAME

2. Configuring Azure credentials

Create an Azure service principal:

SERVICE_PRINCIPAL_NAME=JMeterServicePrincipal

SERVICE_PRINCIPAL=$(az ad sp create-for-rbac --name $SERVICE_PRINCIPAL_NAME)

Run the following commands to fill the credentials variables:

CLIENT_ID=$(echo $SERVICE_PRINCIPAL | jq -r .appId)
CLIENT_SECRET=$(echo $SERVICE_PRINCIPAL | jq -r .password)
TENANT_ID=$(echo $SERVICE_PRINCIPAL | jq -r .tenant)
SUBSCRIPTION_ID=$(az account show | jq -r .id)
SUBSCRIPTION_NAME=$(az account show | jq -r .name)

Create an Azure service connection on Azure DevOps:

SERVICE_CONNECTION_NAME=JMeterAzureConnection

export AZURE_DEVOPS_EXT_AZURE_RM_SERVICE_PRINCIPAL_KEY=$CLIENT_SECRET

SERVICE_ENDPOINT_ID=$(az devops service-endpoint azurerm create --azure-rm-service-principal-id $CLIENT_ID \
                        --azure-rm-subscription-id $SUBSCRIPTION_ID --azure-rm-subscription-name $SUBSCRIPTION_NAME  \
                        --azure-rm-tenant-id $TENANT_ID --name $SERVICE_CONNECTION_NAME | jq -r .id)

az devops service-endpoint update --id $SERVICE_ENDPOINT_ID --enable-for-all true

3. Creating the Variable Group

Set the following variables according to your Azure Container Registry instance:

ACR_NAME=
ACR_RESOURCE_GROUP=

Run the following commands to create the variable group JMETER_TERRAFORM_SETTINGS on Azure DevOps:

az pipelines variable-group create  --name JMETER_TERRAFORM_SETTINGS --authorize \
                                    --variables TF_VAR_JMETER_ACR_NAME=$ACR_NAME \
                                                TF_VAR_JMETER_ACR_RESOURCE_GROUP_NAME=$ACR_RESOURCE_GROUP \
                                                TF_VAR_JMETER_DOCKER_IMAGE=$ACR_NAME.azurecr.io/jmeter \
                                                AZURE_SERVICE_CONNECTION_NAME="$SERVICE_CONNECTION_NAME" \
                                                AZURE_SUBSCRIPTION_ID=$SUBSCRIPTION_ID

4. Creating and Running the Docker Pipeline

PIPELINE_NAME_DOCKER=jmeter-docker-build

az pipelines create --name $PIPELINE_NAME_DOCKER --repository $REPOSITORY_NAME \
    --repository-type tfsgit --branch main \
    --yml-path pipelines/azure-pipelines.docker.yml

5. Creating the JMeter Pipeline

PIPELINE_NAME_JMETER=jmeter-load-test

az pipelines create --name $PIPELINE_NAME_JMETER --repository $REPOSITORY_NAME \
    --repository-type tfsgit --branch main --skip-first-run \
    --yml-path pipelines/azure-pipelines.load-test.yml

az pipelines variable create --pipeline-name $PIPELINE_NAME_JMETER --name TF_VAR_JMETER_JMX_FILE --allow-override
az pipelines variable create --pipeline-name $PIPELINE_NAME_JMETER --name TF_VAR_JMETER_WORKERS_COUNT --allow-override

6. Updating the JMX test definition (optional)

By default the test uses sample.jmx. This JMX file contains a test definition for performing HTTP requests on azure.microsoft.com endpoint through the 443 port. You can simply update the it with the test definition of your preference.

7. Manually Running the JMeter Pipeline

You can choose the JMeter file you want to run and how many JMeter workers you will need for your test. Then you can run the JMeter pipeline using the CLI:

JMETER_JMX_FILE=sample.jmx
JMETER_WORKERS_COUNT=1

az pipelines run --name $PIPELINE_NAME_JMETER \
                 --variables TF_VAR_JMETER_JMX_FILE=$JMETER_JMX_FILE TF_VAR_JMETER_WORKERS_COUNT=$JMETER_WORKERS_COUNT

Or even use the UI to define variables and Run the pipeline:

ui-run-pipeline

Viewing Test Results

JMeter test results are created in a JTL file (results.jtl) with CSV formatting. A Python script was created to convert JTL to JUnit format and used during the pipeline to have full integration with Azure DevOps test visualization.

Azure DevOps with successful requests

Error messages generated by JMeter for failed HTTP requests can also be seen on Azure DevOps.

Azure DevOps with failed requests

Viewing Artifacts

Some artifacts are published after the test ends. Some of them are a static JMeter Dashboard, logs and others.

pipeline-artifacts

You can also download these build artifacts using az pipelines runs artifact download.

After downloading the dashboard and unzipping it, open dashboard/index.html on your browser:

jmeter-dashboard

Pipeline Configuration

All Terraform parameters can be configured using the Variable Group JMETER_TERRAFORM_SETTINGS. Please read JMeter Pipeline Settings to know more details about it.

Limitations

Additional Documentation

External References

Contributing

This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.

When you submit a pull request, a CLA bot will automatically determine whether you need to provide a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions provided by the bot. You will only need to do this once across all repos using our CLA.

This project has adopted the Microsoft Open Source Code of Conduct. For more information see the Code of Conduct FAQ or contact opencode@microsoft.com with any additional questions or comments.