Since first days in my IT career I was struggling between 2 choices to be infrastructure administrator or developer - I like both. Circumstances pushed me to be infrastructure administrator, and for some time development was just my hobby.
In recent years I was discovering more and more tools from AWS, which was bringing my dream to be developer and infrastructure administrator at the same time - tools making Infrastructure as code reality.
One of the tools is AWS Chalice framework
Best definition of Chalice Framework is:
AWS Chalice is a Python Serverless Microframework for AWS and allows you to quickly create and deploy applications that use Amazon API Gateway and AWS Lambda.
Chalice provides developers with the options:
- Quick deploy resources using integrated deploy tool
- Test code locally
Administrators can integrate and deploy Chalice application using CDK, Cloud Formation, Terraform . See AWS blog for CDK deployment
There is always question: Which tool to use - Chalice, SAM, CDK, Flask?
Chalice is suitable for small quick deployment:
- Developer - to quick test applications.
- Deployment in small environment
The scenario #2 is why I exactly decided to use Chalice.
Talking to customer about his EC2 instance pricing, I got the requirements which must be met:
- Windows Server with 2 remote users to login
- No Inbound open ports in Security group - Y-e-e-h!
- No VPN - Guess - this is from Step above
- Outgoing connections are allowed.
- Time zones PST/EST/CET - USA/Europe
- 5 min is ok to start server
- Server needs to be fast, and we need to save money - Y-e-e-h!
- No server management from customer
Solution:
- Deploy Lambda and API Gateway which will start/stop instance when users connect to server - this will save cost, as total server usage is not expected to be more than 12 hours.
- Configure customer side with SSM management plugin installed, and script to start server
- Stop EC2 instance when no user activity for an hour - script inside windows server
Implementation: Step 1
- Docker container with Chalice installed - We are always using containers for Development environment. See Docker file
- Start container
docker run -v ~/chalice:/root/chalice -v /root/.aws:/root/.aws/ -it -p 2022:22 ubuntu:chalice /bin/bash
- In container:
cd chalice
chalice new-project control-ec2
cd control-ec2
python3 -m pip show boto3|grep Version|sed 's/Version: /boto3==/'>>requirements.txt
#this will add the latest boto3 version to requirements for local testing. You do not to do this if you are ok with code
- Edit app.py file:
from chalice import Chalice
import boto3
app = Chalice(app_name='control-ec2')
@app.authorizer(ttl_seconds=30)
def my_auth(auth_request):
# Validate auth_request.token, and then:
return AuthResponse(routes=['/'],
principal_id='arn:aws:ec2:us-west-2:xxxxxxxxxx:root/*')
# Create route to start instance
@app.route('/start/{name}', authorizer=my_auth)
def instance(name):
instances = [name]
ec2 = boto3.client('ec2', region_name='us-west-2')
ec2.start_instances(InstanceIds=instances)
return {'InstanceId started': name}
# Create route to stop instance
@app.route('/stop/{name}', authorizer=my_auth)
def instance_stop(name):
instances = [name]
ec2 = boto3.client('ec2', region_name='us-west-2')
ec2.stop_instances(InstanceIds=instances)
return {'InstanceId stopped': name}
What we are doing here:
- Creating Authorizer which allows only IAM user to invoke API method
- 2 functions to start/stop EC2 instances based on instance Id passed
Note: Change region in boto3 clients and principal id to whatever role/username you need
principal_id='arn:aws:ec2:us-west-2:xxxxxxxxxx:root/*')
- Next run
chalice deploy
orchalice deploy --stage prod
once dev stage is ok
In less than 5 minutes you have it ready
How to invoke API?
*Method 1:
Python code
import requests
from requests_aws_sign import AWSV4Sign
from boto3 import session
session = session.Session()
credentials = session.get_credentials()
region = session.region_name
service = 'execute-api'
url = "REPLACE_THIS_LINE_WITH_URI_AND_INSTANCE_ID"
auth = AWSV4Sign(credentials, region, service)
response = requests.get(url, auth=auth)
print(response.text)
Note: you need to modify code to pass instance Id, or explicitly specify URLs with instance ID - e.g. 2 files to start and stop instance
- There is better method though: use AWS CLI:
aws apigateway test-invoke-method --rest-api-id API_ID --resource-id RESOURCE_ID --http-method GET --path-with-query-string /stop/<instanceId here>
--rest-api-id - returned after chalice deploy or cat .chalice/deployed/prod.json
--resource-id - find in console on particular method , or from
aws apigateway get-resources --rest-api-id API_ID
From solution we implemented only Step 1.
Stay tune how to configure customer side for Steps 2 and 3
Top comments (0)