CloudFormation 基础设施即代码

AWS CloudFormation 是 AWS 的原生基础设施即代码(IaC)服务。

核心概念

基础设施即代码(IaC)

传统 vs IaC:

传统部署方式:
├─ 手动点击控制台
├─ 配置不一致
├─ 难以复制
├─ 无版本控制
├─ 容易出错
└─ 难以审计

IaC 方式:
├─ 代码定义基础设施
├─ 版本控制
├─ 可复现
├─ 自动化部署
├─ 代码审查
└─ 自我文档化

IaC 的优势:

速度
├─ 快速部署环境
├─ 批量创建资源
└─ 自动化流程

一致性
├─ 消除配置漂移
├─ 环境标准化
└─ 减少人为错误

可靠性
├─ 测试验证
├─ 回滚能力
└─ 灾难恢复

可扩展性
├─ 轻松复制环境
├─ 多区域部署
└─ 模块化复用

CloudFormation 架构

┌──────────────────────────────────┐
│      模板(Template)             │
│      ├─ JSON/YAML 格式           │
│      ├─ 声明式语法               │
│      └─ 描述所需资源             │
└────────────┬─────────────────────┘
             │
             ▼
┌──────────────────────────────────┐
│      堆栈(Stack)                │
│      ├─ 资源的集合               │
│      ├─ 生命周期管理             │
│      └─ 整体操作                 │
└────────────┬─────────────────────┘
             │
    ┌────────┴────────┐
    │                 │
┌───▼───────┐   ┌─────▼──────┐
│ 创建资源   │   │  更新资源   │
│ 删除资源   │   │  回滚变更   │
└───────────┘   └────────────┘

模板结构

模板组成部分

AWSTemplateFormatVersion: '2010-09-09'
Description: 'VPC and EC2 infrastructure'

# 元数据(可选)
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "Network Configuration"
        Parameters:
          - VpcCIDR
          - SubnetCIDR

# 参数(可选)
Parameters:
  EnvironmentName:
    Type: String
    Default: Development
    AllowedValues:
      - Development
      - Staging
      - Production
  InstanceType:
    Type: String
    Default: t3.micro
    AllowedValues:
      - t3.micro
      - t3.small
      - t3.medium

# 映射(可选)
Mappings:
  RegionAMI:
    us-east-1:
      AMI: ami-0c55b159cbfafe1f0
    us-west-2:
      AMI: ami-0d1cd67c26f5fca19

# 条件(可选)
Conditions:
  IsProduction: !Equals [!Ref EnvironmentName, Production]
  CreateBackup: !And
    - !Condition IsProduction
    - !Equals [!Ref EnableBackup, 'true']

# 资源(必需)
Resources:
  MyVPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: !Sub '${EnvironmentName}-VPC'

  MyEC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref InstanceType
      ImageId: !FindInMap [RegionAMI, !Ref 'AWS::Region', AMI]
      SubnetId: !Ref MySubnet
      Tags:
        - Key: Environment
          Value: !Ref EnvironmentName

# 输出(可选)
Outputs:
  VPCId:
    Description: VPC ID
    Value: !Ref MyVPC
    Export:
      Name: !Sub '${AWS::StackName}-VPC-ID'
  InstanceId:
    Description: EC2 Instance ID
    Value: !Ref MyEC2Instance

内置函数

引用函数:

# Ref - 引用参数或资源
!Ref ParameterName
!Ref LogicalResourceId

# GetAtt - 获取资源属性
!GetAtt MyInstance.PublicDnsName
!GetAtt MyDB.Endpoint.Address

条件函数:

# Equals - 相等比较
!Equals [!Ref EnvironmentName, Production]

# If - 条件判断
!If [IsProduction, t3.large, t3.micro]

# And/Or/Not - 逻辑运算
!And [Condition1, Condition2]
!Or [Condition1, Condition2]
!Not [Condition1]

字符串函数:

# Sub - 字符串替换
!Sub '${EnvironmentName}-VPC'
!Sub 
  - 'arn:aws:s3:::${BucketName}/*'
  - BucketName: !Ref MyBucket

# Join - 字符串连接
!Join ['-', [!Ref EnvironmentName, 'VPC']]

# Split - 字符串分割
!Split [',', 'a,b,c']

查找函数:

# FindInMap - 映射查找
!FindInMap [RegionAMI, !Ref 'AWS::Region', AMI]

# ImportValue - 导入其他堆栈的输出
!ImportValue OtherStack-VPC-ID

# Select - 选择列表元素
!Select [0, !GetAZs '']

堆栈管理

堆栈生命周期

创建堆栈:

提交模板
    │
    ▼
验证语法
    │
    ▼
按依赖顺序创建资源
    │
    ├─ 资源 A
    ├─ 资源 B(依赖 A)
    └─ 资源 C(依赖 B)
    │
    ▼
CREATE_COMPLETE(全部成功)
  或
CREATE_FAILED(部分失败)
    │
    └─ 自动回滚(可选)

更新堆栈:

变更集(Change Set)
├─ 预览变更
├─ 评估影响
├─ 批准执行
└─ 安全更新

更新行为:
├─ 无中断(No Interruption)
│   └─ 在线更新,不影响服务
├─ 某些中断(Some Interruption)
│   └─ 短暂中断
└─ 替换(Replacement)
    └─ 删除重建资源

删除堆栈:

删除策略:
├─ Delete(默认)
│   └─ 删除堆栈时删除资源
├─ Retain
│   └─ 保留资源(手动管理)
└─ Snapshot
    └─ 删除前创建快照(RDS、EBS)

删除顺序:
├─ 按依赖关系逆序删除
├─ 子资源先删除
└─ 父资源后删除

堆栈策略

防止意外更新:

{
  "Statement": [
    {
      "Effect": "Deny",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "LogicalResourceId/ProductionDB"
    },
    {
      "Effect": "Allow",
      "Action": "Update:*",
      "Principal": "*",
      "Resource": "*"
    }
  ]
}

作用:
├─ 保护关键资源
├─ 防止误删除
├─ 强制审批流程
└─ 生产环境必备

嵌套堆栈

模块化设计

架构:

主堆栈(Parent Stack)
├─ 网络堆栈(Nested Stack)
│   ├─ VPC
│   ├─ Subnets
│   └─ Route Tables
├─ 安全堆栈(Nested Stack)
│   ├─ Security Groups
│   └─ Network ACLs
├─ 计算堆栈(Nested Stack)
│   ├─ EC2 Instances
│   └─ Auto Scaling Groups
└─ 数据库堆栈(Nested Stack)
    ├─ RDS
    └─ ElastiCache

优势:

可重用性
├─ 标准化模块
├─ 跨项目共享
└─ 减少重复

可维护性
├─ 单一职责
├─ 独立更新
└─ 易于理解

可扩展性
├─ 模块化添加功能
├─ 组合复杂架构
└─ 团队协作

嵌套堆栈示例:

Resources:
  NetworkStack:
    Type: AWS::CloudFormation::Stack
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-templates/network.yaml
      Parameters:
        VpcCIDR: 10.0.0.0/16
        PublicSubnetCIDR: 10.0.1.0/24
      TimeoutInMinutes: 30

  ComputeStack:
    Type: AWS::CloudFormation::Stack
    DependsOn: NetworkStack
    Properties:
      TemplateURL: https://s3.amazonaws.com/my-templates/compute.yaml
      Parameters:
        VPCId: !GetAtt NetworkStack.Outputs.VPCId
        SubnetId: !GetAtt NetworkStack.Outputs.PublicSubnetId

StackSets

多账户/多区域部署

概念:

单个模板 → 多个堆栈
├─ 跨 AWS 账户
├─ 跨 AWS 区域
├─ 集中管理
└─ 一致性保证

使用场景:
├─ 组织级别基线配置
├─ 安全标准部署
├─ 跨区域灾备
└─ 多环境一致性

部署策略:

并行部署
├─ 同时创建所有实例
├─ 速度最快
└─ 风险较高

顺序部署
├─ 逐个创建实例
├─ 速度较慢
└─ 风险可控

金丝雀部署
├─ 先部署到测试账户
├─ 验证成功后全量部署
└─ 最安全

Drift Detection

配置漂移检测

概念:

配置漂移(Configuration Drift)
├─ 实际资源状态
│   与
├─ 模板定义状态
│   不一致

原因:
├─ 手动修改资源
├─ 其他工具修改
├─ 控制台操作
└─ 未通过 CloudFormation 更新

检测流程:

触发漂移检测
    │
    ▼
CloudFormation 比较
├─ 模板定义
└─ 实际状态
    │
    ▼
生成漂移报告
├─ 漂移资源列表
├─ 属性差异
└─ 预期值 vs 实际值
    │
    ▼
修复漂移
├─ 更新堆栈(覆盖手动修改)
└─ 更新模板(保留手动修改)

最佳实践

1. 模板组织

目录结构:

cloudformation/
├── templates/
│   ├── network/
│   │   ├── vpc.yaml
│   │   └── subnets.yaml
│   ├── compute/
│   │   ├── ec2.yaml
│   │   └── autoscaling.yaml
│   └── database/
│       └── rds.yaml
├── parameters/
│   ├── dev.json
│   ├── staging.json
│   └── prod.json
└── policies/
    └── stack-policy.json

2. 参数化

环境差异化:

# 开发环境参数
{
  "ParameterKey": "InstanceType",
  "ParameterValue": "t3.micro"
},
{
  "ParameterKey": "MinSize",
  "ParameterValue": "1"
},
{
  "ParameterKey": "MaxSize",
  "ParameterValue": "2"
}

# 生产环境参数
{
  "ParameterKey": "InstanceType",
  "ParameterValue": "m5.large"
},
{
  "ParameterKey": "MinSize",
  "ParameterValue": "3"
},
{
  "ParameterKey": "MaxSize",
  "ParameterValue": "10"
}

3. 标签策略

统一标签:

Tags:
  - Key: Environment
    Value: !Ref EnvironmentName
  - Key: Project
    Value: !Ref ProjectName
  - Key: CostCenter
    Value: !Ref CostCenter
  - Key: Owner
    Value: !Ref OwnerEmail
  - Key: ManagedBy
    Value: CloudFormation

4. 变更管理

变更流程:

1. 创建变更集
   ├─ 预览影响
   └─ 评估风险

2. 代码审查
   ├─ 团队评审
   └─ 安全检查

3. 批准执行
   ├─ 获得批准
   └─ 执行变更

4. 验证结果
   ├─ 功能测试
   └─ 性能验证

5. 监控告警
   ├─ 观察指标
   └─ 响应问题

5. 版本控制

Git 工作流:

main(生产)
├─ 已部署到生产的稳定版本
├─ 受保护分支
└─ 需要审批合并

staging
├─ 预生产环境
├─ 集成测试
└─ UAT

develop
├─ 开发分支
├─ 功能集成
└─ 持续集成

feature/*
├─ 功能开发
└─ 开发者分支

故障排查

常见问题

1. 创建失败:

排查步骤:
├─ 查看堆栈事件
├─ 识别失败资源
├─ 检查错误消息
├─ 验证权限
└─ 检查配额限制

常见原因:
├─ 资源命名冲突
├─ IAM 权限不足
├─ 资源限制(VPC 数量)
├─ 依赖关系错误
└─ 参数验证失败

2. 更新卡住:

UPDATE_IN_PROGRESS 超时

可能原因:
├─ 资源更新卡住
├─ Auto Scaling 无法达到期望数量
├─ ELB 健康检查失败
└─ 等待信号超时

解决方法:
├─ 检查资源日志
├─ 验证依赖服务
├─ 手动干预(如需要)
└─ 回滚变更

3. 删除失败:

DELETE_FAILED 状态

常见原因:
├─ 资源被其他服务使用
├─ S3 bucket 非空
├─ RDS 删除保护
└─ 手动创建的依赖资源

解决方法:
├─ 清理依赖
├─ 禁用删除保护
├─ 保留策略(Retain)
└─ 手动删除资源

CloudFormation vs Terraform

对比

特性 CloudFormation Terraform
供应商 AWS 原生 HashiCorp
多云支持 仅 AWS 支持多云
语法 JSON/YAML HCL
状态管理 AWS 管理 需要配置后端
成本 免费 开源免费
学习曲线 中等 中等
社区 AWS 文档 丰富的社区

选择建议

选择 CloudFormation:

  • 仅使用 AWS
  • 喜欢原生集成
  • 不想管理状态
  • 使用 AWS 特性(StackSets)

选择 Terraform:

  • 多云环境
  • 已有 Terraform 经验
  • 需要更灵活的语法
  • 活跃的社区模块

CloudFormation 是 AWS 上实现基础设施即代码的强大工具,掌握它能显著提升运维效率和一致性!