- 云原生
- 运维
- 安全
【免费下载链接】cloud-custodian
Rules engine for cloud security, cost optimization, and governance, DSL in yaml for policies to query, filter, and take actions on resources
本文基于 docs/source/aws/examples/ebssnapshots.rst 提供的官方示例,深入讲解如何用 Cloud Custodian 的 YAML 策略完成 EBS 快照的全生命周期管理:为 EC2 实例的卷批量创建快照并把实例标签复制到快照上,再通过年龄过滤自动删除超过 7 天的旧快照,实现"永远保留最近 7 天滚动快照"的备份治理闭环。读完本文,你将掌握snapshot动作的完整参数语义、ebs-snapshot资源与age过滤器的组合用法,以及源码级的行为细节与常见坑位。
策略全景:两段式快照生命周期管理
官方示例由两条策略组成,一条负责"创建",一条负责"清理",配合起来就是一套可持续运行的滚动备份方案:
- 创建策略:遍历所有 EC2 实例,对其挂载的 EBS 卷执行快照,同时把实例的关键运维标签(如负责人、用途、成本中心、环境等)复制到快照上,并打上自定义标记;
- 清理策略:扫描当前账号自有的快照,筛出年龄 ≥ 7 天且带有 custodian 快照标记的,逐一删除。
两条策略分别面向ec2与ebs-snapshot两个资源类型,前者使用snapshot动作,后者使用delete动作,恰好对应 Cloud Custodian 中"对资源执行操作"与"对资源做筛选后清理"的典型范式。
策略一:为 EC2 实例卷创建快照并继承标签
policies: - name: ec2-create-ebs-snapshots resource: ec2 actions: - type: snapshot copy-tags: - CreatorName - "Resource Contact" - "Resource Purpose" - Environment - "Billing Cost Center" - Name tags: CloudCustodian: true动作注册与权限要求
该动作在 c7n/resources/ec2.py 中注册为@actions.register('snapshot'),类名为Snapshot(BaseAction)。它声明的 IAM 权限为:
ec2:CreateSnapshotec2:CreateTags
即策略执行时对应的运行角色必须同时具备创建快照与打标签的权限,否则会在运行时被 AWS 拒绝。
参数语义(源码确认)
从动作的 schema 定义(c7n/resources/ec2.py#L1926-L1931)可以看到该动作支持以下参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
copy-tags | 字符串数组 | 无 | 把列出的实例/卷标签复制到快照上,与copy-volume-tags互斥 |
copy-volume-tags | boolean | true | 复制卷上的全部标签到快照 |
tags | object | {'custodian_snapshot': ''} | 创建时额外附加的自定义标签 |
exclude-boot | boolean | false | 是否排除启动卷(root volume)不打快照 |
几个关键行为需要特别留意:
默认行为是复制卷的全部标签。源码注释明确写着 "The default behavior is
copy-volume-tags: true"(c7n/resources/ec2.py)。只有当策略中显式出现copy-tags时,才会走"按名单复制"的逻辑。copy-tags与copy-volume-tags不能同时出现。动作的validate()方法会在策略加载阶段直接抛出PolicyValidationError(c7n/resources/ec2.py),即这是一个在运行前就会被拦截的配置错误。tags的默认值非常关键:当未显式指定tags时,快照会被自动打上custodian_snapshot标签(源码见get_snapshot_tags,c7n/resources/ec2.py)。这正是官方示例第二条策略中用"tag:custodian_snapshot": present过滤的前提。
底层实现:批量卷快照与错误兜底
Snapshot.process_volume_set(c7n/resources/ec2.py)展示了真正的执行细节:
- 调用的是 EC2 的
CreateSnapshots(批量卷快照)接口而非单卷的CreateSnapshot,并通过InstanceSpecification指定InstanceId与ExcludeBootVolume; - 快照描述被固定为
Snapshot Created for {InstanceId} ({Name}),便于在控制台/API 中快速溯源; - 创建成功后,快照 ID 列表被写入资源的
c7n:snapshots属性,供后续动作或输出使用; - 对
InvalidInstanceId.NotFound、ConcurrentSnapshotLimitExceeded、IncorrectState三类已知错误做了降级处理(仅记录 warning 不中断整批任务),其余错误则向上抛出并记录到resources的错误日志中。
官方示例的copy-tags名单里既有裸键(CreatorName、Environment、Name),也有带空格的键("Resource Contact"等),说明该列表支持任意合法的实例标签键名,YAML 中带空格或特殊字符的键记得加引号。
策略二:删除超过 7 天的旧快照
- name: ebs-delete-old-ebs-snapshots resource: ebs-snapshot filters: - type: age days: 7 op: ge - "tag:custodian_snapshot": present actions: - deleteebs-snapshot 资源:默认只扫自己的快照
ebs-snapshot在 c7n/resources/ebs.py 中注册,底层使用 EC2 的describe_snapshots枚举。它的resources()方法有两个值得注意的默认行为:
OwnerIds未指定时强制为['self'],即只扫描当前账号自有的快照,绝不会碰共享快照或公共快照;MaxResults默认 1000,配合分页可覆盖大账号下的海量快照。
同时,SnapshotQueryParser(c7n/resources/ebs.py)支持在query中直接传递 AWS 原生的快照查询条件,例如owner-id、status(pending/completed/error)、tag、tag-key、volume-id、start-time、volume-size等,可以在枚举阶段就收窄扫描范围,降低 API 调用成本。
age 过滤器:按时间老化筛选
age是 Cloud Custodian 内置的通用过滤器,语义为"资源存在时间"。官方示例中:
days: 7指定 7 天为阈值;op: ge表示"大于等于"(资源年龄 ≥ 7 天即命中)。
因此该过滤器精确命中"创建于 7 天前或更早"的快照。需要反向匹配时可将op换成lt(小于)。由于快照的StartTime即创建时间,age过滤器在此场景下天然成立。
标签存在性过滤:只清理自己产生的快照
第二条过滤条件"tag:custodian_snapshot": present是 Cloud Custodian 的标签值过滤器语法:当快照带有custodian_snapshot标签(无论值是什么)即命中。它的价值在于把"我们策略创建的快照"与"人工或其他工具创建的快照"区分开,避免误删手工保留的备份。
delete 动作:默认保护 AMI 关联快照
SnapshotDelete(c7n/resources/ebs.py)实现删除逻辑,权限要求为ec2:DeleteSnapshot。源码揭示了两个重要的安全设计:
- 默认自动过滤 AMI 关联快照:删除前会调用
_filter_ami_snapshots剔除与任何 AMI 关联的快照("by default to keep things safe"),并在日志中记录被自动过滤的数量; - 批量与重试:快照按 50 个一组分块提交删除,并对
RequestLimitExceeded、Client.RequestLimitExceeded等限流错误自动重试,适合大规模清理场景。
若确有需要连同 AMI 相关快照一起处理,可在动作中显式声明skip-ami-snapshots: false(该参数在 schema 中定义,见 c7n/resources/ebs.py),但请务必确认业务上不依赖这些 AMI。
组合运行:如何把两条策略跑起来
将两条策略放入同一个 YAML 文件后,用标准命令执行即可:
custodian run -c ebs-snapshots.yml -s output/-c指定策略文件路径;-s指定输出目录(资源 JSON、日志、metrics 等会落到该目录)。
两条策略互不依赖、顺序无关:创建策略产出的快照天然带有custodian_snapshot标记,7 天后清理策略自然命中它们。把该命令接入 cron / EventBridge 定时调度(例如每天运行一次),即可实现文档标题所描述的"始终保留最近 7 天的滚动快照窗口"。
实战提醒:标记一致性决定清理是否生效
这是最容易踩的坑,且可以从源码直接推导出来:
get_snapshot_tags(c7n/resources/ec2.py)的逻辑是——tags参数一旦被显式指定,就用你给的标签替代默认值;只有未指定tags时,才自动补上custodian_snapshot标签。因此官方示例中tags: CloudCustodian: true意味着快照上不会有custodian_snapshot标签:
- 此时第二条策略的
"tag:custodian_snapshot": present过滤将匹配不到任何快照,删除策略实际不会生效; - 想要两条策略无缝衔接,应二选一:
- 创建策略不写
tags,让默认的custodian_snapshot标签生效(CloudCustodian标记可通过copy-tags里的Name等或后续动作补充); - 或者在
tags中显式同时写入custodian_snapshot,如tags: {CloudCustodian: true, custodian_snapshot: true}。
- 创建策略不写
这一点在官方仓库的测试 tests/test_ebs.py 中有直接佐证:test_volume_snapshot_copy_tags用copy-tags时断言快照标签包含custodian_snapshot;而test_volume_snapshot_copy_volume_tags显式给出tags时,断言快照标签与给定标签完全一致、不再有默认标记。
验证与扩展
仓库中的单元测试为上述行为提供了可复现的验证入口(使用 placebo 回放录制数据):
- tests/test_ebs.py
test_volume_snapshot_copy_tags:验证copy-tags按名单复制并附加默认custodian_snapshot标签; - tests/test_ebs.py
test_volume_snapshot_copy_volume_tags:验证显式tags完全覆盖默认标签; - tests/test_ebs.py 附近的
test_snapshot_copy等用例覆盖了快照复制与删除的完整调用链。
在此基础上,你还可以自然扩展出更多场景:用exclude-boot: true只为数据卷打快照以节省成本;在ebs-snapshot策略的query中加入status: completed只处理完成态快照;或叠加value过滤器按VolumeSize进一步收敛清理范围。把握住snapshot动作的参数语义与ebs-snapshot资源的过滤体系,一套适合自己团队的 EBS 快照治理策略就能快速落地。
- 云原生
- 运维
- 安全
【免费下载链接】cloud-custodian
Rules engine for cloud security, cost optimization, and governance, DSL in yaml for policies to query, filter, and take actions on resources
相关推荐
Cloud Custodian Azure 标签管理实战:用 untag 动作批量清理虚拟机标签
Cloud Custodian Azure 标签管理实战:用 untag 动作批量清理虚拟机标签 导读 本文围绕 Cloud Custodian(c7n)Azu
云原生运维安全Operator SDK v1.39.0 升级指南:Kubernetes 1.31 与 Kubebuilder NetworkPolicy 脚手架迁移实战
Operator SDK v1.39.0 升级指南:Kubernetes 1.31 与 Kubebuilder NetworkPolicy 脚手架迁移实战 导读
云原生运维安全LibrePhotos 缺失照片机制详解:标记原理、自动重链与批量清理实战
LibrePhotos 缺失照片机制详解:标记原理、自动重链与批量清理实战 当照片文件被移动、重命名或存储介质断开时,LibrePhotos 不会直接删除数据库
后端前端移动开发计算机视觉机器学习
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考