Locust.io experiments — running in Docker

Karol Brejna
Locust.io experiments
4 min readDec 20, 2017

Containerizing Locust makes the development of load test easier and — which is more important to me — is a precondition to run Locust on Kubernetes cluster. So, let’s deal with this right at the beginning.

Word of caution

Before we start for good, let me give you a word of warning that applies to a whole series of the following posts in this series.

You may encounter things that you may find disturbing or even horrifying. OK, let’s spit it out: for coding and running most of the experiments I am using Windows. I don’t remember how it exactly started, but now it became kind of exercise in patience (my colleagues who observe my struggle call it a penance), mortification or self-flagellation. Never mind the reason, you will find some Windows-specific commands, terminal screenshots and similar eyesore images.

You’ve been warned, so let’s continue.

Preparing docker image

For me, one of the biggest advantages of using Docker is that Your application and all its dependencies can be bundled into a single container. This container can be moved to some other machine and executed regardless underlying host OS distribution or version (assuming it can run Docker).

Also, I am planning to have a scalable deployment of Locust. For that purpose, I will use Kubernetes, which in turn utilizes Docker containers. The basic prerequisite for achieving that goal, then, will be having a docker image definition for Locust.

So, here is what my requirements for the image are. I want it to:

  • use Python 3
  • use the latest version of Locust
  • be as small as possible
  • be simple to use
  • take Locust scripts by means of mounting a volume

I did a quick research and most of the images found on docker hub are old (1–2 yo) so I decided to give it a try myself.

After some investigation, it turned out that Locust has some run-time dependencies (libraries that need to be present in order for it to run properly), and dependencies required only for building/installing Locust.

The simple plan for creating the image is to use small python image as a baseline, add the dependencies and — after installation completes — get rid of anything that is not required at run-time. Then execute a script that starts Locust.

Here is the initial attempt on the Dockerfile:

And the start script:

In order to build the image the following command could be used:

docker build -t grubykarol/locust:latest .

Running the image

Before we continue, there are three things to mention.

First, you can run Locust in the following modes:

  • standalone — single node “cluster”, where the instance plays both the role of the master and the worker (single Locust instance is responsible for running load tests)
  • distributed — where master controls the behavior of the workers, collects the results and workers (or, in other words, slaves ) do the actual job of generating the load. In this mode, you’ll need one master and one or more slaves

Second, a “prescription” of what to test and how to do this needs to be supplied to the Locust cluster (via so-called locustfile; see https://docs.locust.io/en/latest/writing-a-locustfile.html).

Third, you need to indicate which website/host you are going to test against.

So, let’s go on and see how these are addressed with the dockerfile I am proposing.

You influence the behavior of Docker containers (defined by this docker image) with environment variables.

You can set desired run mode (standalone, master, slave) using LOCUST_MODE variable. The host that is being tested is set through ATTACKED_HOST variable.

As far as the “prescription” is concerned, the image assumes that the test scripts will be supplied on run-time. In other words, when you run the image, you mount a volume (to /locust path) that holds the files describing the test.

The full list of environment variables to adjust Locust configuration is presented below:

Example run-time configurations are presented below.

Example run-time configurations

Let’s run some actual docker containers.

I’ll use the following locustfile. It is supposed to be simple, so it just makes requests against Locust web interface itself.

Let’s assume it is stored on the host machine in a known location (c:\locust-scripts for the following examples).

Issuing the following command (in PowerShell):

docker run --rm --name standalone --hostname standalone `
-e ATTACKED_HOST=http://standalone:8089 `
-v c:\locust-scripts:/locust `
-p 8089:8089 -d `
grubykarol/locust

will start Standalone Locust node:

For distributed mode, you can run the master:

docker run --name master --hostname master `
-p 8089:8089 -p 5557:5557 -p 5558:5558 `
-v c:\locust-scripts:/locust `
-e ATTACKED_HOST='http://master:8089' `
-e LOCUST_MODE=master `
--rm -d grubykarol/locust

and then a couple of slaves:

docker run --name slave0 `
--link master --env NO_PROXY=master `
-v c:\locust-scripts:/locust `
-e ATTACKED_HOST=http://master:8089 `
-e LOCUST_MODE=slave `
-e LOCUST_MASTER=master `
--rm -d grubykarol/locust
docker run --name slave1 `
--link master --env NO_PROXY=master `
-v c:\locust-scripts:/locust `
-e ATTACKED_HOST=http://master:8089 `
-e LOCUST_MODE=slave `
-e LOCUST_MASTER=master `
--rm -d grubykarol/locust

If everything goes well (which it should) you’ll see you Locust cluster up and running:

In conclusion

It looks like we got ourselves a simple, light (~124MB) docker image for Locust.

The source files for this experiment are stored on GitHub (tagged: https://github.com/karol-brejna-i/locust-experiments/releases/tag/dockerfile).

The image is also published on Docker Hub. ATTOW the latest version of the image is 0.8.1-py3.6.

Edit

As it turned out, this article has quite a few views/reads.

I decided to update the docker image for the newer versions of Locust, Python, and Alpine. I moved the sources to a dedicated GitHub repo: https://github.com/karol-brejna-i/docker-locust

You’ll find some information here: https://medium.com/locust-io-experiments/locust-experiments-docker-image-updates-c7576e410efa

--

--