page_type: sample languages:
- python products:
- azure-storage extensions: services: Containerinstance name: Load Testing Pipeline with JMeter, ACI and Terraform description: "Azure Pipeline that provisions JMeter on Azure Container Instance using Terraform for load testing scenarios" urlFragment: "jmeter-aci-terraform"
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.
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:
- Resource Group
- Virtual Network (VNet)
- Storage Account File Share
- 1 JMeter controller on ACI
- N JMeter workers on ACI
You should have the following tools installed:
You should have the following Azure resources:
1. Importing this repository to Azure DevOps
Log in to Azure through Azure CLI:
NOTE: Make sure you are using the correct subscription. You can use
az account showto display what is the current selected one and
az account setto 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:
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:
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.
Error messages generated by JMeter for failed HTTP requests can also be seen on Azure DevOps.
Some artifacts are published after the test ends. Some of them are a static JMeter Dashboard, logs and others.
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:
All Terraform parameters can be configured using the Variable Group
JMETER_TERRAFORM_SETTINGS. Please read JMeter Pipeline Settings to know more details about it.
Load Test duration Please note that for Microsoft hosted agents, you can have pipelines that runs up to 1 hour (private project) or 6 hours (public project). You can have your own agents to bypass this limitation.
ACI on VNET regions Please note that not all regions currently support ACI and VNET integration. If you need private JMeter agents, you can deploy it in a different region and use VNET peering between them. Also note that vCPUs and memory limits change based on regions.
- Implementation Notes
- Adding plugins to JMeter Docker image
- JMeter pipeline settings
- Estimating costs
- Integrating with Application Insights
- User Manual: Remote Testing
- User Manual: Apache JMeter Distributed Testing Step-by-step
- Azure DevOps CLI reference
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.