☰
AWS CloudFormation 实战:通过 UserData 自动为 EC2 根卷打标签(Windows 与 Linux 双系统方案)
2026/10/15 2:58:36 网站建设 项目流程

【免费下载链接】aws-cloudformation-templates

A collection of useful CloudFormation templates

项目地址:https://gitcode.com/gh_mirrors/aw/aws-cloudformation-templates
点击查看免费下载

本文基于开源仓库 aws-cloudformation-templates 中的 TaggingRootVolumesInEC2 解决方案 展开。该方案提供了一份完整的 CloudFormation 模板,它同时创建一台 Linux 实例和一台 Windows 实例,并借助实例资源自身的UserData属性,在系统启动阶段自动为各自的 EBS 根卷打上MyRootTag: MyRootVolumesValue标签。读完本文,你将掌握根卷自动标记的完整架构、双系统下的脚本实现差异、最小权限 IAM 设计,以及通过 CLI 与控制台两种方式部署该模板的完整操作流程。

一、为什么要给 EC2 根卷自动打标签

在真实的生产环境中,EBS 卷(尤其是实例根卷)的标签管理往往容易被忽略。根卷由 AWS 在创建实例时隐式创建,默认不会携带业务维度的标签,这给后续的成本分摊、资源审计、自动化运维(如按标签触发备份、清理、巡检)带来很大不便。

本模板的核心思路是:让实例在首次启动时“自己”给自己的根卷打标签。整个流程不需要人工登录服务器、不需要额外的编排系统,只需在创建实例时注入一段启动脚本,并通过 IAM 角色授予必要的 API 权限即可。模板同时覆盖了 Linux 与 Windows 两种最常见的操作系统,展示了两种完全不同的脚本实现路径。

二、模板资源总览与整体工作流程

模板包含 4 个资源,全部定义在 Tagging_Root_volume.yaml(JSON 版本见 Tagging_Root_volume.json):

资源逻辑名类型作用
WindowsInstanceAWS::EC2::InstanceWindows 2016 实例,启动时通过 PowerShell 脚本标记根卷
LinuxInstanceAWS::EC2::InstanceAmazon Linux 2 实例,启动时通过 AWS CLI 命令标记根卷
InstanceRoleAWS::IAM::Role赋予 EC2 描述实例与创建标签权限的 IAM 角色
InstanceProfileAWS::IAM::InstanceProfile将角色挂载到两台实例的实例配置文件

整体工作流程如下:

  1. CloudFormation 创建两台实例,并将InstanceProfile注入到两台实例中;
  2. 实例首次启动时执行UserData脚本(Linux 为 Shell 脚本,Windows 为 PowerShell);
  3. 脚本通过实例元数据服务(IMDS,地址169.254.169.254)获取可用区、实例 ID 等自身信息;
  4. 脚本根据实例 ID 查询该实例的块设备映射,定位根卷(Linux 下为第一个块设备,Windows 下匹配/dev/sda1)的VolumeId;
  5. 调用aws ec2 create-tags(Linux)或New-EC2Tag(Windows)为该卷写入标签;
  6. 标签写入成功后,即可在 EC2 控制台或通过aws ec2 describe-tags看到根卷上的MyRootTag。

三、模板参数详解

模板定义了 6 个参数,部署时需要根据实际环境填写:

参数类型默认值说明
KeyNameAWS::EC2::KeyPair::KeyName无已有的 EC2 密钥对名称,用于 SSH/RDP 登录实例
InstanceTypeStringt2.micro实例类型,模板通过AllowedValues限定了 t2、m3、m4、c4、c3、r3、i2 系列共 31 种可选值,默认t2.micro
InstanceAZAWS::EC2::AvailabilityZone::Name无实例所在的可用区(AZ)
WindowsAMIIDAWS::SSM::Parameter::Value<AWS::EC2::Image::Id>/aws/service/ami-windows-latest/Windows_Server-2016-English-Full-BaseWindows AMI ID,从 Systems Manager 参数库动态获取
LinuxAMIIDAWS::SSM::Parameter::Value<AWS::EC2::Image::Id>/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2Linux AMI ID,同样从 SSM 参数库动态获取
SubnetIdAWS::EC2::Subnet::Id无实例所在的子网

值得注意的是两个 AMI 参数的写法:AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>属于 CloudFormation 的动态引用(Dynamic Reference),模板不会在创建栈时写死某个 AMI,而是从 SSM 公共参数库中读取“最新”的 AMI ID。默认值分别指向 Windows Server 2016 英文全功能版与 Amazon Linux 2 的公共参数路径,因此无需在参数中手工维护 AMI ID(注意:这些默认参数对应的镜像适用于 eu-west-1 等常见区域,跨区域使用时请以目标区域实际存在的公共参数为准)。

四、Linux 实例的根卷标记实现

Linux 实例的UserData是理解整个方案的关键(源码见 Tagging_Root_volume.yaml 中LinuxInstance资源):

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

逐行拆解:

  1. 获取可用区:通过实例元数据服务(IMDS)的placement/availability-zone路径取得可用区,例如eu-west-1a;
  2. 推导区域:可用区去掉最后一个字母即得到区域名,例如eu-west-1a→eu-west-1。这里用sed 's/[a-z]$//'去掉末尾小写字母;
  3. 获取实例 ID:通过元数据服务的instance-id路径取得当前实例 ID;
  4. 定位根卷:调用aws ec2 describe-instances,用--query取出BlockDeviceMappings[0].Ebs.VolumeId(Linux 实例中第一个块设备即根卷)作为目标卷 ID;
  5. 打标签:调用aws ec2 create-tags,写入Key=MyRootTag,Value=MyRootVolumesValue。

UserData通过!Base64内建函数编码注入(JSON 版本使用Fn::Base64)。由于 Amazon Linux 2 默认预装了 AWS CLI,因此无需额外安装工具即可执行aws ec2命令;脚本执行所需的权限来自实例所挂载的 IAM 角色(见下文第六节)。

五、Windows 实例的根卷标记实现

Windows 实例使用 PowerShell 实现同一目标,这也是原文档中强调的“Windows AMI 未预装 AWS CLI 时,可退化为纯 Windows 命令”的路径(源码见同一 yaml 文件中WindowsInstance资源):

$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

实现要点:

  1. 通过curl(PowerShell 中实际调用的是 Web 请求)读取元数据服务,取.Content获得可用区与实例 ID;
  2. 用Substring去掉可用区末位字母得到区域名;
  3. Get-EC2Instance是 AWS Tools for PowerShell(AWSPowerShell 模块)的 cmdlet,返回实例的BlockDeviceMappings,通过where-object DeviceName -match '/dev/sda1'精确匹配 Windows 根卷设备名,取出其Ebs.VolumeId;
  4. 构造Amazon.EC2.Model.Tag对象(key = "MyRootTag"、value = "MyRootVolumesValue");
  5. 调用New-EC2Tagcmdlet 完成打标签。

该路径不依赖 AWS CLI,只依赖 PowerShell 与 AWS Tools for PowerShell 模块——这正是模板对 Windows 镜像兼容性考虑的具体体现:Windows Server 2016 默认预装了 EC2Config / EC2Launch 及 PowerShell,即使目标 AMI 未安装 AWS CLI,模板中的这段脚本依然可以独立完成任务。

六、最小权限 IAM 角色设计

两台实例能够打标签,前提是获得了 IAM 角色授予的权限。模板中的InstanceRole遵循最小权限原则,策略内容如下:

  • 信任策略(AssumeRolePolicyDocument):Principal.Service为ec2.amazonaws.com,Action为sts:AssumeRole,即仅允许 EC2 服务代入该角色;
  • 权限策略(taginstancepolicy):Effect: Allow,Action包含ec2:Describe*与ec2:CreateTags,Resource为*。

其中ec2:Describe*用于支撑describe-instances/Get-EC2Instance查询根卷 ID,ec2:CreateTags用于写入标签,两个权限恰好覆盖脚本全部 API 调用,没有授予多余的高危权限(如ec2:DeleteTags、ec2:RunInstances)。InstanceProfile资源将InstanceRole绑定为实例配置文件,两台实例通过IamInstanceProfile: !Ref InstanceProfile引用它。

模板同时为两台实例配置了附加块设备映射BlockDeviceMappings(/dev/sdm上的 10 GiB io1 卷,200 IOPS,DeleteOnTermination: true),用于演示实例与数据卷的关系;注意根卷标签逻辑只作用于根卷,不受该附加映射影响。

七、部署方式一:通过 AWS CLI 创建栈

原文档给出了完整的 CLI 命令(部署前请按实际环境替换密钥对、实例类型、可用区与 AMI 参数):

aws cloudformation create-stack \ --stack-name TaggingVolumes \ --template-body file://Tagging_Root_volume.json \ --parameters \ ParameterKey=KeyName,ParameterValue=TestKey \ ParameterKey=InstanceType,ParameterValue=t2.micro \ ParameterKey=InstanceAZ,ParameterValue=eu-west-1 \ ParameterKey=WindowsAMIID,ParameterValue=ami-0d138b26f46625e2f \ ParameterKey=LinuxAMIID,ParameterValue=ami-0fad7378adf284ce0

命令要点:

  • --stack-name TaggingVolumes:栈名可自定义;
  • --template-body file://Tagging_Root_volume.json:指向本地模板文件,仓库同时提供 Tagging_Root_volume.json 与 Tagging_Root_volume.yaml 两种格式,file://路径指向哪个均可;
  • --parameters中的KeyName、InstanceAZ、SubnetId为必填项(模板未设默认值),InstanceType、WindowsAMIID、LinuxAMIID可省略(分别回落到t2.micro与 SSM 参数默认值)。

八、部署方式二:通过 CloudFormation 控制台创建栈

如果不使用 CLI,也可以按原文档的 8 步流程在控制台完成部署:

  1. 打开 CloudFormation 控制台(https://console.aws.amazon.com/cloudformation/home);
  2. 选择Create Stack,然后选择Design template(设计模板);
  3. 在页面底部的Template标签页中,粘贴模板内容(Tagging_Root_volume.json 或 YAML 均可);
  4. 说明:模板中需要根据操作系统与标签需求调整的“核心业务部分”正是UserData属性——修改其中MyRootTag/MyRootVolumesValue的值即可改变写入根卷的标签键值对;
  5. 选择Create stack图标,点击Next,为栈输入名称;
  6. 在Parameters页面填写参数:SSH 密钥对名称(KeyName)、实例类型(InstanceType)以及最重要的 AMI(WindowsAMIID/LinuxAMIID,注意模板默认值面向 eu-west-1 区域);
  7. 点击Next,再点击Next进入审核页;
  8. 在最终创建前,必须勾选确认框,声明 CloudFormation 有权创建 IAM 资源(本模板会创建InstanceRole与InstanceProfile这两个 IAM 资源),否则创建栈会被拒绝。

九、验证结果与使用提醒

栈创建并等实例完成初始化后,可通过以下任一方式验证根卷标签是否写入:

  • 控制台:EC2 控制台 → Volumes,找到实例根卷,查看 Tags 列是否出现MyRootTag: MyRootVolumesValue;
  • CLI:执行aws ec2 describe-tags --filters "Name=resource-id,Values=<VolumeId>"或直接aws ec2 describe-volumes --volume-ids <VolumeId>查看标签。

使用提醒:

  • 会产生费用:模板会创建两台 EC2 实例和一个 IAM 角色,按 AWS 标准计费,验证完毕后记得删除栈(aws cloudformation delete-stack --stack-name TaggingVolumes)以避免持续扣费;
  • AMI 区域差异:模板的 AMI 参数默认值对应 eu-west-1 区域可用的公共参数,其他区域请以目标区域实际的 SSM 参数路径为准;
  • UserData 只在首次启动执行:标签写入依赖首次启动注入的脚本,实例重启不会重复执行;若根卷在实例启动后才被替换,需要重新触发标记逻辑;
  • 标签权限:若自定义镜像未安装 AWS CLI 或 AWS Tools for PowerShell,Linux 路径需要预装 AWS CLI,Windows 路径则按模板中保留的“纯 Windows 命令”写法(即未注释的Get-EC2Instance/New-EC2Tag方案)执行即可。

十、小结

本模板是“实例自我标记”模式的一个典型示范:用UserData+ IAM 实例配置文件替代人工运维,在实例生命周期的最早期完成根卷标签初始化,让后续基于标签的成本分析与自动化治理拥有可靠的数据基础。仓库中的 README 概述了整体思路与部署步骤,YAML 与 JSON 双格式模板则为两种操作系统分别给出了可直接复用的脚本与权限配置,读者可按需选取其一部署到自己的账号中。

【免费下载链接】aws-cloudformation-templates

A collection of useful CloudFormation templates

项目地址:https://gitcode.com/gh_mirrors/aw/aws-cloudformation-templates
点击查看免费下载

相关推荐

上一篇:如何彻底解决HTML转Word的格式丢失问题:html-to-docx实战指南
下一篇:如何通过MegSpot提升你的视觉分析效率?5个实用技巧揭秘

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询