Skip to content
This repository was archived by the owner on Feb 2, 2026. It is now read-only.

Commit bb32023

Browse files
authored
version updates, and locust example task refresh (#38)
add script to start web application proxy instance add source code embed tags for docs updsate README, remove content and encourage readers to visit guide split server into ClusterIP and LoadBalancer for different ports
1 parent 3058106 commit bb32023

12 files changed

Lines changed: 127 additions & 168 deletions

File tree

README.md

Lines changed: 2 additions & 126 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +1,6 @@
1-
## Distribute Load Testing Using GKE
1+
## Distributed Load Testing Using GKE and Locust
22

3-
## Introduction
4-
5-
Load testing is key to the development of any backend infrastructure because load tests demonstrate how well the system functions when faced with real-world demands. An important aspect of load testing is the proper simulation of user and device behavior to identify and understand any possible system bottlenecks, well in advance of deploying applications to production.
6-
7-
However, dedicated test infrastructure can be expensive and difficult to maintain because it is not needed on a continuous basis. Moreover, dedicated test infrastructure is often a one-time capital expense with a fixed capacity, which makes it difficult to scale load testing beyond the initial investment and can limit experimentation. This can lead to slowdowns in productivity for development teams and lead to applications that are not properly tested before production deployments.
8-
9-
## Before you begin
10-
11-
Open Cloud Shell to execute the commands listed in this tutorial.
12-
13-
Define environment variables for the project id, region and zone you want to use for this tutorial.
14-
15-
$ PROJECT=$(gcloud config get-value project)
16-
$ REGION=us-central1
17-
$ ZONE=${REGION}-b
18-
$ CLUSTER=gke-load-test
19-
$ TARGET=${PROJECT}.appspot.com
20-
$ gcloud config set compute/region $REGION
21-
$ gcloud config set compute/zone $ZONE
22-
23-
**Note:** Following services should be enabled in your project:
24-
Cloud Build
25-
Kubernetes Engine
26-
Google App Engine Admin API
27-
Cloud Storage
28-
29-
$ gcloud services enable \
30-
cloudbuild.googleapis.com \
31-
compute.googleapis.com \
32-
container.googleapis.com \
33-
containeranalysis.googleapis.com \
34-
containerregistry.googleapis.com
35-
36-
## Load testing tasks
37-
38-
To deploy the load testing tasks, you first deploy a load testing master and then deploy a group of load testing workers. With these load testing workers, you can create a substantial amount of traffic for testing purposes.
39-
40-
**Note:** Keep in mind that generating excessive amounts of traffic to external systems can resemble a denial-of-service attack. Be sure to review the Google Cloud Platform Terms of Service and the Google Cloud Platform Acceptable Use Policy.
41-
42-
## Load testing master
43-
44-
The first component of the deployment is the Locust master, which is the entry point for executing the load testing tasks described above. The Locust master is deployed with a single replica because we need only one master.
45-
46-
The configuration for the master deployment specifies several elements, including the ports that need to be exposed by the container (`8089` for web interface, `5557` and `5558` for communicating with workers). This information is later used to configure the Locust workers. The following snippet contains the configuration for the ports:
47-
48-
ports:
49-
- name: loc-master-web
50-
containerPort: 8089
51-
protocol: TCP
52-
- name: loc-master-p1
53-
containerPort: 5557
54-
protocol: TCP
55-
- name: loc-master-p2
56-
containerPort: 5558
57-
protocol: TCP
58-
59-
Next, we would deploy a Service to ensure that the exposed ports are accessible to other pods via `hostname:port` within the cluster, and referenceable via a descriptive port name. The use of a service allows the Locust workers to easily discover and reliably communicate with the master, even if the master fails and is replaced with a new pod by the deployment. The Locust master service also includes a directive to create an external forwarding rule at the cluster level (i.e. type of LoadBalancer), which provides the ability for external traffic to access the cluster resources.
60-
61-
After you deploy the Locust master, you can access the web interface using the public IP address of the external forwarding rule. After you deploy the Locust workers, you can start the simulation and look at aggregate statistics through the Locust web interface.
62-
63-
## Load testing workers
64-
65-
The next component of the deployment includes the Locust workers, which execute the load testing tasks described above. The Locust workers are deployed by a single deployment that creates multiple pods. The pods are spread out across the Kubernetes cluster. Each pod uses environment variables to control important configuration information such as the hostname of the system under test and the hostname of the Locust master.
66-
67-
After the Locust workers are deployed, you can return to the Locust master web interface and see that the number of slaves corresponds to the number of deployed workers.
68-
69-
## Setup
70-
71-
1. Create GKE cluster
72-
73-
$ gcloud container clusters create $CLUSTER \
74-
--zone $ZONE \
75-
--scopes "https://www.googleapis.com/auth/cloud-platform" \
76-
--num-nodes "3" \
77-
--enable-autoscaling --min-nodes "3" \
78-
--max-nodes "10" \
79-
--addons HorizontalPodAutoscaling,HttpLoadBalancing
80-
81-
$ gcloud container clusters get-credentials $CLUSTER \
82-
--zone $ZONE \
83-
--project $PROJECT
84-
85-
2. Clone tutorial repo in a local directory on your cloud shell environment
86-
87-
$ git clone <this-repository>
88-
89-
3. Build docker image and store it in your project's container registry
90-
91-
$ pushd gke-load-test
92-
$ gcloud builds submit --tag gcr.io/$PROJECT/locust-tasks:latest docker-image/.
93-
94-
4. Deploy sample application on GAE
95-
96-
$ gcloud app deploy sample-webapp/app.yaml --project=$PROJECT
97-
98-
5. Replace [TARGET_HOST] and [PROJECT_ID] in locust-master-controller.yaml and locust-worker-controller.yaml with the deployed endpoint and project-id respectively.
99-
100-
$ sed -i -e "s/\[TARGET_HOST\]/$TARGET/g" kubernetes-config/locust-master-controller.yaml
101-
$ sed -i -e "s/\[TARGET_HOST\]/$TARGET/g" kubernetes-config/locust-worker-controller.yaml
102-
$ sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kubernetes-config/locust-master-controller.yaml
103-
$ sed -i -e "s/\[PROJECT_ID\]/$PROJECT/g" kubernetes-config/locust-worker-controller.yaml
104-
105-
6. Deploy Locust master and worker nodes:
106-
107-
$ kubectl apply -f kubernetes-config/locust-master-controller.yaml
108-
$ kubectl apply -f kubernetes-config/locust-master-service.yaml
109-
$ kubectl apply -f kubernetes-config/locust-worker-controller.yaml
110-
111-
7. Get the external ip of Locust master service
112-
113-
$ EXTERNAL_IP=$(kubectl get svc locust-master -o yaml | grep ip | awk -F":" '{print $NF}')
114-
115-
8. Starting load testing
116-
The Locust master web interface enables you to execute the load testing tasks against the system under test, as shown in the following image. Access the url as http://$EXTERNAL_IP:8089.
117-
118-
To begin, specify the total number of users to simulate and a rate at which each user should be spawned. Next, click Start swarming to begin the simulation. To stop the simulation, click **Stop** and the test will terminate. The complete results can be downloaded into a spreadsheet.
119-
120-
9. [Optional] Scaling clients
121-
Scaling up the number of simulated users will require an increase in the number of Locust worker pods. To increase the number of pods deployed by the deployment, Kubernetes offers the ability to resize deployments without redeploying them. For example, the following command scales the pool of Locust worker pods to 20:
122-
123-
$ kubectl scale deployment/locust-worker --replicas=20
124-
125-
## Cleaning up
126-
127-
$ gcloud container clusters delete $CLUSTER --zone $ZONE
3+
This is the sample code for the [Distributed load testing using Google Kubernetes Engine](https://cloud.google.com/architecture/distributed-load-testing-using-gke) tutorial.
1284

1295
## License
1306

docker-image/Dockerfile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015 Google Inc. All rights reserved.
1+
# Copyright 2022 Google Inc. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -13,8 +13,8 @@
1313
# limitations under the License.
1414

1515

16-
# Start with a base Python 3.7.2 image
17-
FROM python:3.7.2
16+
# Start with a base image Python 3.9.12 Debian 11 (bullseye) slim
17+
FROM python:3.9.12-slim-bullseye
1818

1919
# Add the licenses for third party software and libraries
2020
ADD licenses /licenses
Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
1-
certifi==2019.3.9
2-
chardet==3.0.4
3-
Click==7.0
4-
Flask==1.0.2
5-
gevent==1.4.0
6-
greenlet==0.4.15
7-
idna==2.8
8-
itsdangerous==1.1.0
9-
Jinja2==2.10.1
10-
locustio==0.11.0
11-
MarkupSafe==1.1.1
12-
msgpack==0.6.1
1+
Brotli==1.0.9
2+
certifi==2021.10.8
3+
chardet==4.0.0
4+
charset-normalizer==2.0.12
5+
click==8.1.2
6+
ConfigArgParse==1.5.3
7+
Flask==2.1.1
8+
Flask-BasicAuth==0.2.0
9+
Flask-Cors==3.0.10
10+
gevent==21.12.0
11+
geventhttpclient==1.5.3
12+
greenlet==1.1.2
13+
idna==3.3
14+
importlib-metadata==4.11.3
15+
itsdangerous==2.1.2
16+
Jinja2==3.0.3
17+
locust==2.8.6
18+
MarkupSafe==2.1.1
19+
msgpack==1.0.3
1320
msgpack-python==0.5.6
14-
pyzmq==18.0.1
15-
requests==2.21.0
16-
six==1.12.0
17-
urllib3==1.24.2
18-
Werkzeug==0.15.1
21+
psutil==5.9.0
22+
pyzmq==22.3.0
23+
requests==2.27.1
24+
roundrobin==0.0.2
25+
six==1.16.0
26+
typing_extensions==4.1.1
27+
urllib3==1.26.9
28+
Werkzeug==2.1.1
29+
zipp==3.8.0
30+
zope.event==4.5.0
31+
zope.interface==5.4.0

docker-image/locust-tasks/run.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/bin/bash
22

3-
# Copyright 2015 Google Inc. All rights reserved.
3+
# Copyright 2022 Google Inc. All rights reserved.
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -22,9 +22,9 @@ LOCUST_MODE=${LOCUST_MODE:-standalone}
2222
if [[ "$LOCUST_MODE" = "master" ]]; then
2323
LOCUS_OPTS="$LOCUS_OPTS --master"
2424
elif [[ "$LOCUST_MODE" = "worker" ]]; then
25-
LOCUS_OPTS="$LOCUS_OPTS --slave --master-host=$LOCUST_MASTER"
25+
LOCUS_OPTS="$LOCUS_OPTS --worker --master-host=$LOCUST_MASTER"
2626
fi
2727

2828
echo "$LOCUST $LOCUS_OPTS"
2929

30-
$LOCUST $LOCUS_OPTS
30+
$LOCUST $LOCUS_OPTS

docker-image/locust-tasks/tasks.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python
22

3-
# Copyright 2015 Google Inc. All rights reserved.
3+
# Copyright 2022 Google Inc. All rights reserved.
44
#
55
# Licensed under the Apache License, Version 2.0 (the "License");
66
# you may not use this file except in compliance with the License.
@@ -18,9 +18,11 @@
1818
import uuid
1919

2020
from datetime import datetime
21-
from locust import HttpLocust, TaskSet, task
21+
from locust import FastHttpUser, TaskSet, task
2222

2323

24+
# [START locust_test_task]
25+
2426
class MetricsTaskSet(TaskSet):
2527
_deviceid = None
2628

@@ -38,5 +40,7 @@ def post_metrics(self):
3840
"/metrics", {"deviceid": self._deviceid, "timestamp": datetime.now()})
3941

4042

41-
class MetricsLocust(HttpLocust):
42-
task_set = MetricsTaskSet
43+
class MetricsLocust(FastHttpUser):
44+
tasks = {MetricsTaskSet}
45+
46+
# [END locust_test_task]

kubernetes-config/locust-master-controller.yaml renamed to kubernetes-config/locust-master-controller.yaml.tpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015 Google Inc. All rights reserved.
1+
# Copyright 2022 Google Inc. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -31,12 +31,12 @@ spec:
3131
spec:
3232
containers:
3333
- name: locust-master
34-
image: gcr.io/[PROJECT_ID]/locust-tasks:latest
34+
image: ${REGION}-docker.pkg.dev/${PROJECT}/${AR_REPO}/${LOCUST_IMAGE_NAME}:${LOCUST_IMAGE_TAG}
3535
env:
3636
- name: LOCUST_MODE
3737
value: master
3838
- name: TARGET_HOST
39-
value: https://[TARGET_HOST]
39+
value: https://${SAMPLE_APP_TARGET}
4040
ports:
4141
- name: loc-master-web
4242
containerPort: 8089

kubernetes-config/locust-master-service.yaml renamed to kubernetes-config/locust-master-service.yaml.tpl

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015 Google Inc. All rights reserved.
1+
# Copyright 2022 Google Inc. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -21,10 +21,6 @@ metadata:
2121
app: locust-master
2222
spec:
2323
ports:
24-
- port: 8089
25-
targetPort: loc-master-web
26-
protocol: TCP
27-
name: loc-master-web
2824
- port: 5557
2925
targetPort: loc-master-p1
3026
protocol: TCP
@@ -35,4 +31,21 @@ spec:
3531
name: loc-master-p2
3632
selector:
3733
app: locust-master
34+
---
35+
kind: Service
36+
apiVersion: v1
37+
metadata:
38+
name: locust-master-web
39+
annotations:
40+
networking.gke.io/load-balancer-type: "Internal"
41+
labels:
42+
app: locust-master
43+
spec:
44+
ports:
45+
- port: 8089
46+
targetPort: loc-master-web
47+
protocol: TCP
48+
name: loc-master-web
49+
selector:
50+
app: locust-master
3851
type: LoadBalancer

kubernetes-config/locust-worker-controller.yaml renamed to kubernetes-config/locust-worker-controller.yaml.tpl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015 Google Inc. All rights reserved.
1+
# Copyright 2022 Google Inc. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -30,11 +30,11 @@ spec:
3030
spec:
3131
containers:
3232
- name: locust-worker
33-
image: gcr.io/[PROJECT_ID]/locust-tasks:latest
33+
image: ${REGION}-docker.pkg.dev/${PROJECT}/${AR_REPO}/${LOCUST_IMAGE_NAME}:${LOCUST_IMAGE_TAG}
3434
env:
3535
- name: LOCUST_MODE
3636
value: worker
3737
- name: LOCUST_MASTER
3838
value: locust-master
3939
- name: TARGET_HOST
40-
value: https://[TARGET_HOST]
40+
value: https://${SAMPLE_APP_TARGET}

sample-webapp/.gcloudignore

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# This file specifies files that are *not* uploaded to Google Cloud Platform
2+
# using gcloud. It follows the same syntax as .gitignore, with the addition of
3+
# "#!include" directives (which insert the entries of the given .gitignore-style
4+
# file at that point).
5+
#
6+
# For more information, run:
7+
# $ gcloud topic gcloudignore
8+
#
9+
.gcloudignore
10+
# If you would like to upload your .git directory, .gitignore file or files
11+
# from your .gitignore file, remove the corresponding line
12+
# below:
13+
.git
14+
.gitignore
15+
16+
# Python pycache:
17+
__pycache__/
18+
# Ignored by the build system
19+
/setup.cfg

sample-webapp/app.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2015 Google Inc. All rights reserved.
1+
# Copyright 2022 Google Inc. All rights reserved.
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -13,7 +13,7 @@
1313
# limitations under the License.
1414

1515

16-
runtime: python37
16+
runtime: python39
1717

1818
instance_class: F2
1919

0 commit comments

Comments
 (0)