CloudFormation helper scripts

CloudFormation提供了几个Python脚本来帮助用户处理EC2资源,包括cfn-init, cfn-signal, cfn-hup

  • 默认CloudFormation helper script已经安装在Amazon Linux AMI上,路径在opt/aws/bin;如果想更新到最新版本,可以在userdata中执行yum update -y aws-cfn-bootstrap
  • 如果是其他操作系统,可以下载aws-cfn-bootstrap包来安装

cfn-init

cfn-init helper script会从 AWS::CloudFormation::Init 里读取metadata,然后执行相应的命令。然后CloudFormation执行UserData时,会从stack中取出相应cfn-init命令并执行。例如:

---
Parameters:
  SSHKey:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instance

Resources:
  MyInstance:
    Type: AWS::EC2::Instance
    Properties:
      AvailabilityZone: us-east-1a
      ImageId: ami-009d6802948d06e52
      InstanceType: t2.micro
      KeyName: !Ref SSHKey
      SecurityGroups:
        - !Ref SSHSecurityGroup
      # we install our web server with user data
      UserData: 
        Fn::Base64:
          !Sub |
            #!/bin/bash -xe
            # 获取最新版本的helper script
            yum update -y aws-cfn-bootstrap
            # Start cfn-init
            /opt/aws/bin/cfn-init -s ${AWS::StackId} -r MyInstance --region ${AWS::Region} || error_exit 'Failed to run cfn-init'
    Metadata:
      Comment: Install a simple Apache HTTP page
      AWS::CloudFormation::Init:  # AWS::CloudFormation::Init必须放到资源的Metadata下。
        config:
          packages:
            yum:
              httpd: []
          files:
            "/var/www/html/index.html":
              content: |
                <h1>Hello World from EC2 instance!</h1>
                <p>This was created using cfn-init</p>                
              mode: '000644'
          commands:
            hello:
              command: "echo 'hello world'"
          services:
            sysvinit:
              httpd:
                enabled: 'true'
                ensureRunning: 'true'

  # our EC2 security group
  SSHSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: SSH and HTTP
      SecurityGroupIngress:
      - CidrIp: 0.0.0.0/0
        FromPort: 22
        IpProtocol: tcp
        ToPort: 22
      - CidrIp: 0.0.0.0/0
        FromPort: 80
        IpProtocol: tcp
        ToPort: 80

上面的CloudFormation会创建一台EC2并启动http服务, 创建完成后,登录到ec2上,index.html已被写到里面:

image-20221023104259385

cfn-inituserdata是如此的相像,它们都用于在创建EC2时执行自定义脚本
但它们也有不同点:userdata是纯的bash脚本;而cfn-init是bash脚本层面上做抽象,将它转换为yaml格式