AWS CloudFormation 模板
什么是 AWS CloudFormation 模板
AWS CloudFormation 模板是一个声明式的 JSON 或 YAML 文件,用于描述你需要运行的 AWS 资源以及它们之间的配置关系。你只需编写一次模板,就可以在任意区域、账户中重复创建一致的资源栈,实现 基础设施即代码(IaC)。相较于手动点击控制台,模板能够避免操作失误、轻松复制环境并纳入版本控制。
简单理解:模板就是你云上架构的蓝图。
模板的基本结构
一个标准的 CloudFormation 模板由以下几个可选且功能明确的段组成。下面将以 YAML 格式为例(也支持 JSON)逐一说明。
---
AWSTemplateFormatVersion: "2010-09-09"
Description: >
这里写模板的用途
Metadata:
# 额外结构化信息
Parameters:
# 用户输入参数
Mappings:
# 静态查找表
Conditions:
# 条件语句
Transform:
# 宏或包含其他模板
Resources:
# 核心:要创建的资源
Outputs:
# 输出信息
AWSTemplateFormatVersion
声明模板格式版本,当前唯一有效值为 "2010-09-09"。该字段可选,但建议始终添加以确保兼容性。
AWSTemplateFormatVersion: "2010-09-09"
Description
一段纯文本描述,用于说明该模板的用途。如果文本较长,可以使用 > 折叠换行。
Description: >
基于AWS最佳实践,
部署带Nginx的EC2实例并配置安全组。
Metadata
存放与模板相关的结构化额外信息,例如控制台界面分组显示参数、定义初始化时需要的文件等。初学者可暂不深入,但要知道这个段存在。
Parameters
允许用户在创建或更新栈时动态传入值,从而提高模板复用性。你可以定义类型、默认值、约束以及描述。
Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues:
- t3.micro
- t3.small
- t3.medium
Description: EC2 实例规格
Mappings
内置的静态查找表,常用于匹配区域、环境等条件下的固定值,比如不同区域的 AMI ID。
Mappings:
RegionAMI:
us-east-1:
AMI: ami-0abcdef1234567890
us-west-2:
AMI: ami-0abcdef1234567891
Conditions
基于输入参数或环境信息,控制是否创建某些资源或设置属性。通常用于区分生产环境与测试环境。
Conditions:
IsProduction: !Equals [!Ref EnvType, production]
Transform
指定模板处理宏,最常用的 AWS::Serverless 用于 SAM 应用,AWS::Include 可引用外部分段模板。基础模板中一般不需要。
Resources(核心)
唯一必选且最核心的段。在这里宣告所有需要创建的 AWS 资源,至少包含一个资源。每个资源声明都包括类型、属性和可选的依赖等。
Resources:
MyEC2Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: ami-12345678
InstanceType: t2.micro
支持的资源类型格式为 AWS::<服务名>::<资源类型>,你可以在 AWS 资源类型参考 中查找所有可用的资源。
Outputs
定义资源栈创建完成后,需要返回给用户或供其他栈使用的信息,例如实例的公网 IP、数据库端点等。输出的值可用于跨栈引用。
Outputs:
WebsiteURL:
Description: 实例的公网 DNS
Value: !GetAtt MyEC2Instance.PublicDnsName
编写你的首个模板:启动一个可访问的 EC2 实例
接下来我们编写一个完整的模板,它将在默认 VPC 中创建一个安全组和一个 Amazon Linux 2 EC2 实例,并输出其公有 DNS。复制以下内容并保存为 first-stack.yaml,然后使用 CloudFormation 控制台或 CLI 上传部署。
---
AWSTemplateFormatVersion: "2010-09-09"
Description: 部署一个带安全组的 EC2 实例,开放 HTTP 访问
Parameters:
InstanceType:
Type: String
Default: t3.micro
AllowedValues: [t3.micro, t3.small]
Description: 选择 EC2 实例规格
Mappings:
RegionAMI:
us-east-1:
AMI: ami-0c02fb55956c7d316
us-west-2:
AMI: ami-0c55b159cbfafe1f0
# 根据部署区域补充更多 AMI
Resources:
# 安全组
WebServerSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: 允许 HTTP 和 SSH 访问
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 80
ToPort: 80
CidrIp: 0.0.0.0/0
- IpProtocol: tcp
FromPort: 22
ToPort: 22
CidrIp: 0.0.0.0/0 # 生产环境中请限制此IP
# EC2 实例
WebServer:
Type: AWS::EC2::Instance
Properties:
ImageId: !FindInMap [RegionAMI, !Ref "AWS::Region", AMI]
InstanceType: !Ref InstanceType
SecurityGroups:
- !Ref WebServerSecurityGroup
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "Hello from CloudFormation" > /var/www/html/index.html
Outputs:
WebsiteURL:
Description: 实例的公网访问地址
Value: !Sub "http://${WebServer.PublicDnsName}"
- Parameters:运行时可以覆盖
InstanceType,增加灵活性。 - Mappings + !FindInMap:根据部署的 AWS 区域自动选择正确的 AMI ID。
- Resources:安全组放行 80 和 22 端口;实例引用安全组并使用
UserData在启动时安装并启动 HTTP 服务。 - Outputs:通过
!Sub拼接出完整的访问 URL。
参数:让模板更灵活
参数是模板的输入接口,使同一个模板可以部署到不同场景。你需要掌握以下几点:
参数类型与约束
CloudFormation 提供了多种参数类型以满足不同需求:
| 类型 | 说明 | 示例 |
|---|---|---|
String |
自由文本 | "MyApp" |
Number |
整数或浮点数 | 3 |
List<Number> |
数值列表 | [80,443] |
CommaDelimitedList |
逗号分隔的字符串列表 | "subnet-1,subnet-2" |
AWS::EC2::VPC::Id |
特定服务的资源类型,提供下拉和校验 | 自动列出账户内 VPC |
AWS::SSM::Parameter::Value<String> |
从 SSM Parameter Store 取值 | 便于统一管理参数 |
通过 AllowedValues, MinLength, MaxValue, ConstraintDescription 等可以进一步限制输入值,降低出错风险。
引用参数
使用内部函数 !Ref 引用参数值:
InstanceType: !Ref InstanceType
同样,!Ref 也可用于引用同一模板内其他资源,对于大多数资源会返回其物理 ID(如 i-1234567890abcdef0),对于 AWS::EC2::Instance 则返回实例 ID。
使用映射与条件
映射实战:根据环境与区域决定配置
结合 Mappings 可以轻松实现多环境、多区域的统一模板。例如根据环境(dev/prod)选取不同的实例规格:
Mappings:
EnvConfig:
dev:
instanceType: t3.micro
prod:
instanceType: t3.large
# 在资源中引用
InstanceType: !FindInMap [EnvConfig, !Ref Environment, instanceType]
其中 Environment 是一个字符串参数,需要用户传入 dev 或 prod。
条件:按需创建资源
条件允许某些资源或属性仅在满足特定表达式时才生效。以下示例只在环境为 prod 时创建 RDS 数据库:
Conditions:
CreateDB: !Equals [!Ref Environment, prod]
Resources:
MyDatabase:
Condition: CreateDB
Type: AWS::RDS::DBInstance
Properties:
Engine: mysql
DBInstanceClass: db.t3.micro
# 其他属性...
条件也可以用于控制属性的值,结合 !If 函数:
Properties:
InstanceType: !If [IsProd, t3.large, t3.micro]
输出:导出关键信息
Outputs 不但用于向用户展示结果,还是 跨栈引用 的关键。导出的输出值可以被其他 CloudFormation 栈通过 Fn::ImportValue 导入,轻松实现分层架构。
Outputs:
VPCId:
Description: 新创建的 VPC ID
Value: !Ref MyVPC
Export:
Name: !Sub "${AWS::StackName}-VPCId"
请注意,被导出的名称必须在同一区域唯一。建议使用 AWS::StackName 作为前缀以避免冲突。
最佳实践与进阶提示
- 始终使用参数化模板:避免硬编码 AMI ID、CIDR 块等,利用 Mappings 或 SSM 参数。
- 善用
AWS::NoValue:当条件不满足时,可移除某个属性而非将其设为空值,避免创建无效配置。 - 利用嵌套栈:将复杂架构拆分为多层、多个模板,通过
AWS::CloudFormation::Stack资源引用,提高可维护性。 - 使用 cfn-lint 和 cfn-nag:在提交模板前进行静态分析,自动发现安全漏洞和语法错误。
- 保护敏感信息:切勿在模板中明文写入密码,应通过
NoEcho参数配合 Secrets Manager 处理。 - 版本控制与变更集:将模板纳入 Git,部署前使用 变更集(Change Set) 预览影响,避免意外中断服务。
- 熟悉内部函数:掌握
!Ref,!Sub,!Join,!GetAtt,!FindInMap,!If,!Select等函数,能让模板更简洁强大。
总结
AWS CloudFormation 模板是自动化管理 AWS 基础设施的基石。理解 Resources、Parameters、Mappings 和 Outputs 等核心段落,配合条件与内置函数,就能编写出健壮、可复用且易于维护的模板。从今天起,放弃手动操作,用代码定义你的云上世界。