Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Vincent Lesierse
committed
Mar 14, 2018
1 parent
10af7dd
commit cb9907d
Showing
6 changed files
with
157 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
.env | ||
template-packaged.yml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
# aws-ecs-automation | ||
# AWS ECS Automation | ||
Collection of solutions to automate AWS ECS related tasks | ||
|
||
## ECR Deployment Trigger | ||
Lambda function that will create a CloudWatch event rule which will be triggered as soon as a Docker image is pushed to ECR and deploys it automatically to a ECS Cluster. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
# ECR Deployment Trigger | ||
This Lambda function will create a CloudWatch event rule which will be triggered as soon as a Docker image is pushed to ECR and deploys it automatically to a ECS Cluster. | ||
|
||
## Installation | ||
For the installation of this Lambda function you need to take the following steps. | ||
|
||
### Prepare | ||
Use Python 3.6 and [Virtualenv](https://virtualenv.pypa.io/en/stable) to install your virtual environment get the required packages. | ||
|
||
```sh | ||
virtualenv -p python3 --no-site-packages --distribute .env && source .env/bin/activate && pip install -r requirements.txt | ||
``` | ||
|
||
### S3 Bucket | ||
As S3 bucket is required as destination for the AWS SAM package. If you don't have one already, create one: | ||
|
||
```sh | ||
aws s3 mb s3://your-aws-sam-bucket | ||
``` | ||
|
||
### Package | ||
Use the AWS CLI to create and upload the AWS SAM package to S3: | ||
|
||
```sh | ||
aws cloudformation package --template-file template.yml --output-template-file template-packaged.yml --s3-bucket your-aws-sam-bucket | ||
``` | ||
|
||
### Deploy | ||
Use the AWS CLI to deploy the AWS SAM package using CloudFormation: | ||
|
||
```sh | ||
aws cloudformation deploy --capabilities CAPABILITY_IAM --template-file template-packaged.yml --stack-name <YOUR STACK NAME> --parameter-overrides Cluster=<YOUR CLUSTER> | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import os | ||
import boto3 | ||
|
||
|
||
def lambda_handler(event, context): | ||
cluster = os.environ['CLUSTER'] | ||
region = event['region'] | ||
ecs = boto3.client('ecs', region_name=region) | ||
|
||
repositoryName = event['detail']['responseElements']['image']['repositoryName'] | ||
registryId = event['detail']['responseElements']['image']['registryId'] | ||
imageTag = event['detail']['responseElements']['image']['imageId']['imageTag'] | ||
image = f'{registryId}.dkr.ecr.{region}.amazonaws.com/{repositoryName}' | ||
|
||
def get_task_definitions(): | ||
response = ecs.list_task_definition_families(status='ACTIVE') | ||
families = response['families'] | ||
while ('nextToken' in response): | ||
response = ecs.list_task_definition_families(nextToken=response['nextToken']) | ||
families.append(response['families']) | ||
|
||
taskDefinitions = [ecs.describe_task_definition(taskDefinition=family)['taskDefinition'] for family in families] | ||
return [ | ||
taskDefinition for taskDefinition in taskDefinitions | ||
if any([c for c in taskDefinition['containerDefinitions'] if c['image'].startswith(image)]) | ||
] | ||
|
||
def update_task_definition(taskDefinition, newTaskDefinitions, image, imageTag): | ||
family = taskDefinition['family'] | ||
containerDefinitions = taskDefinition['containerDefinitions'] | ||
print(f'Update task definition: {family}') | ||
[ | ||
update_container_definition(containerDefinition, image, imageTag) | ||
for containerDefinition in containerDefinitions | ||
if containerDefinition['image'].startswith(image) | ||
] | ||
|
||
response = ecs.register_task_definition( | ||
family=family, | ||
taskRoleArn=taskDefinition['taskRoleArn'], | ||
containerDefinitions=containerDefinitions, | ||
volumes=taskDefinition['volumes'], | ||
placementConstraints=taskDefinition['placementConstraints'], | ||
requiresCompatibilities=taskDefinition['compatibilities']) | ||
oldTaskDefinitionArn = taskDefinition['taskDefinitionArn'] | ||
newTaskDefinitionArn = response['taskDefinition']['taskDefinitionArn'] | ||
newTaskDefinitions[strip_arn(oldTaskDefinitionArn)] = newTaskDefinitionArn | ||
return newTaskDefinitionArn | ||
|
||
def update_container_definition(containerDefinition, image, imageTag): | ||
print(f'Update container definition to {image}:{imageTag}') | ||
containerDefinition['image'] = f'{image}:{imageTag}' | ||
|
||
def get_services(cluster): | ||
response = ecs.list_services(cluster=cluster) | ||
service_arns = response['serviceArns'] | ||
while ('nextToken' in response): | ||
response = ecs.list_services(cluster=cluster, nextToken=response['nextToken']) | ||
service_arns.append(response['serviceArns']) | ||
return [ | ||
service for service in ecs.describe_services(cluster=cluster, services=service_arns)['services'] | ||
if service['status'] == 'ACTIVE' | ||
] | ||
|
||
def update_service(service, newTaskDefinitionArn): | ||
serviceArn = service['serviceArn'] | ||
print(f'Update service {serviceArn} with {newTaskDefinitionArn}') | ||
response = ecs.update_service(cluster=cluster, service=serviceArn, taskDefinition=newTaskDefinitionArn) | ||
|
||
def strip_arn(arn): | ||
return arn[:arn.rindex(":")] | ||
|
||
# Update Task Definitions | ||
taskDefinitions = get_task_definitions() | ||
|
||
newTaskDefinitions = {} | ||
[update_task_definition(taskDefinition, newTaskDefinitions, image, imageTag) for taskDefinition in taskDefinitions] | ||
|
||
if newTaskDefinitions: | ||
services = get_services(cluster) | ||
# Update Services | ||
[ | ||
update_service(service, newTaskDefinitions[strip_arn(service['taskDefinition'])]) | ||
for service in services | ||
if strip_arn(service['taskDefinition']) in newTaskDefinitions.keys() | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
boto3>=1.6.7 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
AWSTemplateFormatVersion: '2010-09-09' | ||
Transform: 'AWS::Serverless-2016-10-31' | ||
Parameters: | ||
Cluster: | ||
Type: String | ||
Description: Name of the ECS Cluster | ||
Resources: | ||
ECRDeploy: | ||
Type: 'AWS::Serverless::Function' | ||
Properties: | ||
Handler: deploy_handler.lambda_handler | ||
Runtime: python3.6 | ||
CodeUri: . | ||
Description: Triggered when a Docker image is pushed to ECR and deploys it automatically to the ECS cluster | ||
Environment: | ||
Variables: | ||
CLUSTER: | ||
Ref: Cluster | ||
Policies: AmazonEC2ContainerServiceFullAccess | ||
Events: | ||
ECRPutImage: | ||
Type: CloudWatchEvent | ||
Properties: | ||
Pattern: | ||
source: | ||
- aws.ecr | ||
detail: | ||
eventSource: | ||
- ecr.amazonaws.com | ||
eventName: | ||
- PutImage |