AWS DevOps Blog

Automatic Deployment to New Amazon EC2 On-Demand and Spot Instances Using AWS CodeDeploy, Amazon CloudWatch Events, and AWS Lambda

AWS CodeDeploy is a service that automates application deployments to your compute infrastructure, including fleets of Amazon EC2 instances. AWS CodeDeploy can automatically deploy the latest app version to any new EC2 instance launched due to a scaling event. However, if your servers are not part of the Auto Scaling group, it might be a challenge to automate the code deployment for new EC2 launches. This is especially true if you are running your workload on an EC2 Spot Fleet. In this post, I’ll show you how to use AWS CodeDeploy, an Amazon CloudWatch Events rule, EC2 tags, and AWS Lambda to automate your deployments so that all EC2 instances run the same version of your application.

Solution overview:

An Amazon CloudWatch rule is triggered when a new Amazon EC2 instance is launched. The rule invokes an AWS Lambda function that extracts three tags:

· Name
· CodeDeployDeploymentGroup
· CodeDeployApplication

The Lambda function then uses the instance tags to add the EC2 instance to the deployment group. After the instance has been added, Lambda queries AWS CodeDeploy to retrieve the last successful deployment in that deployment group and synchronizes the EC2 instance with the latest code. The following diagram shows the sequence:

 

Note: For an EC2 Spot Fleet, the tags that you create for your Spot instance are not added automatically by the Spot service to fulfill the request. The Lambda function adds these tags after the Spot instance is launched.

 

Example:

Let’s take an example of an AWS CodeDeploy application cd-single-deploy-app, and its deployment group, cd-single-deploy-app-group, which has two instances in it. These instances are not part of an Auto Scaling group.

For information about the steps in deploying an application to an instance, see this tutorial in the AWS CodeDeploy User Guide.

In the AWS CodeDeploy console, you’ll find the deployment ID, d-CSBCXR2GP. We will use this ID later in the testing phase. Our workflow ensures that when a new EC2 instance is launched, it joins the deployment group automatically and the latest version of the application is deployed to it.

You can configure the Lambda function, associated IAM role and policy, and the CloudWatch Events rule by running this CloudFormation template included in the code repository.

https://github.com/awslabs/aws-codedeploy-new-instance-sync-lambda

The CloudFormation template does the following:

Step 1: Create an IAM role named Auto-Deploy-EC2-Codedeploy and attach the following policies:

•	arn:aws:iam::aws:policy/AWSLambdaExecute 
•	arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess 
•	arn:aws:iam::aws:policy/service-role/AmazonEC2SpotFleetTaggingRole 

Use the following JSON document to create another policy named CodeDeploy and attach it to the IAM role.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "codedeploy:Get*",
                "codedeploy:UpdateDeploymentGroup",
                "codedeploy:List*",
                "codedeploy:CreateDeployment"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow",
            "Sid": "StartContinuousAssessmentLambdaPolicyStmt"
        }
    ]
}

Make sure the CodeDeploy role has PassRole permission  to the service role defined in the CodeDeploy deployment group.

Step 2: Follow these steps to create a Lambda function:

https://github.com/awslabs/aws-codedeploy-new-instance-sync-lambda/blob/master/README.md

Step 3: In Amazon CloudWatch Events, set up a rule for running instances and configure the Lambda function as a target.

Step 4: In the AWS Lambda console, choose your Lambda function. On the Triggers tab, check that the trigger is enabled.

You can now test to ensure if a new EC2 instance is launched, it gets synchronized automatically with the latest code

Test:

A new EC2 instance is launched from the EC2 console, the AWS CloudFormation template, or the EC2 APIs with CodeDeployApplication, CodeDeployDeploymentGroup, and Name tag.

 

Go to CloudWatch Logs console to check the Lambda execution logs.

Here is an analysis of sample log:

·  You should see the EC2 instance ID

{[
"arn:aws:EC2:us-east-1:XXXXXXXXXXXX:instance/i-00203362b337dd743"]
}

·  You should see the deployment ID of the last successful deployment. It should match the one you noted earlier

DepId is d-CSBCXR2GP

·    Finally, you should see the deployment ID of the new deployment created by CodeDeploy

"{u'deploymentId': u'd-W6E1TFFGP', 'ResponseMetadata': {'RetryAttempts': 0, '	HTTPStatusCode': 200, 'RequestId': '73046797-bb22-11e7-ad7b-25693e030410', 'HTTPHeaders': {'x-amzn-requestid': '73046797-bb22-11e7-ad7b-25693e030410', 'content-length': '30', 'content-type': 'application/x-amz-json-1.1'}}}
"

Now, go to CodeDeploy console to confirm that the new deployment was successful.

In this screenshot, you can see that the new EC2 instance was synched with latest code.

Summary:

In this post, I’ve demonstrated how to use AWS CodeDeploy, AWS Lambda, an Amazon CloudWatch Events rule, and EC2 tags to automate deployments to disparate EC2 instances. If you are running your workload on Spot instances or have a fleet of On-Demand EC2 instances as part of your application, you can use the steps in this blog post to solve the automation around the deployment for new instances.