如何标记 AWS CloudFormation 创建的实例的根卷?

上次更新时间:2020 年 1 月 16 日

我想标记通过 AWS CloudFormation 创建的 Amazon Elastic Compute Cloud (Amazon EC2) 实例的根卷。

简短描述

Amazon EC2 实例资源的标签属性不会扩展到通过 AWS CloudFormation 创建的卷中。 标记可以限制您对实例进行的控制。这有助于您管理特定资源的成本、限制 AWS Identity and Access Management (IAM) 策略及对其他资源施加类似的控制。

使用 AWS CloudFormation 引导启动可使您对实例的 Amazon Elastic Block Store (Amazon EBS) 根卷进行标记。 引导启动方法通过 AWS::EC2::Instance 资源的 UserData 属性完成。要执行引导启动,在创建好实例后使用 AWS 命令行界面 (AWS CLI) 命令或标准的 PowerShell 命令。

解决方法

使用 AWS CloudFormation 模板创建实例

1.    打开 AWS CloudFormation 控制台

2.    选择创建堆栈,然后选择设计模板

3.    在代码编辑器中的参数选项卡上,选择模板

4.    对于选择模板语言,选择 YAML

5.    复制以下 JSON 或 YAML 模板,然后将该模板粘贴到您的代码编辑器中。

JSON 模板:

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Description": "AWS CloudFormation Sample Template Tagging Root Volumes of EC2 Instances: This template shows how to automatically tag the root volume of the EC2 instances which are created through the CloudFormation template. This is done through the UserData property of the AWS::EC2::Instance resource. **WARNING** This template creates two Amazon EC2 instances and an IAM Role. You will be billed for the AWS resources used if you create a stack from this template.",
  "Parameters": {
    "KeyName": {
      "Type": "AWS::EC2::KeyPair::KeyName",
      "Description": "Name of an existing EC2 KeyPair to enable SSH access to the ECS instances."
    },
    "InstanceType": {
      "Description": "EC2 instance type",
      "Type": "String",
      "Default": "t2.micro",
      "AllowedValues": [
        "t2.micro",
        "t2.small",
        "t2.medium",
        "t2.large",
        "m3.medium",
        "m3.large",
        "m3.xlarge",
        "m3.2xlarge",
        "m4.large",
        "m4.xlarge",
        "m4.2xlarge",
        "m4.4xlarge",
        "m4.10xlarge",
        "c4.large",
        "c4.xlarge",
        "c4.2xlarge",
        "c4.4xlarge",
        "c4.8xlarge",
        "c3.large",
        "c3.xlarge",
        "c3.2xlarge",
        "c3.4xlarge",
        "c3.8xlarge",
        "r3.large",
        "r3.xlarge",
        "r3.2xlarge",
        "r3.4xlarge",
        "r3.8xlarge",
        "i2.xlarge",
        "i2.2xlarge",
        "i2.4xlarge",
        "i2.8xlarge"
      ],
      "ConstraintDescription": "Please choose a valid instance type."
    },
    "InstanceAZ": {
      "Description": "EC2 AZ.",
      "Type": "AWS::EC2::AvailabilityZone::Name",
      "ConstraintDescription": "Must be the name of an availabity zone."
    },
    "WindowsAMIID": {
      "Description": "The Latest Windows 2016 AMI taken from the public Systems Manager Parameter Store",
      "Type": "AWS::SSM::Parameter::Value<String>",
      "Default": "/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base"
    },
    "LinuxAMIID": {
      "Description": "The Latest Amazon Linux 2 AMI taken from the public Systems Manager Parameter Store",
      "Type": "AWS::SSM::Parameter::Value<String>",
      "Default": "/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2"
    }
  },
  "Resources": {
    "WindowsInstance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": {
          "Ref": "WindowsAMIID"
        },
        "InstanceType": {
          "Ref": "InstanceType"
        },
        "AvailabilityZone": {
          "Ref": "InstanceAZ"
        },
        "IamInstanceProfile": {
          "Ref": "InstanceProfile"
        },
        "KeyName": {
          "Ref": "KeyName"
        },
        "UserData": {
          "Fn::Base64": {
            "Fn::Join" : [
              "",
              [
                "<powershell>\n",
                "$AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content\n ",
                "$AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)\n ",
                "$AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content\n ",
                "$ROOT_VOLUME_IDS=((Get-EC2Instance -Region $AWS_REGION -InstanceId $AWS_INSTANCE_ID).Instances.BlockDeviceMappings | where-object DeviceName -match '/dev/sda1').Ebs.VolumeId\n ",
                "$tag = New-Object Amazon.EC2.Model.Tag\n ",
                "$tag.key = \"MyRootTag\"\n ",
                "$tag.value = \"MyRootVolumesValue\"\n ",
                "New-EC2Tag -Resource $ROOT_VOLUME_IDS -Region $AWS_REGION -Tag $tag\n",
                "</powershell>\n"
              ]
            ]
          }
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Ref": "AWS::StackName"
            }
          }
        ],
        "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/sdm",
            "Ebs": {
              "VolumeType": "io1",
              "Iops": "200",
              "DeleteOnTermination": "true",
              "VolumeSize": "10"
            }
          }
        ]
      }
    },
    "LinuxInstance": {
      "Type": "AWS::EC2::Instance",
      "Properties": {
        "ImageId": {
          "Ref": "LinuxAMIID"
        },
        "InstanceType": {
          "Ref": "InstanceType"
        },
        "AvailabilityZone": {
          "Ref": "InstanceAZ"
        },
        "IamInstanceProfile": {
          "Ref": "InstanceProfile"
        },
        "KeyName": {
          "Ref": "KeyName"
        },
        "UserData": {
          "Fn::Base64": {
            "Fn::Join" : [
              "",
              [
                "#!/bin/sh\n",
                "AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)\n",
                "AWS_REGION=${AWS_AVAIL_ZONE::-1}\n",
                "AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)\n",
                "ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)\n",
                "aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue\n"
              ]
            ]
          }
        },
        "Tags": [
          {
            "Key": "Name",
            "Value": {
              "Ref": "AWS::StackName"
            }
          }
        ],
        "BlockDeviceMappings": [
          {
            "DeviceName": "/dev/sdm",
            "Ebs": {
              "VolumeType": "io1",
              "Iops": "200",
              "DeleteOnTermination": "true",
              "VolumeSize": "10"
            }
          }
        ]
      }
    },
    "InstanceRole": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "Service": [
                  "ec2.amazonaws.com"
                ]
              },
              "Action": [
                "sts:AssumeRole"
              ]
            }
          ]
        },
        "Path": "/",
        "Policies": [
          {
            "PolicyName": "taginstancepolicy",
            "PolicyDocument": {
              "Version": "2012-10-17",
              "Statement": [
                {
                  "Effect": "Allow",
                  "Action": [
                    "ec2:Describe*",
                    "ec2:CreateTags"
                  ],
                  "Resource": "*"
                }
              ]
            }
          }
        ]
      }
    },
    "InstanceProfile": {
      "Type": "AWS::IAM::InstanceProfile",
      "Properties": {
        "Path": "/",
        "Roles": [
          {
            "Ref": "InstanceRole"
          }
        ]
      }
    }
  }
}

YAML 模板:

AWSTemplateFormatVersion: 2010-09-09
Description: 'AWS CloudFormation Sample Template Tagging Root Volumes of EC2 Instances:
 This template shows how to automatically tag the root volume of the EC2 instances which are
 created through the CloudFormation template. This is done through the UserData property of 
 the AWS::EC2::Instance resource.
 **WARNING** This template creates two Amazon EC2 instances and an IAM Role.
 You will be billed for the AWS resources used if you create a stack from this template.'
Parameters:
 KeyName:
  Type: AWS::EC2::KeyPair::KeyName
  Description: Name of an existing EC2 KeyPair to enable SSH access to the ECS instances.
 InstanceType:
  Description: EC2 instance type
  Type: String
  Default: t2.micro
  AllowedValues: [t2.micro, t2.small, t2.medium, t2.large, m3.medium, m3.large,
   m3.xlarge, m3.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge,
   c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, c3.large, c3.xlarge,
   c3.2xlarge, c3.4xlarge, c3.8xlarge, r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge,
   r3.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge]
  ConstraintDescription: Please choose a valid instance type.
 InstanceAZ:
  Description: EC2 AZ.
  Type: AWS::EC2::AvailabilityZone::Name
  ConstraintDescription: "Must be the name of an availabity zone."
 WindowsAMIID:
  Description: The Latest Windows 2016 AMI taken from the public Systems Manager Parameter Store
  Type: AWS::SSM::Parameter::Value<String>
  Default: /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base
 LinuxAMIID:
  Description: The Latest Amazon Linux 2 AMI taken from the public Systems Manager Parameter Store
  Type : AWS::SSM::Parameter::Value<String>
  Default: /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2
Resources:
 #Tagging the root volume for the EC2 instances with the Windows OS
 #The commented out powershell commands are to utilize if the AMI has the AWS CLI installed and you prefer that approach.
 WindowsInstance:
  Type: 'AWS::EC2::Instance'
  Properties:
   ImageId: !Ref WindowsAMIID
   InstanceType: !Ref InstanceType
   AvailabilityZone: !Ref InstanceAZ
   IamInstanceProfile: !Ref InstanceProfile
   KeyName: !Ref KeyName
   UserData: 
    Fn::Base64: |
     <powershell>
      $AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content
      $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
      $AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content
      $ROOT_VOLUME_IDS=((Get-EC2Instance -Region $AWS_REGION -InstanceId $AWS_INSTANCE_ID).Instances.BlockDeviceMappings | where-object DeviceName -match '/dev/sda1').Ebs.VolumeId
      $tag = New-Object Amazon.EC2.Model.Tag
      $tag.key = "MyRootTag"
      $tag.value = "MyRootVolumesValue"
      New-EC2Tag -Resource $ROOT_VOLUME_IDS -Region $AWS_REGION -Tag $tag
     </powershell>
    #<powershell>
    #$AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content
    #$AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
    #$AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content
    #$ROOT_VOLUME_IDS =(aws ec2 describe-instances --region eu-west-1 --instance-id $AWS_INSTANCE_ID --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)
    #aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue
    #</powershell>
   Tags:
    - Key: Name
     Value: !Ref 'AWS::StackName'
   BlockDeviceMappings:
    - DeviceName: /dev/sdm
     Ebs:
      VolumeType: io1
      Iops: '200'
      DeleteOnTermination: 'true'
      VolumeSize: '10'
 #Tagging the root volume for EC2 instances with an Unix OS with the AWS CLI installed.
 LinuxInstance:
  Type: 'AWS::EC2::Instance'
  Properties:
   ImageId: !Ref LinuxAMIID
   InstanceType: !Ref InstanceType
   AvailabilityZone: !Ref InstanceAZ
   IamInstanceProfile: !Ref InstanceProfile
   KeyName: !Ref KeyName
   UserData: 
    Fn::Base64: |
     #!/bin/sh
     AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
     AWS_REGION="`echo \"$AWS_AVAIL_ZONE\" | sed 's/[a-z]$//'`"
     AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
     ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)
     aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue
   Tags:
    - Key: Name
     Value: !Ref 'AWS::StackName'
   BlockDeviceMappings:
    - DeviceName: /dev/sdm
     Ebs:
      VolumeType: io1
      Iops: '200'
      DeleteOnTermination: 'true'
      VolumeSize: '10'
 #AMI role given to the instances, the instances need the describe and create tags to complete the UserData
 InstanceRole:
  Type: 'AWS::IAM::Role'
  Properties:
   AssumeRolePolicyDocument:
    Version: 2012-10-17
    Statement:
     - Effect: Allow
      Principal:
       Service:
        - ec2.amazonaws.com
      Action:
       - 'sts:AssumeRole'
   Path: /
   Policies:
    - PolicyName: taginstancepolicy
     PolicyDocument:
      Version: 2012-10-17
      Statement:
       - Effect: Allow
        Action:
         - 'ec2:Describe*'
         - 'ec2:CreateTags'
        Resource: '*'
 InstanceProfile:
  Type: 'AWS::IAM::InstanceProfile'
  Properties:
   Path: /
   Roles:
    - !Ref InstanceRole

6.    在模板的 UserData 部分中,更新 --tags Key=Name,Value=newAMI 以匹配您对 Linux 实例的要求。对于 Windows 实例,更新 $tag.key="MyRootTag"$tag.value="MyRootVolumesValue"。 请参阅下面的 UserData 部分,了解有关 Linux 和 Windows 的示例。

Linux 示例:

#Linux UserData
    UserData:
       Fn::Base64: !Sub |
          #!/bin/bash
          AWS_AVAIL_ZONE=$(curl http://169.254.169.254/latest/meta-data/placement/availability-zone)
          AWS_REGION="`echo \"$AWS_AVAIL_ZONE\" | sed 's/[a-z]$//'`"
          AWS_INSTANCE_ID=$(curl http://169.254.169.254/latest/meta-data/instance-id)
          ROOT_VOLUME_IDS=$(aws ec2 describe-instances --region $AWS_REGION --instance-id $AWS_INSTANCE_ID --output text --query Reservations[0].Instances[0].BlockDeviceMappings[0].Ebs.VolumeId)
          aws ec2 create-tags --resources $ROOT_VOLUME_IDS --region $AWS_REGION --tags Key=MyRootTag,Value=MyRootVolumesValue

Windows 示例:

#Windows UserData with standard Powershell commands (no AWS CLI installed)
      UserData:
         Fn::Base64: !Sub |
          <powershell>
            $AWS_AVAIL_ZONE=(curl http://169.254.169.254/latest/meta-data/placement/availability-zone).Content
            $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
            $AWS_INSTANCE_ID=(curl http://169.254.169.254/latest/meta-data/instance-id).Content
            $ROOT_VOLUME_IDS=((Get-EC2Instance -Region $AWS_REGION -InstanceId $AWS_INSTANCE_ID).Instances.BlockDeviceMappings | where-object DeviceName -match '/dev/sda1').Ebs.VolumeId
            $tag = New-Object Amazon.EC2.Model.Tag
            $tag.key = "MyRootTag"
            $tag.value = "MyRootVolumesValue"
            New-EC2Tag -Resource $ROOT_VOLUME_IDS -Region $AWS_REGION -Tag $tag
          </powershell>

注意:要想使 UserData 使用 AWS CLI 命令,您必须在您的 EC2 实例的 Amazon 系统映像 (AMI) 内安装 AWS CLI。默认情况下,所有 Amazon Linux AMI 上均安装有 AWS CLI。您还必须为您的 EC2 实例附加一个实例配置文件。实例配置文件包括调用 ec2:DescribeInstancesec2:CreateTags API 的权限。

7.    选择创建堆栈图标。

8.    对于堆栈名称,请输入您的堆栈名称。

9.    在参数部分中,根据您的环境需求输入适当的信息,包括您的实例类型、EC2 键对和 AMI。

10.    选择下一步

11.    在选项部分中,输入堆栈的适当信息,然后选择下一步

12.    要启用 AWS CloudFormation 堆栈来创建 IAM 资源,请选中“我确认 AWS CloudFormation 可能会创建 IAM 资源”复选框。

13.    选择创建

标记实例的根卷

1.    打开 Amazon EC2 控制台

2.    在导航窗格的 Elastic Block Store 部分中,选择

3.    在筛选条件字段中,输入您在 AWS CloudFormation 堆栈中设置的标签,以确认卷已做上标记。


这篇文章对您有帮助吗?

我们可以改进什么?


需要更多帮助?