Skip to content

Commit e561b4e

Browse files
authored
Merge pull request #11 from smithmicro/feature-10
Using ECS-CLI to streamline Lucy
2 parents 2e1fdbf + 05cd2dc commit e561b4e

File tree

6 files changed

+159
-257
lines changed

6 files changed

+159
-257
lines changed

README.md

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ The `smithmicro/lucy` Docker image can be run as-is with a number of required en
1212

1313
Prerequisites to use this image:
1414
* Create a VPC with at least one subnet as ECS requires the use of VPC **
15-
* Create a VPC security group that allows ports 22, 1099, 50000 and 51000 (tcp) to the VPC **
15+
* Create a VPC security group that allows ports 22, 1099, 50000 and 51000 (tcp) and 4445 (udp) to the VPC **
1616
* Create a security key pair and place in the `keys` subdirectory
1717
* Have your AWS CLI Access Key ID/Secret Access Key handy
1818
* Replace or edit the included `plans/demo.jmx` to run your specific tests
@@ -31,7 +31,6 @@ docker run -v <oath to jmx>:/plans -v <path to pem>:/keys -v <path to logs>:/log
3131
--env SUBNET_ID=<subnet ID within your VPC> \
3232
--env KEY_NAME=<key pair name without extension> \
3333
--env MINION_COUNT=<number of minions> \
34-
--enc INSTANCE_TYPE=<valid ECS instance type> \
3534
smithmicro/lucy /plans/demo.jmx
3635
```
3736
For 5 test instances in N. Virginia, `docker run` would look like this, assuming your `jmeter-key.pem` file is located in the `keys` subdirectory:
@@ -44,50 +43,44 @@ docker run -v $PWD/plans:/plans -v $PWD/keys:/keys -v $PWD/logs:/logs \
4443
--env SUBNET_ID=subnet-12345678 \
4544
--env KEY_NAME=jmeter-key \
4645
--env MINION_COUNT=5 \
47-
--enc INSTANCE_TYPE=t2.small \
4846
smithmicro/lucy /plans/demo.jmx
4947
```
5048

5149
## Architecture
52-
This Docker image replaces the JMeter master/slave nomenclature with *Gru*, *Minion* and *Lucy*. *Gru* manages the *Minions* from within EC2, but *Lucy* orchestrates the entire process.
50+
This Docker image replaces the JMeter master/slave nomenclature with *Gru*, *Minion* and *Lucy*. *Gru* manages the *Minions* from within ECS, but *Lucy* orchestrates the entire process.
5351

5452
```
55-
+-------------------------------------+
56-
| EC2 +-----------------+ |
57-
| | ECS | |
58-
| | +--------+ | |
59-
| +---------+ | | +--------+ | | +--------+
60-
| | |---->| | +--------+ ---------->| |
61-
| | Gru |<----| | | | ---------->| Target |
62-
| | | | +-| | Minion | ---------->| |
63-
| +---------+ | +-| | | | +--------+
64-
| ^ | | +--------+ | |
65-
| | | +-----------------+ |
66-
+------|-|----------------------------+
67-
| |
68-
.jmx | | .log/.jtl
69-
| v
70-
+----------+
71-
| |
72-
| Lucy |
73-
| |
74-
+----------+
53+
+--------------------------------------+
54+
| EC2 |
55+
| +--------------------------------+ |
56+
| | ECS | |
57+
| | +--------+ | |
58+
| | +-------+ | +--------+ | | +--------+
59+
| | | |---->| | +--------+ ---------->| |
60+
| | | Gru |<----| | | | ---------->| Target |
61+
| | | | +-| | Minion | ---------->| |
62+
| | +-------+ +-| | | | +--------+
63+
| | ^ | +--------+ | |
64+
| +-----|-|------------------------+ |
65+
+--------|-|---------------------------+
66+
| |
67+
.jmx | | .log/.jtl
68+
| v
69+
+----------+
70+
| |
71+
| Lucy |
72+
| |
73+
+----------+
7574
```
7675

7776
*Lucy* runs the `lucy.sh` script to perform the following steps:
78-
* Step 1 - Create an ECS Cluster
79-
* Step 2 - Create all instances and register them with the Cluster
80-
* Step 3 - Create the Minion ECS task
81-
* Step 4 - Wait until the instances are running and registered with the Cluster
82-
* Step 5 - Fetch our Contatiner Instance IDs
83-
* Step 6 - Run a Minion Task with the requested instance count
84-
* Step 7 - Get public IP addresses from Gru and Minions
85-
* Step 8 - Run Gru with the specified JMX
86-
* JMeter does its thing here
87-
* Once complete, copy the jmeter.log and results.jtl files from Gru to Lucy
88-
* Step 9 - Stop all Tasks
89-
* Step 10 - Terminate all instances
90-
* Step 11 - Delete the cluster
77+
* Step 1 - Create 2 ECS Clusters
78+
* Step 2 - Fetch our Contatiner Instance IDs
79+
* Step 3 - Run a Minion Task with the requested instance count
80+
* Step 4 - Get IP addresses from Gru and Minions
81+
* Step 5 - Run Gru with the specified JMX
82+
* Step 6 - Fetch the results
83+
* Step 7 - Delete the clusters
9184

9285
### Volumes
9386
The `lucy` container uses 3 volumes:
@@ -128,6 +121,28 @@ docker-compose up
128121
```
129122
Using the `docker-compose scale` command does not work as it creates hostnames like `minion_1`. This causes an error in JMeter as it uses the hostname in URL form and sees the underscore as an illegal URL character.
130123

124+
## Notes
125+
The following required and optional environment variables are supported:
126+
127+
| Variable | Required | Default | Notes |
128+
|---|---|---|---|
129+
|AWS_DEFAULT_REGION|Yes|None|AWS Region (e.g. us-east-1)|
130+
|AWS_ACCESS_KEY_ID|Yes|None|AWS Access Key|
131+
|AWS_SECRET_ACCESS_KEY|Yes|None|AWS Secret Key|
132+
|INPUT_JMX|Yes|None|File path of JMeter Test file to run (.jmx). You can optionally specify this as the first command line option of `docker run`|
133+
|KEY_NAME|Yes|None|AWS Security Key Pair .pem file (do not specify the .pem extension)|
134+
|SECURITY_GROUP|Yes|None|AWS Secuirty group that allows ports 22,1099,50000,51000/tcp and 4445/udp from all ports (e.g. sg-12345678)|
135+
|SUBNET_ID|Yes|None|One or more Subnets that are assigned to your VPC|
136+
|VPC_ID||VPC assigned to SUBNET_ID|We dautomatically erive this from your SUBNET_ID|
137+
|JMETER_VERSION||latest|smithmicro/lucy Image tag. See Docker Hub for [available versions](https://hub.docker.com/r/smithmicro/jmeter/tags/).|
138+
|INSTANCE_TYPE||t2.micro|To double your memory, pass t2.small|
139+
|MEM_LIMIT||950m|If you are using t2.small, set MEM_LIMIT to 1995m|
140+
|MINION_COUNT||2||
141+
|PEM_PATH||/keys|This must match your Volume map. See Volume section above.|
142+
|MINION_CLUSTER_NAME||JMeterMinion|Name that appears in your AWS Cluster UI|
143+
|GRU_CLUSTER_NAME||JMeterGru|Name that appears in your AWS Cluster UI|
144+
|GRU_PRIVATE_IP||(blank)|Set to true if you would like to run Lucy within AWS. See GitHub [Issue 8](https://github.com/smithmicro/jmeter-ecs/issues/8) for details.|
145+
131146
## Notes
132147
This Docker image uses the Instance Metadata API documented here:
133148
* http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
@@ -138,6 +153,7 @@ To get the instance public hostname within the `entrypoint.sh` script, we call:
138153
For more information on JMeter Distributed Testing, see:
139154
* http://jmeter.apache.org/usermanual/remote-test.html
140155

156+
141157
## Inspired by...
142158
https://en.wikipedia.org/wiki/Despicable_Me_2
143159

aws-setup.sh

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ if [ "$CIDR_BLOCK" == '' ]; then
99
# create a CIDR block at 10.74, the 74 being ASCII 'J'
1010
CIDR_BLOCK=10.74.0.0/16
1111
fi
12-
if [ "$SUBNET_CIDR_BLOCK" == '' ]; then
12+
if [ "$SUBNET_CIDR_BLOCK1" == '' ]; then
1313
# this CIDR limits us to 251 JMeter Minions - protection from a typo trying to create 1000 instances
14-
SUBNET_CIDR_BLOCK=10.74.1.0/24
14+
SUBNET_CIDR_BLOCK1=10.74.1.0/24
15+
fi
16+
if [ "$SUBNET_CIDR_BLOCK2" == '' ]; then
17+
# this CIDR limits us to 251 JMeter Minions - protection from a typo trying to create 1000 instances
18+
SUBNET_CIDR_BLOCK2=10.74.2.0/24
1519
fi
1620
if [ "$OWNER" == '' ]; then
1721
OWNER=jmeter-ecs
@@ -39,10 +43,12 @@ echo "Created VPC $VPC_ID"
3943
# enable DNS hostnames
4044
aws ec2 modify-vpc-attribute --vpc-id $VPC_ID --enable-dns-hostnames --output text
4145

42-
# create a single subnet
43-
SUBNET_ID=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $SUBNET_CIDR_BLOCK \
46+
# create a 2 subnets
47+
SUBNET_ID1=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $SUBNET_CIDR_BLOCK1 \
48+
--query 'Subnet.[SubnetId]' --output text | tr -d '\n')
49+
SUBNET_ID2=$(aws ec2 create-subnet --vpc-id $VPC_ID --cidr-block $SUBNET_CIDR_BLOCK2 \
4450
--query 'Subnet.[SubnetId]' --output text | tr -d '\n')
45-
echo "Created Subnet $SUBNET_ID"
51+
echo "Created Subnets $SUBNET_ID1,$SUBNET_ID2"
4652

4753
# Step 2: Make Your Subnet Public
4854
IGW_ID=$(aws ec2 create-internet-gateway --query 'InternetGateway.[InternetGatewayId]' --output text | tr -d '\n')
@@ -59,12 +65,14 @@ if [ "$CREATE_ROUTE_RESULT" == 'True' ]; then
5965
echo "Created route for all traffic to the Internet Gateway"
6066
fi
6167

62-
# make this a public subnet
63-
RTBASSOC_ID=$(aws ec2 associate-route-table --subnet-id $SUBNET_ID --route-table-id $RTB_ID --output text | tr -d '\n')
64-
echo "Created Route Table Association $RTBASSOC_ID"
68+
# make these public subnet
69+
RTBASSOC_ID1=$(aws ec2 associate-route-table --subnet-id $SUBNET_ID1 --route-table-id $RTB_ID --output text | tr -d '\n')
70+
RTBASSOC_ID2=$(aws ec2 associate-route-table --subnet-id $SUBNET_ID2 --route-table-id $RTB_ID --output text | tr -d '\n')
71+
echo "Created Route Table Associations $RTBASSOC_ID1,$RTBASSOC_ID2"
6572

6673
# we need public IP addresses so instances can register with ECS clusters
67-
aws ec2 modify-subnet-attribute --subnet-id $SUBNET_ID --map-public-ip-on-launch
74+
aws ec2 modify-subnet-attribute --subnet-id $SUBNET_ID1 --map-public-ip-on-launch
75+
aws ec2 modify-subnet-attribute --subnet-id $SUBNET_ID2 --map-public-ip-on-launch
6876

6977
# create a security group for JMeter
7078
SG_ID=$(aws ec2 create-security-group --group-name "JMeter" --description "JMeter Security Group" --vpc-id $VPC_ID --output text | tr -d '\n')
@@ -74,11 +82,11 @@ JMETER_IP_PERMISSIONS='[{"IpProtocol": "tcp", "FromPort": 22, "ToPort": 22, "IpR
7482
aws ec2 authorize-security-group-ingress --group-id $SG_ID --ip-permissions "$JMETER_IP_PERMISSIONS"
7583

7684
# tag all created resources
77-
aws ec2 create-tags --resources $VPC_ID $SUBNET_ID $IGW_ID $RTB_ID $SG_ID --tags $VPC_TAGS --output text
85+
aws ec2 create-tags --resources $VPC_ID $SUBNET_ID1 $SUBNET_ID2 $IGW_ID $RTB_ID $SG_ID --tags $VPC_TAGS --output text
7886

7987
echo "******** Use these two enviroment variables in 'docker run'"
80-
echo " --env SUBNET_ID=$SUBNET_ID'"
81-
echo " --env SECURITY_GROUP=$SG_ID'"
88+
echo " --env SUBNET_ID=$SUBNET_ID1,$SUBNET_ID2"
89+
echo " --env SECURITY_GROUP=$SG_ID"
8290
echo "********"
8391

8492
# ensure we have the Role name 'ecsInstanceRole' created

lucy/Dockerfile

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,20 @@ ENV AWS_DEFAULT_REGION=
1212

1313
# Install the AWS CLI
1414
RUN apk add --update --no-cache \
15+
ca-certificates \
1516
openssh-client \
17+
openssl \
1618
python \
1719
py-pip \
1820
&& pip install \
1921
awscli
2022

21-
# copy our entrypoint script and Task definition
22-
COPY lucy.sh minion.json /opt/jmeter/
23+
# Install the ECS CLI
24+
RUN wget -O /usr/local/bin/ecs-cli -q https://s3.amazonaws.com/amazon-ecs-cli/ecs-cli-linux-amd64-latest \
25+
&& chmod +x /usr/local/bin/ecs-cli
26+
27+
# copy our entrypoint script and compose file for the Minions
28+
COPY lucy.sh lucy.yml /opt/jmeter/
2329
RUN chmod +x /opt/jmeter/lucy.sh
2430

2531
WORKDIR /logs

0 commit comments

Comments
 (0)