【免费下载链接】aws-cloudformation-templates
A collection of useful 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):
| 资源逻辑名 | 类型 | 作用 |
|---|---|---|
WindowsInstance | AWS::EC2::Instance | Windows 2016 实例,启动时通过 PowerShell 脚本标记根卷 |
LinuxInstance | AWS::EC2::Instance | Amazon Linux 2 实例,启动时通过 AWS CLI 命令标记根卷 |
InstanceRole | AWS::IAM::Role | 赋予 EC2 描述实例与创建标签权限的 IAM 角色 |
InstanceProfile | AWS::IAM::InstanceProfile | 将角色挂载到两台实例的实例配置文件 |
整体工作流程如下:
- CloudFormation 创建两台实例,并将
InstanceProfile注入到两台实例中; - 实例首次启动时执行
UserData脚本(Linux 为 Shell 脚本,Windows 为 PowerShell); - 脚本通过实例元数据服务(IMDS,地址
169.254.169.254)获取可用区、实例 ID 等自身信息; - 脚本根据实例 ID 查询该实例的块设备映射,定位根卷(Linux 下为第一个块设备,Windows 下匹配
/dev/sda1)的VolumeId; - 调用
aws ec2 create-tags(Linux)或New-EC2Tag(Windows)为该卷写入标签; - 标签写入成功后,即可在 EC2 控制台或通过
aws ec2 describe-tags看到根卷上的MyRootTag。
三、模板参数详解
模板定义了 6 个参数,部署时需要根据实际环境填写:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
KeyName | AWS::EC2::KeyPair::KeyName | 无 | 已有的 EC2 密钥对名称,用于 SSH/RDP 登录实例 |
InstanceType | String | t2.micro | 实例类型,模板通过AllowedValues限定了 t2、m3、m4、c4、c3、r3、i2 系列共 31 种可选值,默认t2.micro |
InstanceAZ | AWS::EC2::AvailabilityZone::Name | 无 | 实例所在的可用区(AZ) |
WindowsAMIID | AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> | /aws/service/ami-windows-latest/Windows_Server-2016-English-Full-Base | Windows AMI ID,从 Systems Manager 参数库动态获取 |
LinuxAMIID | AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> | /aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2 | Linux AMI ID,同样从 SSM 参数库动态获取 |
SubnetId | AWS::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逐行拆解:
- 获取可用区:通过实例元数据服务(IMDS)的
placement/availability-zone路径取得可用区,例如eu-west-1a; - 推导区域:可用区去掉最后一个字母即得到区域名,例如
eu-west-1a→eu-west-1。这里用sed 's/[a-z]$//'去掉末尾小写字母; - 获取实例 ID:通过元数据服务的
instance-id路径取得当前实例 ID; - 定位根卷:调用
aws ec2 describe-instances,用--query取出BlockDeviceMappings[0].Ebs.VolumeId(Linux 实例中第一个块设备即根卷)作为目标卷 ID; - 打标签:调用
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实现要点:
- 通过
curl(PowerShell 中实际调用的是 Web 请求)读取元数据服务,取.Content获得可用区与实例 ID; - 用
Substring去掉可用区末位字母得到区域名; Get-EC2Instance是 AWS Tools for PowerShell(AWSPowerShell 模块)的 cmdlet,返回实例的BlockDeviceMappings,通过where-object DeviceName -match '/dev/sda1'精确匹配 Windows 根卷设备名,取出其Ebs.VolumeId;- 构造
Amazon.EC2.Model.Tag对象(key = "MyRootTag"、value = "MyRootVolumesValue"); - 调用
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 步流程在控制台完成部署:
- 打开 CloudFormation 控制台(https://console.aws.amazon.com/cloudformation/home);
- 选择Create Stack,然后选择Design template(设计模板);
- 在页面底部的Template标签页中,粘贴模板内容(Tagging_Root_volume.json 或 YAML 均可);
- 说明:模板中需要根据操作系统与标签需求调整的“核心业务部分”正是
UserData属性——修改其中MyRootTag/MyRootVolumesValue的值即可改变写入根卷的标签键值对; - 选择Create stack图标,点击Next,为栈输入名称;
- 在Parameters页面填写参数:SSH 密钥对名称(
KeyName)、实例类型(InstanceType)以及最重要的 AMI(WindowsAMIID/LinuxAMIID,注意模板默认值面向 eu-west-1 区域); - 点击Next,再点击Next进入审核页;
- 在最终创建前,必须勾选确认框,声明 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
相关推荐
ToolJet 在 AWS EC2 上的部署实战指南:基于 AMI 与 CloudFormation 的完整方案
ToolJet 在 AWS EC2 上的部署实战指南:基于 AMI 与 CloudFormation 的完整方案 本指南完整讲解如何在 AWS EC2 上部署
低代码后端前端AI 应用MCP 服务Telegraf aws_ec2 处理器插件完全指南:为指标自动附加 AWS EC2 元数据标签
Telegraf aws_ec2 处理器插件完全指南:为指标自动附加 AWS EC2 元数据标签 导读 aws_ec2 是 Telegraf 内置的流式处理器(
可观测性指标监控运维从装好到收到第一声广播:SDR++ 软件定义无线电接收上手指南
从装好到收到第一声广播:SDR++ 软件定义无线电接收上手指南 SDR++ 是一款跨平台的开源软件定义无线电(SDR)接收软件,支持 Windows、Linux
桌面应用通信
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考