Locust Experiments — Docker image updates

Karol Brejna
Locust.io experiments
4 min readApr 9, 2019

Some time ago I did an experiment on dockerizing Locust.

Photo by Fancycrave on Unsplash

The results are stored in the following repo: https://github.com/karol-brejna-i/locust-experiments/tree/master/docker-image. The image itself is hosted on docker hub ( https://hub.docker.com/r/grubykarol/locust).

I’ve been using this image in Kubernetes clusters and in my Locust experiments with success.

Recently a new version of Locust was released so I decided to use this as an excuse to refresh the docker image and show information on how to use it.

GitHub repository

I decided to create a dedicated repository for the project. If you visit https://github.com/karol-brejna-i/docker-locust, you’ll notice that the repo is organized so it can maintain many versions of the image.

Tagging “system” was chosen to easily distinguish between the versions. It reflects the directory structure and contains information about all the components of the image: Locust version, Python version, and the OS version.

Folder structure looks like this:

   .
|-- locust version a
| |--- python version x
| | |-- OS version 1
| | `-- OS version 2
| `--- python version y
| |--- OS version 1
| `--- OS version 2
|-- locust version b
...

Where:

  • locust version is a specific version of Locust (i.e. 0.9.0)
  • python version is a specific version of Python (i.e. 3.6)
  • OS version 1 is a specific version of the operating system (i.e. alpine3.9)

For example, for locust 0.10.0 that runs on Python 3.6 on Alpine 3.9 the dockerfile is placed in:

\
|--- 0.10.0
| `-- python3.6
| `-- alpine3.9

The tag for this image will be:

grubykarol/locust:0.10.0-python3.6-alpine3.9

Usage

The image does not include locust scripts during a build. It expects that the scripts will be supplied on runtime by mounting a volume (to /locust path).

This gives the ability to use the exact same image for different deployments. There is no need to build your image that would inherit from this one and only include test scripts (although it’s also possible).

Pulling the image

Pull the latest stable version:

docker pull grubykarol/locust

Or choose Locust, Python and OS (Operating System) version you want and pull and the image that is tagged accordingly:

docker pull grubykarol/locust:0.10.0-python3.6-alpine3.9

Running the image

The image uses the following environment variables to configure its behavior:

In order to run your tests with Locust, you need to provide it with test sources. The image doesn’t any. It assumes the sources will be delivered, for example by mounting as a volume (/locust) during runtime. So, in the simplest case, for a standalone node (with a /usr/scirpts host folder holding locustfile.py), a basic run command could look like this:

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

or, with additional runtime options to run without the UI:

docker run --rm --name standalone \
--hostname standalone \
-e ATTACKED_HOST=http://example.com \
-e "LOCUST_OPTS=--no-web" \
-v /usr/scirpts:/locust grubykarol/locust

For distributed mode, you could run the master with:

docker run --name master --hostname master \
-p 8089:8089 -p 5557:5557 -p 5558:5558 \
-v /usr/scirpts:/locust \
-e ATTACKED_HOST=http://master:8089 \
-e LOCUST_MODE=master \
--rm -d grubykarol/locust

and then some slaves:

docker run --name slave0 \
--link master --env NO_PROXY=master \
-v /usr/scirpts:/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 /usr/scirpts:/locust \
-e ATTACKED_HOST=http://master:8089 \
-e LOCUST_MODE=slave \
-e LOCUST_MASTER=master \
--rm -d grubykarol/locust

Extending the image

In some cases, it would probably be convenient to build a dedicated image. For example, to following dockerfile adds locust scripts and installs some Python dependencies:

FROM grubykarol/locust:0.11.0-python3.6-alpine3.9
COPY locust-scripts /locust
ENV ATTACKED_HOST http://example.com
RUN pip install --no-cache-dir elasticsearch>=6.3.1 redis

After building the image (docker build -t locust/mytests .) you could run it with:

docker run --rm -d -p 8089:8089 locust/mytests

No more need for mounting a volume (the scripts had been added while building the image) and no need to set ATTACKED_HOST (it’s done already in the dockerfile).

Examples

There is a folder in the GitHub repository that contains a few examples of running locust docker images (using Docker Compose). Their goal is to help understand how to use specific settings (environment variables).

They include configurations for:

  • running a standalone node of Locust
  • running distributed Locust cluster
  • running distributed Locust cluster without web UI with timed execution

Conclusions

Locust is a great load/stress testing tool. One of the greatest advantages is that is easy to use. Running it with Docker makes things even easier.

The images that I prepared should work for most (hopefully: all) use cases. Please, let me know if they work/don’t work for you?

Any feedback can help to improve them. And making someone’s life easier, at the same time ;-)

Thank you for our attention!

P.S.

The sources for this article are stored in the following GitHub repo: https://github.com/karol-brejna-i/docker-locust.

Docker images are hosted on docker hub: https://hub.docker.com/r/grubykarol/locust.

ATTOW they include images for Locust 0.8.1, 0.9.0, 0.10.0, 0.11.0 (although I am not sure which versions were officially released ;-) ) for Python 3.6 and Alpine 3.9.

--

--