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

7 分钟阅读
0

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

简短描述

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

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

**注意:**如果在运行 AWS CLI 命令时收到错误,请确保您使用的是最新的 AWS CLI 版本

解决方法

使用 CloudFormation 模板创建实例

1.    打开 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 you how to automatically tag the root volume of the EC2 instances that are created through the AWS 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 Availability 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",
                "try {\n",
                "$AWS_AVAIL_ZONE=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/placement/availability-zone' -UseBasicParsing).Content\n ",
                "$AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)\n ",
                "$AWS_INSTANCE_ID=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/instance-id' -UseBasicParsing).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",
                "}\n",
                "catch {\n",
                "Write-Output $PSItem\n",
                "}\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*"
                  ],
                  "Resource": "*"
                },
                {
                  "Effect": "Allow",
                  "Action": [
                    "ec2:CreateTags"
                  ],
                  "Resource": [
                    {
                      "Fn::Sub": "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:volume/*"
                    },
                    {
                      "Fn::Sub": "arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/*"
                    }
                  ]
                }
              ]
            }
          }
        ]
      }
    },
    "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 you how to automatically tag the root volume of the EC2
  instances that are created through the AWS 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 Availability 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: !Base64
        'Fn::Join':
          - ''
          - - |
              <powershell>
            - |
              try {
            - >-
              $AWS_AVAIL_ZONE=(Invoke-WebRequest -Uri
              'http://169.254.169.254/latest/meta-data/placement/availability-zone'
              -UseBasicParsing).Content

            - |-
              $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)

            - >-
              $AWS_INSTANCE_ID=(Invoke-WebRequest -Uri
              'http://169.254.169.254/latest/meta-data/instance-id'
              -UseBasicParsing).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
            - |
              }
            - |
              catch {
            - |
              Write-Output $PSItem
            - |
              }
            - |
              </powershell>
      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: !Base64
        'Fn::Join':
          - ''
          - - |
              #!/bin/sh
            - >
              AWS_AVAIL_ZONE=$(curl
              http://169.254.169.254/latest/meta-data/placement/availability-zone)
            - |
              AWS_REGION=${AWS_AVAIL_ZONE::-1}
            - >
              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'
  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*'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'ec2:CreateTags'
                Resource:
                  - !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:volume/*'
                  - !Sub 'arn:aws:ec2:${AWS::Region}:${AWS::AccountId}:instance/*'
  InstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref InstanceRole

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

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>
      try {  
      $AWS_AVAIL_ZONE=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/placement/availability-zone' -UseBasicParsing).Content
      $AWS_REGION=$AWS_AVAIL_ZONE.Substring(0,$AWS_AVAIL_ZONE.length-1)
      $AWS_INSTANCE_ID=(Invoke-WebRequest -Uri 'http://169.254.169.254/latest/meta-data/instance-id' -UseBasicParsing).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
      }
      catch {
      Write-Output $PSItem
      }
      </powershell>

**重要事项:**要对 UserData 使用 AWS CLI 命令,必须在 EC2 实例的亚马逊云机器镜像(AMI)中安装 AWS CLI。默认情况下,AWS CLI 安装在所有 Amazon Linux AMI 中。您还必须将实例配置文件附加到 EC2 实例。实例配置文件仅包含对 AWS 区域和账户内的 EC2 卷和实例调用 ec2:DescribeInstancesec2:CreateTags API 的权限。

7.    选择创建堆栈图标。

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

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

10.    选择下一步

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

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

13.    选择创建

标记实例的根卷

1.    打开 Amazon EC2 控制台

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

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


AWS 官方
AWS 官方已更新 3 年前