Sunday, May 18, 2014

AWS automation – CloudFormation bootstrapping early lessons – Part 3

The sample template illustrates a simple bootstrapping scenario; it creates a windows helper instance, which is set up to execute a PowerShell script stored in external repository (S3). You may develop a number of scripts to build, manage, and monitor the VPC and associated resources, this method can be used to deploy those capabilities systematically and automatically.

Everything is built around “WindowInstance”, which has these main components associated with bootstrapping
  •  “UserData” section defines "cloud-init" bootstrapping, which performs the execution of cfn-init
  •   “Metadata” section is defined for "cfn-init" bootstrapping. It installs PowerShell script from S3 to the local directory, and defines the command to run powershell script with
  •  cfn-signal script is used to return the status of command execution back to CloudFormation with the use of a WaitConditionHandle

Note the instance is defined with IAM Instance Profile, which provides it necessary privilege to access external data store, and perform VPC operations.

This simple method works nicely for initial deployment. How to manage ongoing changes? In this simple model, we will pick up new configuration by launching a new instance. We can put the instance behind an auto-scaling group, by terminating the existing instance, a new one will spin up automatically, triggering the execution of updated configurations.

There is an alternative method to trigger updates without launching new instances. AWS has designed cfn-hup to assist with updates by polling the CloudFormation meta-data for changes, and then executes defined actions when a change is detected. Now, instead of recreating the stack and launching a new instance, an update of CloudFormation stack will kick of the configuration change on the running instance. Please see Peter Hancock’s “Updating your AWS bootstrap” for a nice explanation of the technique. 

See sample template below:

{
  "AWSTemplateFormatVersion" : "2010-09-09",

  "Description" : "CF bootstrapping template sample: windows instance running a powershell script, obtained from S3, note how cfn:init defines command to use option switch to run powershell",

  "Parameters" : {
    "KeyPairName" : {
      "Description" : "Name of an existing Amazon EC2 key pair",
      "Type" : "String",
 "Default" : "xxx"
    },
"WindowInstanceSubnet" : {
      "Description" : "Subnet ID to launch instance",
      "Type" : "String",
      "Default" : "subnet-xxx"
    },

    "WindowInstanceSGs": {
    "Description": "Comma-delimited list of Security Group IDs for instance",
    "Type": "CommaDelimitedList",
      "Default": "sg-xxx, sg-xxx"
    },
    "InstanceType" : {
      "Description" : "Amazon EC2 instance type",
      "Type" : "String",
      "Default" : "t1.micro",
      "AllowedValues" : [ "t1.micro", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "c1.medium", "c1.xlarge"]
    }
  },

  "Mappings" : {
    "AWSInstanceType2Arch" : {
      "t1.micro"   : { "Arch" : "64" },
      "m1.small"   : { "Arch" : "64" },
      "m1.medium"  : { "Arch" : "64" },
      "m1.large"   : { "Arch" : "64" },
      "m1.xlarge"  : { "Arch" : "64" },
      "m2.xlarge"  : { "Arch" : "64" },
      "m2.2xlarge" : { "Arch" : "64" },
      "m2.4xlarge" : { "Arch" : "64" },
      "c1.medium"  : { "Arch" : "64" },
      "c1.xlarge"  : { "Arch" : "64" }
    },
    "AWSRegionArch2AMI" : {
      "us-east-1"      : {"64" : "ami-dfcdc4b6"},
      "us-west-1"      : {"64" : "ami-c2cef187"},
      "us-west-2"      : {"64" : "ami-16197726"},
      "eu-west-1"      : {"64" : "ami-fde21e8a"},
      "ap-southeast-1" : {"64" : "ami-08f5a45a"},
      "ap-southeast-2" : {"64" : "ami-7377ee49"},
      "ap-northeast-1" : {"64" : "ami-514e3e50"},
      "sa-east-1"      : {"64" : "ami-35319228"}
    }
  },

  "Resources" : {
    "InstanceRole":{
      "Type":"AWS::IAM::Role",
        "Properties" : {
          "AssumeRolePolicyDocument" : {
            "Statement": [{
              "Effect" : "Allow",
              "Principal" : {
                "Service" : [ "ec2.amazonaws.com" ]
              },
              "Action" : [ "sts:AssumeRole" ]
            }]
          },
          "Path" : "/"
        }
    },
      
    "RolePolicies" : {
      "Type" : "AWS::IAM::Policy",
      "Properties" : {
        "PolicyName" : "VPCupdate",
        "PolicyDocument" : {
          "Statement" : [
{
            "Action" : [ "ec2:*" ],
            "Effect" : "Allow",
            "Resource" : "*"
},
{
            "Action" : [ "s3:*" ],
            "Effect" : "Allow",
            "Resource" : "*"
}
 ]
        },
        "Roles" : [ { "Ref" : "InstanceRole" } ]
      }
    },
      
    "InstanceProfile" : {
      "Type":"AWS::IAM::InstanceProfile",
      "Properties" : {
        "Path" : "/",
        "Roles" : [ { "Ref":"InstanceRole" } ]
      }
    },

  "WindowInstance": {
      "Type" : "AWS::EC2::Instance",
      "Metadata" : {
        "AWS::CloudFormation::Init" : {
          "config" : {
            "files" : {
              "C:\\cfn\\yourscript.ps1" : {
                "source" : "https://s3.amazonaws.com/your-cfn-repo/yourscript.ps1"
              }
            },
            "commands" : {
     "1-update" : {
  "command" : "powershell.exe -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -File C:\\cfn\\yourscript.ps1"
              }
            }
            
          }
        }
      },
      "Properties": {
        "InstanceType" : { "Ref" : "InstanceType" },
        "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" },
                      { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] },
         "Tags":[
            {
                  "Key":"Name",
                  "Value":"WindowInstance"
            }
        ],
"IamInstanceProfile" : { "Ref" : "InstanceProfile" },
        "SubnetId" : { "Ref" : "WindowInstanceSubnet" },
        "SecurityGroupIds" : { "Ref" : "WindowInstanceSGs" },
        "KeyName" : { "Ref" : "KeyPairName" },
        "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
                ""
          ]]}}
        }
    },

    "WindowInstanceWaitHandle" : {
      "Type" : "AWS::CloudFormation::WaitConditionHandle"
    },

    "WindowInstanceWaitCondition" : {
      "Type" : "AWS::CloudFormation::WaitCondition",
      "DependsOn" : "WindowInstance",
      "Properties" : {
        "Handle" : {"Ref" : "WindowInstanceWaitHandle"},
        "Timeout" : "500"
      }
    }
  },

  "Outputs" : {
...
  }
}

No comments:

Post a Comment