Skip to content

Commit 17bcb18

Browse files
authored
Merge pull request GoogleCloudPlatform#4 from RealKinetic/part-1-rak-review
Part 1 rak review
2 parents b0593bc + 3ce84c4 commit 17bcb18

File tree

5 files changed

+123
-55
lines changed

5 files changed

+123
-55
lines changed

Blog_part_1.md

+83-52
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ I've quoted Locust’s high level description below but you can visit [their](ht
2525
2626
Now that we have a rough idea of what Locust is, let's get it installed.
2727

28-
** NOTE: If you don’t want to install Locust locally, skip down to the Docker section towards the bottom of this guide.
28+
**NOTE:** If you don’t want to install Locust locally, skip down to the Docker section towards the bottom of this guide.
2929

3030
## Install Locust
3131

@@ -61,36 +61,37 @@ Now that we have Locust installed we can create and run a Locust script. But fir
6161

6262
## Test Server
6363

64-
I have created a repo we will build out as we go. Within that repo you will find an example_server program written in Go (compiled on OSX). You can directly grab that binary [here](https://github.com/RealKinetic/locust_k8s/blob/49b221e52484c6e0d165490a3dbbf1fe4d2f9dce/example_server) or clone the repo with the following command: `git clone git@github.com:RealKinetic/locust_k8s.git`
64+
I created a repo we will use to build out the server and test scripts. Within that repo you will find an [example_server](https://github.com/RealKinetic/locust_k8s/blob/master/examples/golang/example_server.go) program written in Go. If you are on OSX, and you trust binaries from the internet, you can grab the binary [here](https://github.com/RealKinetic/locust_k8s/blob/master/example_server); otherwise clone the repo with the following command:
6565

66-
Here is the Go code behind the file. It is also included in the repo if you would like to make changes or do not trust running a binary from the Internet. To build the go file run: `$ go build example_server.go`
66+
$ git clone git@github.com:RealKinetic/locust_k8s.git
67+
$ cd locust_k8s
6768

68-
Once you have the binary or repo pulled down go to that directly:
69+
To build the server, run:
6970

70-
$ cd locust_k8s
71+
$ go build examples/golang/example_server.go
7172

72-
And run the following command to run the server:
73+
And run the following command to start the server:
7374

7475
$ ./example_server
7576

76-
This server will sit on port `8080`. You can test it by visiting http://localhost:8080. You should see a page with:
77+
This server will listen on port `8080`. You can test it by visiting [http://localhost:8080](http://localhost:8080/). You should see a page with:
7778

78-
Our example home page.
79+
> Our example home page.
7980
80-
There are two other endpoints exposed by this example server.
81+
There are two other endpoints exposed by our example server.
8182

82-
* `\login` which we will send a post request to and returns `Login. The server will output `Login Request` to stdout when this endpoint is hit.
83-
* `\profile` which we will send a get request to and returns `Profile`. The server will output `Profile Request` to stdout when this endpoint is hit.
83+
* [`/login`](http://localhost:8080/login) accepts `POST` requests and returns a plain text response "*Login.*". The server will output "`Login Request`" to stdout when this endpoint is hit.
84+
* [`/profile`](http://localhost:8080/profile) accepts `GET` requests and returns "*Profile.*". The server will output "`Profile Request`" to stdout when this endpoint is hit.
8485

85-
Now that we have an example server to hit we can create the Locust file.
86+
Now that we have an example server, we can create the Locust test file.
8687

8788
## Running Locust
8889

8990
For this example we can use the example provided by Locust in their [quick start documentation](http://docs.locust.io/en/latest/quickstart.html).
9091

91-
You can use the `locustfile.py` in our example repo or create said file.
92+
You can use the `locustfile.py` in our example repo, or create the file yourself.
9293

93-
Here's the code that you will need in `locustfile.py`:
94+
Your `locustfile.py` should contain the following:
9495

9596
from locust import HttpLocust, TaskSet, task
9697

@@ -100,7 +101,9 @@ Here's the code that you will need in `locustfile.py`:
100101
self.login()
101102

102103
def login(self):
103-
self.client.post("/login", {"username":"ellen_key", "password":"education"})
104+
self.client.post("/login",
105+
{"username":"ellen_key",
106+
"password":"education"})
104107

105108
@task(2)
106109
def index(self):
@@ -115,35 +118,46 @@ Here's the code that you will need in `locustfile.py`:
115118
min_wait = 5000
116119
max_wait = 9000
117120

118-
You can learn more about what this file does in the Locust documentation and quick start walkthrough (highly recommended).
121+
The Locust documentation and [quick start documentation](http://docs.locust.io/en/latest/quickstart.html) provides an explanation of the contents. We highly recommend working through their docs to learn more.
119122

120123
Now that we have our locustfile we can do a test.
121124

122125
First ensure your example server is running:
123126

124127
$ ./example_server
125128

126-
Then we run Locust and give it our file.
129+
Now, in a new terminal we will run Locust. We will pass it the name of our test file, `locustfile.py`, and tell it to run against our example server on port `8080` of `localhost`.
130+
131+
$ locust -f locustfile.py --host=http://localhost:8080
127132

128-
locust -f locustfile.py --host=http://localhost:8080
133+
With Locust running we can open the web user interface at: [http://localhost:8089](http://localhost:8089).
129134

130-
We pass in the host of our example server which is running on port 8080 of localhost.
135+
For this test, we will simulate 1 user and specify 1 for the hatch rate. Click the `Start swarming` button. You should now see something similar to the following in the terminal running example server:
131136

132-
With Locust running we can open the web user interface at: http://localhost:8089
137+
2017/09/13 15:24:33 Login Request
138+
2017/09/13 15:24:33 Profile Request
139+
2017/09/13 15:24:40 Profile Request
140+
2017/09/13 15:24:46 Index Request
141+
2017/09/13 15:24:55 Index Request
142+
2017/09/13 15:25:00 Index Request
143+
2017/09/13 15:25:07 Profile Request
144+
2017/09/13 15:25:12 Index Request
133145

134-
We can do a quick test by adding 1 user to simulate and 1 for a hatch rate. Then click the `Start swarming` button.
146+
In the Locust UI you will see a list of the endpoints being hit. You will see the request counts incrementing for `/` and `/profile`. There should be no failures unless Locust is having issues connecting to your server.
135147

136-
You should now see messages being sent to the stdout of your example server. In the Locust UI you will see a list of the endpoints being hit. You will see the request counts incrementing for `/` and `/profile`. There should not be failures being logged unless Locust is having issues connecting to your server.
148+
![Locust Screenshot](/locust-run.png)
137149

138150
# Docker
139151

140-
We're going to build and run our [Docker](https://www.docker.com/) containers locally first so go ahead and install Docker for your environment based off the directions on the [Docker](https://www.docker.com/) website.
152+
We're going to start by building and running our [containers](https://www.docker.com/what-container) locally using [Docker](https://www.docker.com/). Install Docker for your environment using the directions on the [Docker](https://www.docker.com/) website.
153+
154+
**NOTE:** Before continuing, you should stop the two servers from the previous sections using `ctrl-c` in each terminal window.
141155

142156
# Docker Environment
143157

144-
We will have two containers running in our scenario: our example server and Locust instance. To support our locust container’s communication with our example server we need to configure a custom Docker network. Thankfully this is a simple process.
158+
We will run two containers: our service (our golang example server) and our Locust instance. To support our locust container’s communication with our example server we need to configure a custom Docker network. Thankfully this is a simple process.
145159

146-
The following command will create a custom Docker network named `locustnw`
160+
The following command will create a custom Docker network named `locustnw`:
147161

148162
$ docker network create --driver bridge locustnw
149163

@@ -174,43 +188,51 @@ This will use the `Dockerfile` we've create in the `examples/golang` directory w
174188
# Build the example executable
175189
RUN go build example_server.go
176190

177-
# Set script to be executable
191+
# Set the server to be executable
178192
RUN chmod 755 example_server
179193

180194
# Expose the required port (8080)
181195
EXPOSE 8080
182196

183-
# Start Locust using LOCUS_OPTS environment variable
197+
# Start our example service
184198
ENTRYPOINT ["./example_server"]
185199

186-
The `-t` argument allows us to tag our container with a name. In this case we're tagging it `goexample`.
200+
The `-t` argument tags our container with a name, `goexample`, in this case.
187201

188202
Now that we've created our container we can run it with the following:
189203

190-
$ docker run -it -p=8080:8080 --name=exampleserver --network=locustnw goexample
204+
$ docker run -it -p=8080:8080 \
205+
--name=exampleserver \
206+
--network=locustnw \
207+
goexample
191208

192-
- The `-p` flag exposes port 8080 within the container to the outside on the same port 8080. This is the port our example server is listenining on.
193-
- The `--name` flag allows us to give a named identifier to the container. This allows us to reference this container by name as a host instead of by IP address. This will be critical when we run the locust container.
209+
- The `-p` flag exposes the container's port 8080 on localhost as port 8080. This is the port our example server is listening on.
210+
- The `--name` flag allows us to give a named identifier to the container. This allows us to reference this container by name as a host instead of by IP address. This will be critical when we run the Locust container.
194211
- The `--network` argument tells Docker to use our custom network for this container.
195212

196-
Since we exposed and mapped port 8080, you can test that our server is working by visiting http://localhost:8080.
213+
**NOTE:** If you get the following error, stop the `example_server` we started previously (or any other services on port 8080).
197214

198-
Once you've verified that our example server container is running we can now build and run our Locust container. FYI if you ran Locust locally earlier you can re-run the same tests again now. Just point at the container version of our example server with the following `locust -f locustfile.py --host=http://localhost:8080`.
215+
docker: Error response from daemon: driver failed programming external connectivity on endpoint exampleserver (...): Error starting userland proxy: Bind for 0.0.0.0:8080 failed: port is already allocated.
216+
217+
218+
Since we exposed and mapped port 8080, you can test that our server is working by visiting [http://localhost:8080](http://localhost:8080).
219+
220+
Once you've verified your example server container is running, you can now build and run your Locust container.
199221

200222
## Locust Container
201223

202224
Building and running our locust container is similar to the process we used for our example server. First we build the container image with the following:
203225

204226
$ docker build docker -t locust-tasks
205227

206-
This uses the `Dockerfile` in our `docker` directory. That file consists of:
228+
This builds the `Dockerfile` located in our `docker` directory. That file consists of:
207229

208230
# Start with a base Python 2.7.8 image
209231
FROM python:2.7.13
210232

211233
MAINTAINER Beau Lyddon <beau.lyddon@realkinetic.com>
212234

213-
# Add the external tasks directory into /tasks
235+
# Add the external tasks directory into /locust-tasks
214236
RUN mkdir locust-tasks
215237
ADD locust-tasks /locust-tasks
216238
WORKDIR /locust-tasks
@@ -227,9 +249,9 @@ This uses the `Dockerfile` in our `docker` directory. That file consists of:
227249
# Start Locust using LOCUS_OPTS environment variable
228250
ENTRYPOINT ["./run.sh"]
229251

230-
A note: as you can see, this container doesn't run Locust directly but instead uses a `run.sh` file which lives in `docker/locust-tasks`. This file is important for part 2 of our tutorial, when we will run locust in a distributed mode.
252+
A note: this container doesn't run Locust directly but instead uses a `run.sh` file which lives in `docker/locust-tasks`. This file is important for part 2 of our tutorial where we will run locust in a distributed mode.
231253

232-
We will discuss quickly one import part of that file. Looking at the contents of that file:
254+
We will briefly discuss one import part of the `run.sh` file:
233255

234256
LOCUST="/usr/local/bin/locust"
235257
LOCUS_OPTS="-f /locust-tasks/locustfile.py --host=$TARGET_HOST"
@@ -245,58 +267,67 @@ We will discuss quickly one import part of that file. Looking at the contents of
245267

246268
$LOCUST $LOCUS_OPTS
247269

248-
You see that we rely on an environment variable named `$TARGET_HOST` to be the host url passed into our locustfile. This is what will allow us to communicate across containers within our Docker network. Let's look at how we do that.
270+
We rely on an environment variable named `$TARGET_HOST` being passed into our locustfile. This is key for us to communicate across containers within our Docker network.
249271

250-
With that container built we can run it with a similar command as our dev server.
272+
With our container built, we can run it with a similar command as our example service.
251273

252-
$ docker run -it -p=8089:8089 -e "TARGET_HOST=http://exampleserver:8080" --network=locustnw locust-tasks:latest
274+
$ docker run -it -p=8089:8089 \
275+
-e "TARGET_HOST=http://exampleserver:8080" \
276+
--network=locustnw locust-tasks:latest
253277

254-
Once again we're exposing a port but this time it's port `8089`, the default locust port. We pass the same network command to ensure this container also runs on our custom Docker network. However: one additional argument we pass in is `-e`. This is the argument for passing environment variables in to the Docker container. In this case we're passing in `http://exampleserver:8080` as the variable `TARGET_HOST`. So now we can see how the `$TARGET_HOST` environment variable in our `run.sh` script comes into play. We also see how the custom Docker network and named containers allows us to use `exampleserver` as the host name versus attempting to find the containers IP address and passing that in. This simplifies things a great deal.
278+
Once again we're exposing a port but this time it's port `8089`, the default locust port. We pass the network name to ensure this container also runs on our custom `locustnw` network.
255279

256-
Now that we have our locust server running we can visit http://localhost:8089 in a browser on our local machine to run locust via a container hitting our dev server also running within a container.
280+
We also pass an additional argument: `-e`. This argument sets environment variables inside the Docker container. In this case we're passing in `http://exampleserver:8080` as the variable `TARGET_HOST`. This is how the `$TARGET_HOST` environment variable needed by our `run.sh` script is set. We also see how the custom Docker network and named containers allow us to use `exampleserver` as the host name versus attempting to find the containers IP address and passing that in. This simplifies things a great deal.
281+
282+
Now that we have our locust server running we can visit [http://localhost:8089](http://localhost:8089) in a browser on our local machine. This connects to our container which will test against our example server, also running within a container.
257283

258284
$ open http://localhost:8089
259285

260286
# Deployment
261287

262-
We can obviously install Locust directly on any machine we'd like. Whether on bare metal, a VM, or in our case we're going to use [Docker](https://www.docker.com/) and [Google Container Engine (GKE)](https://www.docker.com/).
288+
We can install Locust directly on any machine we'd like. Bare metal, a VM, or, in our case, we're going to install into a [Docker](https://www.docker.com/) container and deploy the container to [Google Container Engine (GKE)](https://cloud.google.com/container-engine/).
263289

264290
## Google Container Engine
265291

266292
### Prerequisites
267293

268294
* Google Cloud Platform account
269295
* Install and setup [Google Cloud SDK](https://cloud.google.com/sdk/)
296+
** Be sure to run `$ gcloud init` after installing `gcloud`.
270297

271298
**Note:** when installing the Google Cloud SDK you will need to enable the following additional components:
272299

273-
* `Compute Engine Command Line Interface`
274-
* `kubectl`
300+
* [`Compute Engine Command Line Interface`](https://cloud.google.com/compute/docs/gcloud-compute/)
301+
* `kubectl` (`$ gcloud components install kubectl`)
302+
303+
Set an environment variable to the cloud project you will be using:
304+
305+
$ export $PROJECTID
275306

276-
Before continuing, you can also set your preferred zone and project:
307+
Before continuing, you can also [set your preferred zone and project](https://cloud.google.com/container-engine/docs/quickstart#optional_run_this_tutorial_locally_with_gcloud):
277308

278309
$ gcloud config set compute/zone ZONE
279-
$ gcloud config set project PROJECT-ID
310+
$ gcloud config set project $PROJECTID
280311

281312
### Deploying our example container
282313

283-
You can use the directions directly from the [Google Container Engine Quickstart](https://cloud.google.com/container-engine/docs/quickstart) or follow what we have below.
314+
We have summarized the key steps needed to deploy a container from the [Google Container Engine Quickstart](https://cloud.google.com/container-engine/docs/quickstart) below. If you would like a more thorough walkthrough, view the quickstart guide.
284315

285-
First up we're going to create a cluster on GKE for our container to run in:
316+
First up we're going to create a cluster on GKE:
286317

287318
$ gcloud container clusters create example-cluster
288319

289320
Then we want to give a new tag to our example container that matches where we will be pushing it in the [Google Container Registry](https://cloud.google.com/container-registry/). The Google Container Registry is Google's hosted Docker Registry. You can use any Docker registry that you'd prefer.
290321

291-
$ docker tag goexample gcr.io/PROJECT-ID/goexample
322+
$ docker tag goexample gcr.io/$PROJECTID/goexample
292323

293324
Now that we've tagged our image we can push it to the registry with the following:
294325

295-
$ gcloud docker -- push gcr.io/PROJECT-ID/goexample
326+
$ gcloud docker -- push gcr.io/$PROJECTID/goexample
296327

297328
With that pushed we can now run the image:
298329

299-
$ kubectl run example-node --image=gcr.io/PROJECT-ID/goexample:latest --port=8080
330+
$ kubectl run example-node --image=gcr.io/$PROJECTID/goexample:latest --port=8080
300331

301332
This is a similar command to our local Docker commands where we give it a name and expose a port. In this case however we're using `kubectl` which is the [Kubernetes Command Line Inteface](https://kubernetes.io/docs/user-guide/kubectl-overview/).
302333

docker/Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ FROM python:2.7.13
1717

1818
MAINTAINER Beau Lyddon <beau.lyddon@realkinetic.com>
1919

20-
# Add the external tasks directory into /tasks
20+
# Add the external tasks directory into /locust-tasks
2121
RUN mkdir locust-tasks
2222
ADD locust-tasks /locust-tasks
2323
WORKDIR /locust-tasks

docker/locust-tasks/locustfile.py

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Licensed under the Apache License, Version 2.0 (the "License");
2+
# you may not use this file except in compliance with the License.
3+
# You may obtain a copy of the License at
4+
#
5+
# http://www.apache.org/licenses/LICENSE-2.0
6+
#
7+
# Unless required by applicable law or agreed to in writing, software
8+
# distributed under the License is distributed on an "AS IS" BASIS,
9+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
# See the License for the specific language governing permissions and
11+
# limitations under the License.
12+
13+
from locust import HttpLocust, TaskSet, task
14+
15+
16+
class UserBehavior(TaskSet):
17+
18+
def on_start(self):
19+
""" on_start is called when a Locust start before any task is scheduled """
20+
self.login()
21+
22+
def login(self):
23+
self.client.post("/login", {"username":"ellen_key", "password":"education"})
24+
25+
@task(2)
26+
def index(self):
27+
self.client.get("/")
28+
29+
@task(1)
30+
def profile(self):
31+
self.client.get("/profile")
32+
33+
34+
class WebsiteUser(HttpLocust):
35+
task_set = UserBehavior
36+
min_wait = 5000
37+
max_wait = 9000

examples/golang/Dockerfile

+2-2
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@ WORKDIR example
2323
# Build the example executable
2424
RUN go build example_server.go
2525

26-
# Set script to be executable
26+
# Set server to be executable
2727
RUN chmod 755 example_server
2828

2929
# Expose the required port (8080)
3030
EXPOSE 8080
3131

32-
# Start Locust using LOCUS_OPTS environment variable
32+
# Start our example service
3333
ENTRYPOINT ["./example_server"]

locust-run.png

63.5 KB
Loading

0 commit comments

Comments
 (0)