mirror of
https://github.com/helm/charts.git
synced 2026-08-23 22:37:45 +00:00
Add a Chart for Locust Distributed Load Testing (#637)
* Add first locust chart draft * Move to stable * Improve post installation NOTES * Enable Health Check on locust master * Enable hard limit on Kubernetes Resources * Ensure master is ready before starting workers * Fix quotes for Worker deployment
This commit is contained in:
committed by
Lachlan Evenson
parent
e4b2d1e441
commit
d763d9933c
@@ -0,0 +1,5 @@
|
||||
name: locust
|
||||
description: A chart for locust distributed load testing
|
||||
version: 0.1.0
|
||||
sources:
|
||||
- https://github.com/honestbee/distributed-load-testing
|
||||
@@ -0,0 +1,71 @@
|
||||
# Locust Helm Chart
|
||||
|
||||
This is a templated deployment of [Locust](locust.io) for Distributed Load
|
||||
testing using Kubernetes.
|
||||
|
||||
## Pre Requisites:
|
||||
|
||||
* Requires (and tested with) helm `v2.1.2` or above.
|
||||
|
||||
## Chart details
|
||||
|
||||
This chart will do the following:
|
||||
|
||||
* Convert all files in `tasks/` folder into a configmap
|
||||
* Create a Locust master and Locust worker deployment with the Target host
|
||||
and Tasks file specified.
|
||||
|
||||
|
||||
### Installing the chart
|
||||
|
||||
To install the chart with the release name `locust-nymph` in the default namespace:
|
||||
|
||||
```bash
|
||||
helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator
|
||||
helm install -n locust-nymph --set master.config.target-host=http://site.example.com incubator/locust
|
||||
```
|
||||
|
||||
| Parameter | Description | Default |
|
||||
| ---------------------------- | ---------------------------------- | ----------------------------------------------------- |
|
||||
| `Name` | Locust master name | `locust` |
|
||||
| `image.repository` | Locust container image name | `quay.io/honestbee/locust` |
|
||||
| `image.tag` | Locust Container image tag | `0.7.5` |
|
||||
| `service.type` | k8s service type exposing master | `NodePort` |
|
||||
| `service.nodePort` | Port on cluster to expose master | `0` |
|
||||
| `master.config.target-host` | locust target host | `http://site.example.com` |
|
||||
| `worker.config.locust-script`| locust script to run | `/locust-tasks/tasks.py` |
|
||||
| `worker.replicaCount` | Number of workers to run | `2` |
|
||||
|
||||
Specify parameters using `--set key=value[,key=value]` argument to `helm install`
|
||||
|
||||
Alternatively a YAML file that specifies the values for the parameters can be provided like this:
|
||||
|
||||
```bash
|
||||
$ helm install --name my-release -f values.yaml incubator/locust
|
||||
```
|
||||
|
||||
You can start the swarm from the command line using Port forwarding as follows:
|
||||
|
||||
Get the Locust URL following the Post Installation notes.
|
||||
|
||||
for example:
|
||||
```bash
|
||||
export LOCUST_URL=http://127.0.0.1:8089
|
||||
```
|
||||
|
||||
Start / Monitor & Stop the Locust swarm via the web panel or with following commands:
|
||||
|
||||
Start:
|
||||
```bash
|
||||
curl -XPOST $LOCUST_URL/swarm -d"locust_count=100&hatch_rate=10"
|
||||
```
|
||||
|
||||
Monitor:
|
||||
```bash
|
||||
watch -n 1 "curl -s $LOCUST_URL/stats/requests | jq -r '[.user_count, .total_rps, .state] | @tsv'"
|
||||
```
|
||||
|
||||
Stop:
|
||||
```bash
|
||||
curl $LOCUST_URL/stop
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
from locust import HttpLocust, TaskSet, task
|
||||
import json, requests
|
||||
|
||||
class ElbTasks(TaskSet):
|
||||
@task(1)
|
||||
def status(self):
|
||||
self.client.get("/status")
|
||||
|
||||
class ElbWarmer(HttpLocust):
|
||||
task_set = ElbTasks
|
||||
min_wait = 1000
|
||||
max_wait = 3000
|
||||
@@ -0,0 +1,24 @@
|
||||
{{ .Chart.Name }} installed!
|
||||
|
||||
Get the Locust URL to visit by running these commands in the same shell:
|
||||
|
||||
{{- if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get svc -n {{ .Release.Namespace }} {{ template "locust.master-svc" . }} -o jsonpath='{.spec.ports[?(@.name=="{{ .Values.service.name }}")].nodePort}')
|
||||
export NODE_IP=$(kubectl get no -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
export LOCUST_URL=http://$NODE_IP:$NODE_PORT/
|
||||
|
||||
{{- else if contains "LoadBalancer" .Values.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status by running 'kubectl get svc -n {{ .Release.Namespace }} -w {{ template "locust.master-svc" . }}'
|
||||
export SERVICE_IP=$(kubectl get svc -n {{ .Release.Namespace }} {{ template "locust.master-svc" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
export LOCUST_URL=http://$SERVICE_IP:{{ .Values.service.externalPort }}/
|
||||
|
||||
{{- else if contains "ClusterIP" .Values.service.type }}
|
||||
export POD_NAME=$(kubectl get po --namespace {{ .Release.Namespace }} -l "app={{ template "locust.fullname" . }},component=master" -o jsonpath="{.items[0].metadata.name}")
|
||||
export LOCUST_URL=http://127.0.0.1:{{ .Values.service.externalPort }}
|
||||
kubectl port-forward $POD_NAME {{ .Values.service.externalPort }}:{{ .Values.service.externalPort }} &
|
||||
|
||||
{{- end }}
|
||||
|
||||
For more information on Distributed load testing on Kubernetes using Locust, visit:
|
||||
https://cloud.google.com/solutions/distributed-load-testing-using-kubernetes
|
||||
@@ -0,0 +1,27 @@
|
||||
{{/* vim: set filetype=mustache: */}}
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
*/}}
|
||||
{{- define "locust.fullname" -}}
|
||||
{{- printf "%s-%s" .Release.Name "locust" | trunc 63 -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "locust.master-svc" -}}
|
||||
{{- printf "%s-%s" .Release.Name "master-svc" | trunc 63 -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "locust.master" -}}
|
||||
{{- printf "%s-%s" .Release.Name "master" | trunc 63 -}}
|
||||
{{- end -}}
|
||||
|
||||
{{- define "locust.worker" -}}
|
||||
{{- printf "%s-%s" .Release.Name "worker" | trunc 63 -}}
|
||||
{{- end -}}
|
||||
|
||||
{{/*
|
||||
Create fully qualified configmap name.
|
||||
*/}}
|
||||
{{- define "locust.worker-configmap" -}}
|
||||
{{- printf "%s-%s" .Release.Name "worker" -}}
|
||||
{{- end -}}
|
||||
@@ -0,0 +1,67 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "locust.master" . }}
|
||||
labels:
|
||||
app: {{ template "locust.fullname" . }}
|
||||
heritage: {{ .Release.Service | quote }}
|
||||
release: {{ .Release.Name | quote }}
|
||||
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
|
||||
component: master
|
||||
spec:
|
||||
replicas: 1
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: {{default 1 .Values.master.maxSurge}}
|
||||
maxUnavailable: {{default 1 .Values.master.maxUnavailable}}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
release: {{ .Release.Name | quote }}
|
||||
app: {{ template "locust.fullname" . }}
|
||||
component: "master"
|
||||
spec:
|
||||
containers:
|
||||
- name: locust
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
resources:
|
||||
{{ toYaml .Values.worker.resources | indent 10 }}
|
||||
env:
|
||||
{{- range $key, $value := .Values.master.config }}
|
||||
- name: {{ $key | upper | replace "-" "_" }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
- name: LOCUST_MODE
|
||||
value: "master"
|
||||
- name: LOCUST_SCRIPT
|
||||
value: {{ index .Values.worker.config "locust-script" | quote }}
|
||||
ports:
|
||||
- containerPort: {{ .Values.service.internalPort }}
|
||||
name: loc-master-web
|
||||
protocol: TCP
|
||||
- containerPort: 5557
|
||||
name: loc-master-p1
|
||||
protocol: TCP
|
||||
- containerPort: 5558
|
||||
name: loc-master-p2
|
||||
protocol: TCP
|
||||
volumeMounts:
|
||||
- name: locust-tasks
|
||||
mountPath: /locust-tasks/
|
||||
livenessProbe:
|
||||
periodSeconds: 30
|
||||
httpGet:
|
||||
path: /
|
||||
port: {{ .Values.service.internalPort }}
|
||||
readinessProbe:
|
||||
periodSeconds: 30
|
||||
httpGet:
|
||||
path: /
|
||||
port: {{ .Values.service.internalPort }}
|
||||
volumes:
|
||||
- name: "locust-tasks"
|
||||
configMap:
|
||||
name: {{ template "locust.worker-configmap" . }}
|
||||
restartPolicy: Always
|
||||
@@ -0,0 +1,30 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ template "locust.master-svc" . }}
|
||||
labels:
|
||||
heritage: {{ .Release.Service | quote }}
|
||||
release: {{ .Release.Name | quote }}
|
||||
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
|
||||
app: {{ template "locust.fullname" . }}
|
||||
component: "master"
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- name: {{ .Values.service.name }}
|
||||
port: {{ .Values.service.externalPort }}
|
||||
targetPort: {{ .Values.service.internalPort }}
|
||||
nodePort: {{ .Values.service.nodePort}}
|
||||
protocol: TCP
|
||||
- name: master-p1
|
||||
port: 5557
|
||||
protocol: TCP
|
||||
targetPort: 5557
|
||||
- name: master-p2
|
||||
port: 5558
|
||||
protocol: TCP
|
||||
targetPort: 5558
|
||||
selector:
|
||||
app: {{ template "locust.fullname" . }}
|
||||
component: "master"
|
||||
sessionAffinity: None
|
||||
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ template "locust.worker-configmap" . }}
|
||||
labels:
|
||||
heritage: {{ .Release.Service | quote }}
|
||||
release: {{ .Release.Name | quote }}
|
||||
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
|
||||
app: {{ template "locust.fullname" . }}
|
||||
data:
|
||||
{{ (.Files.Glob "tasks/*").AsConfig | indent 2 }}
|
||||
@@ -0,0 +1,50 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ template "locust.worker" . }}
|
||||
labels:
|
||||
heritage: {{ .Release.Service | quote }}
|
||||
release: {{ .Release.Name | quote }}
|
||||
chart: "{{.Chart.Name}}-{{.Chart.Version}}"
|
||||
app: {{ template "locust.fullname" . }}
|
||||
component: worker
|
||||
spec:
|
||||
replicas: {{default 2 .Values.worker.ReplicaCount}}
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
rollingUpdate:
|
||||
maxSurge: {{default 1 .Values.worker.maxSurge}}
|
||||
maxUnavailable: {{default 1 .Values.worker.maxUnavailable}}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: {{ template "locust.fullname" . }}
|
||||
component: worker
|
||||
spec:
|
||||
containers:
|
||||
- name: locust
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
volumeMounts:
|
||||
- name: locust-tasks
|
||||
mountPath: /locust-tasks/
|
||||
env:
|
||||
{{- range $key, $value := .Values.worker.config }}
|
||||
- name: {{ $key | upper | replace "-" "_" }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
- name: LOCUST_MODE
|
||||
value: "worker"
|
||||
- name: LOCUST_MASTER
|
||||
value: {{ template "locust.master-svc" . }}
|
||||
- name: LOCUST_MASTER_WEB
|
||||
value: "{{ .Values.service.internalPort }}"
|
||||
- name: TARGET_HOST
|
||||
value: {{ index .Values.master.config "target-host" | quote }}
|
||||
resources:
|
||||
{{ toYaml .Values.worker.resources | indent 10 }}
|
||||
restartPolicy: Always
|
||||
volumes:
|
||||
- name: "locust-tasks"
|
||||
configMap:
|
||||
name: {{ template "locust.worker-configmap" . }}
|
||||
@@ -0,0 +1,36 @@
|
||||
Name: locust
|
||||
|
||||
image:
|
||||
repository: quay.io/honestbee/locust
|
||||
tag: 0.7.5
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
service:
|
||||
name: master-web
|
||||
type: NodePort
|
||||
externalPort: 8089
|
||||
internalPort: 8089
|
||||
nodePort: 0
|
||||
master:
|
||||
config:
|
||||
target-host: https://site.example.com
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
worker:
|
||||
config:
|
||||
|
||||
# all files from tasks folder are mounted under `/locust-tasks`
|
||||
locust-script: "/locust-tasks/tasks.py"
|
||||
replicaCount: 2
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
Reference in New Issue
Block a user