How do I make sure that the CodeDeploy agent is deployed when I use CloudFormation to provision Amazon EC2 instances?

Last updated: 2022-03-11

I'm provisioning my infrastructure and AWS CodeDeploy resources using AWS CloudFormation. How do I make sure that the CodeDeploy agent is installed and running on my Amazon Elastic Compute Cloud (Amazon EC2) instances?

Short description

If you create either of the following resources as the target of a CodeDeploy deployment, then use the cfn-init and cfn-signal helper scripts:

  • AWS::EC2::Instance
  • AWS::AutoScaling::AutoScalingGroup

Before you provision your infrastructure deployment, you can use the helper scripts to fully provision your target instances with the CodeDeploy agent.

Resolution

To use the cfn-init and cfn-signal helper scripts to deploy the CodeDeploy agent, complete the following steps to correctly configure the AWS CloudFormation template.

1.    In a code editor, create a JSON or YAML file to use as the AWS CloudFormation template for your resources.

2.    For the Metadata key, use the AWS::CloudFormation::Init type to include metadata for your instance or launch configuration.

Example Metadata key that uses the AWS::CloudFormation::Init type

"SampleLinuxInstance" : {
            "Type" : "AWS::EC2::Instance",
            "Metadata" : {
                "AWS::CloudFormation::Init" : {
                    "config" : {
                        "packages" : {
                            "yum" : {
                                "ruby" : []
                            }
                        },
                        "files" : {
                            "/home/ec2-user/install" : {
                                "source" : {"Fn::Join" : ["", ["https://aws-codedeploy-", {"Ref" : "AWS::Region"}, ".s3.amazonaws.com/latest/install"]]},
                                "mode" : "000755"
                            }
                        },
                        "commands" : {
                            "00-install-agent" : {
                                "command" : "./install auto",
                                "cwd" : "/home/ec2-user/"
                            },
                            "01-cfn-signal" : {
                                "command" : {"Fn::Join" : ["", ["/opt/aws/bin/cfn-signal -e 0 --stack ", { "Ref": "AWS::StackName" }, " --resource SampleLinuxInstance --region ", { "Ref" : "AWS::Region" }]]}
                            }
                        }
                    }
                }
            },
            "Properties" : {
                ...
            }
        }

Note: The AWS::CloudFormation::Init type includes installation steps for the CodeDeploy agent. It also includes the command to signal back to the CloudFormation stack after you complete the following steps.

3.    Set the UserData property to invoke the cfn-init script.

Example UserData property that invokes the cfn-init script

"Properties" : {
                "InstanceType" : "t2.micro",
                "ImageId" : {"Ref" : "AMI"},
                "IamInstanceProfile" : {"Ref" : "SampleInstanceProfile"},
                "KeyName" : {"Ref" : "SSHKey"},
                "UserData" :  {"Fn::Base64" : {
                    "Fn::Join" : ["", [
                        "#!/bin/bash\n",
                        "yum -y update\n",
                        "yum -y install cfn-bootstrap\n",
                        "/opt/aws/bin/cfn-init -v",
                        " --stack ", { "Ref" : "AWS::StackName" },
                        " --resource SampleLinuxInstance",
                        " --region ", { "Ref" : "AWS::Region" }, 
                        "\n"
                    ]]
                }},
                "Tags" : [
                    {
                        "Key" : {"Ref" : "InstanceTagKey"},
                        "Value" : {"Ref" : "InstanceTagValue"}
                    }
                ]
            }

4.    For the instance resource, configure the CreationPolicy attribute to do the following: Require the Amazon EC2 instance or Amazon EC2 Auto Scaling group to send success signals to CloudFormation within a specific time period.

Example CreationPolicy attribute that requires an Amazon EC2 instance to send success signals to CloudFormation within a specific time period

"SampleLinuxInstance" : {
            "Type" : "AWS::EC2::Instance",
            "CreationPolicy" : {
                "ResourceSignal" : {
                    "Count" : "1",
                    "Timeout" : "PT5M"
                }
            },

5.    To create an explicit dependency for your deployment group resource on the Amazon EC2 instance or Amazon EC2 Auto Scaling group, use the DependsOn attribute.

Example DependsOn attribute that creates an explicit dependency for a deployment group resource

"SampleLinuxCDDeploymentGroup" : {
            "Type" : "AWS::CodeDeploy::DeploymentGroup",
            "DependsOn" : "SampleLinuxInstance",
            "Properties" : {
                "ApplicationName" : {"Ref" : "SampleCDApp"},
                "ServiceRoleArn" : {"Ref" : "ServiceRole"},
                "Ec2TagFilters" : [
                    {
                        "Key" : {"Ref" : "InstanceTagKey"},
                        "Value" : {"Ref" : "InstanceTagValue"},
                        "Type" : "KEY_AND_VALUE"
                    }
                ],
                "Deployment" : {
                    "Revision" : {
                        "RevisionType" : "S3",
                        "S3Location" : {
                            "Bucket" : {"Ref" : "BucketName"},
                            "BundleType" : {"Ref" : "BundleType"},
                            "Key" : {"Ref" : "BundleKey"}
                        }
                    }
                }
            }
        }

6.    To complete the CloudFormation template, include any other additional resources, properties, or outputs required for your environment.

7.    Use the completed template to create a CloudFormation stack.