diff --git a/.ebextensions/resources.config b/.ebextensions/resources.config index 6f1f318..f89a0a9 100644 --- a/.ebextensions/resources.config +++ b/.ebextensions/resources.config @@ -21,7 +21,7 @@ Resources: Properties: FromPort: "9876" ToPort: "9876" - GroupName: { "Ref": "AWSEBSecurityGroup" } + GroupId: { "Fn::GetAtt": ["AWSEBSecurityGroup", "GroupId"] } IpProtocol: "tcp" SourceSecurityGroupId: { "Fn::GetAtt": ["AWSEBSecurityGroup", "GroupId"] } FollowerToMaster: @@ -29,6 +29,6 @@ Resources: Properties: FromPort: "5557" ToPort: "5558" - GroupName: { "Ref": "AWSEBSecurityGroup" } + GroupId: { "Fn::GetAtt": ["AWSEBSecurityGroup", "GroupId"] } IpProtocol: "tcp" SourceSecurityGroupId: { "Fn::GetAtt": ["AWSEBSecurityGroup", "GroupId"] } diff --git a/.ebextensions/setup.config b/.ebextensions/setup.config index 0638058..e9c4014 100644 --- a/.ebextensions/setup.config +++ b/.ebextensions/setup.config @@ -14,9 +14,12 @@ packages: gcc-c++: [] python: pyzmq: [ "16.0.3" ] - locustio: [ "0.8.1" ] + locustio: [ "0.9.0" ] + bs4: [] option_settings: + aws:elasticbeanstalk:command: + DeploymentPolicy: AllAtOnce aws:elasticbeanstalk:application:environment: MASTER_IP_TABLE: '`{ "Ref" : "MasterIPTable"}`' EB_ENV_NAME: '`{"Ref" : "AWSEBEnvironmentName"}`' diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000..048d491 --- /dev/null +++ b/.env.sample @@ -0,0 +1,13 @@ +# Service configuration variables + +LOCUST_TARGET_URL = "https://www.YourWebSite.com" # Set the target website URL +SERVICE_PROFILE_NAME="elasticbeanstalk-locust-profile" # Keep this as default +SERVICE_PROFILE_FILE_PATH = "./iam-profile.yaml" # Keep this as default +SERVICE_INSTANCE_TYPE="c3.large" +SERVICE_REGION = "eu-west-1" +SERVICE_SCALE = "10" +SERVICE_ENV = "test" +SERVICE_CNAME = "$(SERVICE_ENV)-taherbs-locust" +SERVICE_VPC = vpc-XXXXXX #Eb app VPC ID +SERVICE_EC2_SUBNETS = subnet-XXXXXX #Eb app EC2 subnets +SERVICE_ELB_SUBNETS = subnet-XXXXXX #Eb app ALB subnets diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d354ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.elasticbeanstalk/* +!.elasticbeanstalk/*.cfg.yml +!.elasticbeanstalk/*.global.yml +.virtualenv +.env +site-locustfile.py +.DS_Store diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fabbb1f --- /dev/null +++ b/Makefile @@ -0,0 +1,60 @@ +# makefile for automating service deployment + +# Load env vars +include .env +VARS:=$(shell sed -ne 's/ *\#.*$$//; /./ s/=.*$$// p' .env ) +$(foreach v,$(VARS),$(eval $(shell echo export $(v)="$($(v))"))) + +.PHONY: profile-create +profile-create: + aws cloudformation create-stack --stack-name $(SERVICE_PROFILE_NAME) \ + --region $(SERVICE_REGION) \ + --template-body file://$(SERVICE_PROFILE_FILE_PATH) \ + --parameters ParameterKey=InstanceProfileName,ParameterValue=$(SERVICE_PROFILE_NAME) \ + --capabilities CAPABILITY_NAMED_IAM + aws cloudformation wait stack-create-complete --stack-name $(SERVICE_PROFILE_NAME) \ + --region $(SERVICE_REGION) + echo "elasticbeanstalk-locust-role stack created..." + +.PHONY: profile-delete +profile-delete: + aws cloudformation delete-stack --stack-name $(SERVICE_PROFILE_NAME) \ + --region $(SERVICE_REGION) + aws cloudformation wait stack-delete-complete --stack-name $(SERVICE_PROFILE_NAME) \ + --region $(SERVICE_REGION) + echo "elasticbeanstalk-locust-role stack deleted..." + +.PHONY: profile-check +profile-check: + aws iam get-instance-profile --instance-profile-name $(SERVICE_PROFILE_NAME) 1>/dev/null + +.PHONY: eb-init +eb-init: + eb init -r $(SERVICE_REGION) -p "Java 8" + +.PHONY: eb-deploy +eb-deploy: profile-check eb-init + eb create --instance_type $(SERVICE_INSTANCE_TYPE) \ + --scale $(SERVICE_SCALE) \ + --instance_profile $(SERVICE_PROFILE_NAME) \ + --cname $(SERVICE_CNAME) \ + --branch_default $(SERVICE_ENV) \ + --vpc.id $(SERVICE_VPC) \ + --vpc.ec2subnets $(SERVICE_EC2_SUBNETS) \ + --vpc.elbsubnets $(SERVICE_ELB_SUBNETS) \ + --vpc.elbpublic --vpc.publicip \ + --envvars TARGET_URL=$(LOCUST_TARGET_URL) \ + --region $(SERVICE_REGION) + +.PHONY: eb-update +eb-update: + eb setenv TARGET_URL=$(LOCUST_TARGET_URL) + eb scale $(SERVICE_SCALE) + eb deploy --staged + +.PHONY: eb-terminate +eb-terminate: + eb terminate --all --force + +.PHONY: terminate-all +terminate-all: eb-terminate profile-delete diff --git a/README.md b/README.md index 3d11e18..92e325b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,38 @@ # AWS Elastic Beanstalk Load Generator Example This sample application uses the [Locust](http://locust.io/) open source load testing tool to create a simple load generator for your applications. The sample test definition *[locustfile.py](locustfile.py)* tests the root of an endpoint passed in as an environment variable *(TARGET_URL)*. For more information on the format of the test definition file, see [Writing a locustfile](http://docs.locust.io/en/latest/writing-a-locustfile.html). +## Requirements: +[AWS Elastic Beanstalk Command Line Interface (CLI)](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html) + +## Usage: + +### Automated Deployment + + 1. Edit/create the *[.env](.env.sample)* file and specify any/all configuration settings for your environment. + + 2. Create IAM Instance Profile + ```bash + make profile-create + ``` + + 3. Deploy the Elastic Beanstalk service + ```bash + make eb-deploy + ``` + + 4. If want to update the target url, update the LOCUST_TARGET_URL attribute in the *[.env](.env)* file then run: + ```bash + make eb-update + ``` + *Note:* git stage your changes before running the update so EB take on consideration your changes. + + 5. Terminate the application + ```bash + make eb-terminate # terminate the eb application + make terminate-all # terminate the eb application and delete the IAM Instance Profile + ``` + +### Manual Deployment You can get started using the following steps: 1. [Install the AWS Elastic Beanstalk Command Line Interface (CLI)](http://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install.html). 2. Create an IAM Instance Profile named **aws-elasticbeanstalk-locust-role** with the policy in [policy.json](policy.json). For more information on how to create an IAM Instance Profile, see [Create an IAM Instance Profile for Your Amazon EC2 Instances](https://docs.aws.amazon.com/codedeploy/latest/userguide/how-to-create-iam-instance-profile.html). @@ -26,3 +58,16 @@ You can get started using the following steps: 8. When you are done with your tests, run `eb terminate --all` to clean up. *Note: Running Locust in distributed mode requires a master/slave architecture. This sample requires that the auto scaling minimum and maximum be set to the same value to ensure that the master isn't terminated by auto scaling. If for some reason the master instance is replaced, an `eb deploy` should be all it takes to fix it.* + +### Useful AWS Elastic Beanstalk Command Line Interface: + +```bash +eb open # Open application dashboard +eb status # Check application status +eb deploy # Deploy application changes +eb list -v # Show running applications list +eb logs # Show application logs +eb printenv # List application env variables +eb scale # Scale application +eb setenv TARGET_URL="https://new-url.test.com" # Update application TARGET_URL env variables +``` diff --git a/iam-profile.yaml b/iam-profile.yaml new file mode 100644 index 0000000..7a09682 --- /dev/null +++ b/iam-profile.yaml @@ -0,0 +1,48 @@ +AWSTemplateFormatVersion: '2010-09-09' + +Parameters: + InstanceProfileName: + Description: IAM instance profile name + Type: String + +Resources: + LocustServiceRole: + Type: AWS::IAM::Role + Properties: + RoleName: elasticbeanstalk-locust-role + AssumeRolePolicyDocument: + Statement: + - Effect: Allow + Principal: + Service: + - ec2.amazonaws.com + Action: + - sts:AssumeRole + Policies: + - PolicyName: elasticbeanstalk-locust-policy + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - dynamodb:GetItem + - dynamodb:UpdateItem + Resource: + - 'arn:aws:dynamodb:*:*:table/*-stack-MasterIPTable*' + - Effect: Allow + Action: + - autoscaling:DescribeAutoScalingGroups + - cloudformation:ListStackResources + - elasticbeanstalk:DescribeEnvironmentResources + Resource: '*' + LocustServiceProfile: + Type: AWS::IAM::InstanceProfile + Properties: + InstanceProfileName: !Ref InstanceProfileName + Roles: + - !Ref 'LocustServiceRole' +Outputs: + RoleName: + Value: !Ref 'LocustServiceRole' + ProfileName: + Value: !Ref 'LocustServiceProfile' diff --git a/policy.json b/policy.json index cefb0e9..af1df27 100644 --- a/policy.json +++ b/policy.json @@ -25,4 +25,4 @@ ] } ] -} \ No newline at end of file +}