原文:
annas-archive.org/md5/cf1c4e1db999839ba88fc56df4011156
译者:飞龙
协议:CC BY-NC-SA 4.0
AWS 平台的增长速度非常快,正在被各行各业广泛采用。正如俗话所说,朋友不会让朋友建立数据中心。不管从哪个角度看,按需计算、网络和存储的模式将持续存在。尤其是当你看到 AWS 平台在功能和增强方面的更新速度时,很难再去反对站在巨人的肩膀上,尤其是与其他云服务提供商或所谓的私有云相比。
我们与许多技术专家合作,他们在各自领域有着深厚的知识,但对于 AWS 平台却可能是全新的。或者,他们可能熟悉 AWS,但对于自动化和基础设施代码实践则是新手。
我们希望为这些人写一本书。
本书旨在通过提供教程、模式和最佳实践,帮助你开启 AWS 之旅,尤其是在我们在咨询工作中常常需要帮助的领域。书中的所有教程和建议都基于我们个人的经验和我们在帮助客户使用 AWS 平台时的观察。
CloudFormation 是 AWS 原生的自动化方法,用于部署 AWS 资源(可重复和可靠),我们在本书中广泛使用它。接下来的教程将帮助你熟悉 CloudFormation,快速开始定制和构建自己的模板。拥有如此强大的功能,可能会让你陷入迷茫。本书旨在引导你走上正确的道路,帮助你以可持续和可维护的方式采用该平台。
第一章,AWS 基础,是对基础设施即代码、CloudFormation 和 AWS CLI 工具的概述。
第二章,管理 AWS 账户,涵盖了你需要了解的所有关于管理账户和开始使用 AWS 组织的内容。
第三章,存储与内容分发,展示了如何备份数据并将文件对象提供给用户。
第四章,使用 AWS 计算,深入讲解了如何在 AWS 上运行虚拟机(EC2 实例),如何进行自动扩展,以及如何创建和管理负载均衡器。
第五章,管理工具,概述了如何审计你的账户并监控你的基础设施。
第六章,数据库服务,展示了如何在 AWS 平台上创建、管理和扩展数据库。
第七章,网络,介绍了私有网络、路由和 DNS。
第八章,安全与身份,提供了关于如何管理身份和基于角色的访问的建议和实用解决方案。
第九章,估算成本,概述了如何估算在 AWS 平台上的花费,以及如何通过购买预留实例容量来降低成本。
本书中的食谱展示了如何在 AWS 上部署多种资源,因此您至少需要一个具有完全管理权限的 AWS 账户。您还需要一个文本编辑器来编辑 YAML/JSON CloudFormation 模板,以及支持常见操作系统(macOS/Linux/Windows)的 AWS CLI 工具。
本书适用于任何具有技术背景、并有兴趣使用 AWS 的人,无论是迁移现有工作负载还是部署全新应用程序。那些希望学习 CloudFormation 的读者也会发现本书非常有用。
在本书中,您会发现几个经常出现的标题(准备就绪、如何做……、它是如何工作的……、更多内容以及另见)。
为了清晰地指示如何完成食谱,我们使用以下这些章节:
本节告诉您在食谱中可以期待的内容,并描述如何设置任何软件或为食谱所需的任何初步设置。
本节包含执行食谱所需的步骤。
本节通常包含对前一节内容的详细解释。
本节包含关于食谱的附加信息,旨在让读者对食谱有更深入的了解。
本节提供了有用的链接,指向与食谱相关的其他有用信息。
在本书中,您会找到几种文本样式,用以区分不同类型的信息。以下是这些样式的一些示例及其含义的解释。
文本中的代码词、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 用户名的显示方式如下:“您现在应该在应用账户下有一个活动会话,使用PowerUserRole
角色。”
一段代码设置如下:
Parameters:
EC2KeyName:
Type: String
Description: EC2 Key Pair to launch with
当我们希望引起您对代码块中特定部分的注意时,相关行或项会以粗体显示:
Parameters:
EC2KeyName:
Type: String
Description: EC2 Key Pair to launch with
任何命令行输入或输出如下所示:
aws ec2 describe-availability-zones --output json
新术语和重要词汇会以粗体显示。您在屏幕上看到的词语,例如在菜单或对话框中出现的词汇,将以这种方式呈现:“点击‘下一步’按钮可以将您带到下一个屏幕。”
警告或重要备注会以这样的框显示:
提示和技巧以这样的方式呈现:
我们欢迎读者的反馈。告诉我们你对这本书的看法——喜欢或不喜欢的部分。读者反馈对我们很重要,因为它帮助我们开发出你真正能从中受益的书籍。
若要向我们发送一般反馈,请直接发送电子邮件至[email protected]
,并在邮件主题中注明书籍标题。
如果你在某个领域有专长,并且有兴趣为书籍写作或贡献内容,请参阅我们的作者指南:www.packtpub.com/authors。
现在你已经是一本 Packt 书籍的骄傲拥有者,我们提供许多帮助你充分利用购买内容的方式。
你可以从www.packtpub.com
的账户中下载这本书的示例代码文件。如果你在其他地方购买了本书,可以访问www.packtpub.com/support
,并注册以将文件直接通过电子邮件发送给你。
你可以按照以下步骤下载代码文件:
使用你的电子邮件地址和密码登录或注册我们的网站。
将鼠标指针悬停在顶部的 SUPPORT 标签上。
点击“代码下载与勘误”。
在搜索框中输入书籍名称。
选择你想下载代码文件的书籍。
从下拉菜单中选择你购买此书的地方。
点击“代码下载”。
你还可以通过点击书籍网页上的“代码文件”按钮下载代码文件。此页面可以通过在搜索框中输入书籍名称访问。请注意,你需要登录 Packt 账户。
文件下载后,请确保使用最新版本的以下工具解压或提取文件夹:
WinRAR / 7-Zip for Windows
Zipeg / iZip / UnRarX for Mac
7-Zip / PeaZip for Linux
书籍的代码包也托管在 GitHub 上,链接为github.com/PacktPublishing/AWS-Administration-Cookbook
。我们还有其他来自丰富书籍和视频目录的代码包,可以在github.com/PacktPublishing/
查看!快去看看吧!
尽管我们已经尽一切努力确保内容的准确性,但错误还是可能发生。如果你在我们的书籍中发现了错误——可能是文本或代码中的错误——我们将非常感激你能向我们报告。通过这样做,你可以帮助其他读者避免困惑,并帮助我们改进后续版本的书籍。如果你发现任何勘误,请通过访问www.packtpub.com/submit-errata
,选择你的书籍,点击勘误提交表单链接,并填写勘误的详细信息。你的勘误经过验证后,将会被接受,勘误内容将会上传到我们的网站或添加到该书籍勘误列表的勘误部分。
要查看先前提交的勘误,请访问www.packtpub.com/books/content/support
并在搜索框中输入书籍名称。所需信息将显示在勘误部分。
互联网盗版版权材料是一个持续存在的问题,涉及所有媒体。在 Packt,我们非常重视保护我们的版权和许可。如果你在互联网上发现了任何形式的我们作品的非法复制品,请立即提供该盗版材料的地址或网站名称,以便我们采取措施。
请通过[email protected]
与我们联系,并提供可疑盗版材料的链接。
我们感谢你在保护我们的作者和确保我们能够为你提供有价值内容方面的帮助。
如果你对本书的任何方面有问题,可以通过[email protected]
与我们联系,我们将尽力解决问题。
在本章中,我们将介绍:
基础设施即代码
AWS CloudFormation
AWS 命令行工具
亚马逊网络服务(AWS)是一个公共云服务提供商。它提供按需付费的基础设施和平台服务。这意味着您可以按需访问曾经需要一次性购买的资源。您可以访问企业级服务,同时只为您所需的部分付费,通常按小时计费。
AWS 以提供开发者所需的基础组件为荣,使他们能够构建和扩展所需的解决方案。
为了跟上教程,您需要一个 AWS 账户。请访问aws.amazon.com/
点击注册按钮并输入您的信息,创建账户。
尽管我们会尽可能利用免费套餐,但您仍然需要一张有效的信用卡来完成注册过程。请访问aws.amazon.com/free/
了解更多信息。请注意,免费套餐仅适用于账户生命周期的第一年。
AWS 的一个基本概念是,其服务及基于这些服务构建的解决方案是 为故障而设计的。这意味着,底层资源的故障是一个积极规划的场景,而不是等到无法忽视时才去避免。
因此,所有可用的服务和资源都被划分到地理上分散的 区域 中。使用特定区域意味着您可以为用户提供速度和性能优化的服务。
在一个区域内,总是有多个 可用区(又称 AZ)。每个 AZ 代表一个地理上独立—但仍然接近—的物理数据中心。AZ 拥有自己的设施和电源,因此,可能导致单个 AZ 离线的事件不太可能影响该区域的其他 AZ。
较小的区域至少有两个 AZ,而最大的区域有五个。
在撰写本文时,以下区域是活跃的:
代码 | 名称 | 可用区 |
---|---|---|
us-east-1 |
北弗吉尼亚 | 5 |
us-east-2 |
俄亥俄州 | 3 |
us-west-1 |
北加利福尼亚州 | 3 |
us-west-2 |
俄勒冈州 | 3 |
ca-central-1 |
加拿大 | 2 |
eu-west-1 |
爱尔兰 | 3 |
eu-west-2 |
伦敦 | 2 |
eu-central-1 |
法兰克福 | 2 |
ap-northeast-1 |
东京 | 3 |
ap-northeast-2 |
首尔 | 2 |
ap-southeast-1 |
新加坡 | 2 |
ap-southeast-2 |
悉尼 | 3 |
ap-south-1 |
孟买 | 2 |
sa-east-1 |
圣保罗 | 3 |
创建 AWS 账户后,您首先会看到的是基于网页的控制台,并且在查看和确认您的配置时,您将经常使用它。
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06326_01_01.png
AWS 网页控制台
控制台提供了所有可用服务的概览,以及相关的计费和费用信息。每个服务都有自己的部分,显示的信息取决于查看的服务。随着新特性和服务的发布,控制台会不断变化和改进。如果你登录时发现界面有所变化,不必惊讶。
请记住,控制台始终按 区域 显示你的资源。如果你看不到已创建的资源,请确保已选择正确的区域。
选择距离你物理位置最近的区域,以获得最快的响应时间。请注意,并非所有区域都有相同的服务可用。较大的老旧区域通常有最多的服务可用。某些较新的或较小的区域(可能离你较近)可能还没有启用所有服务。虽然服务会持续发布到各个区域,但如果你必须使用新服务,可能需要选择其他区域。
us-east-1
(即北弗吉尼亚)区域是特殊的,因为它是第一个区域。所有服务都可以在那里使用,新的服务 总是 首先发布在那里。
随着你对 AWS 使用的熟练度提高,你将在控制台上花费的时间会减少,而更多地通过 AWS CLI 工具和 CloudFormation 以编程方式控制服务,接下来我们将更详细地讨论这些内容。
在可能的情况下,我们已经将食谱(recipe)基于 CloudFormation 模板。CloudFormation 是 AWS 提供的 基础设施即代码 服务。
在 CloudFormation 不适用的情况下,我们使用了 AWS CLI 来使流程具备可重复性和自动化能力。
由于食谱基于 CloudFormation 模板,你可以轻松地将不同的模板结合起来,实现你想要的结果。通过编辑模板或将它们结合在一起,你可以以最小的努力创建更有用和定制化的配置。
基础设施即代码 (IaC) 是通过代码定义来管理基础设施的做法。
在 基础设施即服务 (IaaS) 平台上,例如 AWS,需要使用 IaC 才能最大化效用和价值。IaC 与传统的 交互式 基础设施管理方法的主要区别在于,它是机器可处理的。这带来了诸多好处:
改进的资源可见性
部署和环境之间更高的一致性
更容易的故障排除
能够以更少的努力实现更大的扩展性
更好的成本控制
在更为抽象的层面,所有这些因素也为你的开发人员带来了其他改进:你现在可以利用经过验证的软件开发实践来管理基础设施,并在团队中实现 DevOps 实践。
由于你的基础设施以机器可读的文件形式表示,你可以像对待应用程序代码一样对待它。你可以采用软件开发的最佳实践,并将其应用到你的基础设施中。这意味着你可以像管理代码一样将其存储在版本控制中(例如,Git 和 SVN),并享受它所带来的好处:
所有对基础设施的更改都会记录在提交历史中
你可以在接受/合并之前审查变更
你可以轻松比较不同的配置
你可以选择并使用特定时间点的配置
在各个环境(例如开发、测试和生产环境)中保持一致的配置意味着你可以更加自信地部署基础设施。当你知道正在使用的配置时,由于有一个共同的基准,你可以轻松地在其他环境中测试变更。
IaC 不同于仅仅编写基础设施脚本。大多数工具和服务将利用高级语言和领域特定语言(DSL),使你能够专注于更高层次的需求。它使你能够使用先进的软件开发技术,如静态分析、自动化测试和优化。
IaC 使得复制和故障排除变得更加容易:因为你可以复制你的环境,所以可以准确地重现你的生产环境进行测试。
过去,由于硬件成本过高,测试环境很少有完全相同的基础设施。现在,由于可以按需创建和销毁,你能够仅在需要时复制环境。你只需要为它们运行的时间付费,通常按小时计算。测试完成后,只需关闭环境并停止支付费用。
比故障排除更好的是在问题导致错误之前就修复它们。当你在多个环境中完善你的基础设施即代码(IaC)时,你将获得一种没有它很难获得的自信。在将你的基础设施部署到生产环境时,你已经做过多次了。
手动配置基础设施可能是一个繁琐且容易出错的过程。通过自动化,你消除了手动实现的潜在可变性:计算机擅长无聊的重复任务,所以把这些任务交给它们做吧!
一旦自动化,提供更多资源的劳动成本几乎为零——你已经完成了这项工作。无论你是需要启动一台服务器还是一千台,它都不需要额外的工作。
从实际角度来看,AWS 中的资源几乎没有限制。如果你愿意为此付费,AWS 会让你使用它。
AWS 有着强烈的(商业)利益,希望你能够尽可能容易地提供基础设施。作为客户,你的好处是你可以根据需求创建和销毁这些资源。
显然,在传统的物理硬件环境中按需销毁基础设施是不可能的。你几乎无法找到一个数据中心,允许你仅仅因为当前没有使用服务器和空间,就停止为它们付费。
另一个按需基础设施能够大幅节省成本的使用场景是你的开发环境。只有在有开发人员使用它时,开发环境才有意义。当开发人员下班回家时,你可以关闭开发环境,这样就不需要为其付费了。在开发人员早上来之前,简单地安排他们的环境进行创建。
DevOps 和 IaC 是密切相关的。将你的基础设施(传统上是运营的关注点)作为代码(传统上是开发的关注点)进行存储的做法,促使了责任的共享,从而促进了协作。
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06326_01_02.png
图片来源:维基百科
通过自动化软件开发生命周期中的PACKAGE、RELEASE和CONFIGURE活动(如图所示),你可以提高发布速度,同时增加信心。
基于云的 IaC 鼓励为故障做架构设计:因为你的资源是虚拟化的,所以必须为物理(主机)硬件故障的可能性做计划,尽管这种情况不太可能发生。
能够在几分钟内重建整个环境是终极的恢复解决方案。
与物理硬件不同,你可以通过删除关键组件来轻松模拟和测试软件架构中的故障——反正它们都是虚拟的!
服务器端的 IaC 示例包括配置管理工具,如 Ansible、Chef 和 Puppet。
虽然重要,这些配置管理工具并非 AWS 特有,因此我们在此不会详细介绍。如果你需要了解更多,市面上有无数书籍和课程专门讲解此话题。
CloudFormation 是 AWS 的 IaC 服务。
使用特定格式和语言编写的模板定义了应当配置的 AWS 资源。CloudFormation 是声明式的,不仅可以配置资源,还可以更新它们。
我们将在下一个主题中详细介绍 CloudFormation。
本书中我们将广泛使用 CloudFormation,因此理解它是什么以及它如何融入 AWS 生态系统非常重要。这里的信息应该足以帮助你入门,但在必要时,我们会参考 AWS 的官方文档。
CloudFormation 服务允许你以自动化和可重复的方式配置和管理一组 AWS 资源。在 AWS 术语中,这些资源集合被称为堆栈。不过请注意,堆栈的大小可以根据需要调整。它可以由一个单一的 S3 桶组成,也可以包含托管你三层 Web 应用所需的一切。
在本章中,我们将向你展示如何定义要包含在 CloudFormation 堆栈中的资源。我们会进一步讨论这些堆栈的组成,以及何时和为何更倾向于将资源分配到多个堆栈中。最后,我们将分享一些在构建无数 CloudFormation 堆栈过程中学到的小技巧。
请注意!
几乎每个人在使用 CloudFormation 的过程中都会遇到至少一两个小问题。不过,这一切都是值得的。
到现在为止,自动化的好处应该已经开始显现给你看了。但不要陷入误区,认为 CloudFormation 只对大规模资源集合有用。即使是执行最简单的任务,比如创建一个 S3 桶,如果你需要在每个区域都做一遍,也会变得非常重复。
我们与很多客户合作,这些客户在其基础设施方面有非常严格的控制和治理,尤其是在网络层面(例如 VPC、NACL 和安全组)。能够使用 YAML(或 JSON)表达一个人的云足迹,将其存储在源代码仓库中,并通过高可见性的流水线进行处理,能让这些客户确信他们的基础设施更改已经经过同行评审,并且会在生产环境中按预期工作。当然,遵循 IaC SDLC 实践的纪律性和承诺在其中起着重要作用,但 CloudFormation 帮助我们摆脱了依赖 20 页手动变更清单、应对未追踪或未解释的配置漂移,以及避免因操作失误导致的意外停机的时代。
现在是开始从层次的角度思考你的 AWS 部署的好时机。你的各个层次将会相互叠加,你将会在它们之间定义清晰的关系。
这是一个自下而上的示例,展示了你的层蛋糕可能的样子:
VPC 与 CloudTrail
子网、路由和 NACL
NAT 网关、VPN 或堡垒主机及相关安全组
应用堆栈 1:安全组,S3 桶
应用堆栈 1:跨可用区的 RDS 和只读副本
应用堆栈 1:应用程序和 Web 服务器自动扩展组以及 ELB
应用堆栈 1:CloudFront 和 WAF 配置
在这个示例中,你的 VPC 中可能会有许多应用堆栈层,前提是你的子网中有足够的 IP 地址!这通常出现在开发环境中的 VPC。因此,你可以立即享受到多租户能力与应用隔离的好处。
这种方法的一个优势是,在你开发 CloudFormation 模板时,如果你弄错了应用服务器的配置,你不需要回滚 CFN 为你完成的所有工作。你可以直接删除该特定层(以及依赖它的层),然后从那里重新开始。如果你将所有内容包含在一个单一的模板中,就不可能做到这一点。
我们通常与客户合作,其中每一层的所有权和管理反映了公司内技术部门的结构。传统的基础设施、网络和网络安全人员通常对为数字团队创建安全的应用部署环境感兴趣,因此他们喜欢对基础层进行严格的管理。康威定律(Conway’s Law),由梅尔文·康威提出,在这里开始发挥作用:
“任何设计系统的组织,最终都会产生一个设计,其结构是该组织沟通结构的复制。”
最后,即使你是一个小团队中的单人基础设施开发人员,你也会从这种方法中受益。例如,你会发现它显著减少了你遇到 AWS 限制、超时和循环依赖的风险。
这时我们开始动手实践。CloudFormation 模板文件是你堆栈的编程表示,通常以 YAML 或 JSON 形式表达。当你希望创建 CloudFormation 堆栈时,你将这个模板文件通过 API、Web 控制台、命令行工具或其他方法(例如 SDK)推送到 CloudFormation。
模板可以被 CloudFormation 一次又一次地重放,创建多个堆栈实例。
直到最近,JSON 是唯一的选择。我们实际上鼓励你采用 YAML,并且我们将在本书中使用它作为所有示例。以下是其中一些原因:
它看起来更美观。语法更简洁,如果你选择生成 CloudFormation 模板,几乎每种编程语言都有某种形式的 YAML 库。
你的模板大小将会更小。这从开发人员的角度来看更实用,同时也意味着你更不容易遇到 CloudFormation 模板文件大小限制(50 KB)。
字符串替换功能更易于使用和解释。
你的 EC2 UserData
(当 EC2 实例启动时运行的脚本)将更容易实现和维护。
CloudFormation 模板由多个部分组成,但我们将重点关注以下四个部分:
参数
资源
输出
映射
这是一个简短的 YAML 示例:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
EC2KeyName:
Type: String
Description: EC2 Key Pair to launch with
Mappings:
RegionMap:
us-east-1:
AMIID: ami-9be6f38c
ap-southeast-2:
AMIID: ami-28cff44b
Resources:
ExampleEC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.nano
UserData:
Fn::Base64:
Fn::Sub': |
#!/bin/bash -ex
/opt/aws/bin/cfn-signal '${ExampleWaitHandle}'
ImageId:
Fn::FindInMap: [ RegionMap, Ref: 'AWS::Region', AMIID ]
KeyName:
Ref: EC2KeyName
ExampleWaitHandle:
Type: AWS::CloudFormation::WaitConditionHandle
Properties:
ExampleWaitCondition:
Type: AWS::CloudFormation::WaitCondition
DependsOn: ExampleEC2Instance
Properties:
Handle:
Ref: ExampleWaitHandle
Timeout: 600
Outputs:
ExampleOutput:
Value:
Fn::GetAtt: ExampleWaitCondition.Data
Description: The data signaled with the WaitCondition
CloudFormation 参数是你在创建或更新堆栈时定义的输入值,类似于你向任何命令行工具提供参数的方式。它们允许你在不修改模板的情况下自定义堆栈。参数可能用于的常见示例如下:
EC2 AMI ID:你可能希望使用安装了最新安全补丁的新 AMI 重新部署堆栈。
子网 ID:你可能有一个自动伸缩组需要在其中部署服务器的子网列表。这些子网 ID 在开发、测试和生产环境中会有所不同。
端点目标和凭证:这些包括 API 主机名、用户名和密码等内容。
你会发现有很多种参数类型。简而言之,它们包括:
字符串
数字
列表
逗号分隔列表
除了这些,AWS 还提供了一些 AWS 特定的参数类型。这些在通过 CloudFormation 网页控制台执行模板时特别有用。例如,AWS::EC2::AvailabilityZone::Name
类型的参数会让网页控制台显示一个有效可选可用区的下拉列表。在ap-southeast-2
区域,列表如下所示:
ap-southeast-2a
ap-southeast-2b
ap-southeast-2c
AWS 特定的参数类型列表正在不断增长,已经大到无法在此列举。尽管如此,我们会在本书中多次使用它们,并且它们可以很容易地在 AWS CloudFormation 文档中找到。
在创建或更新堆栈时,你需要为模板中定义的所有参数提供值。在适当的情况下,你可以为参数定义默认值。例如,你可能有一个名为debug
的参数,用来指示应用程序以调试模式运行。你通常不希望默认启用此模式,因此可以将此参数的默认值设置为false
、disabled
或应用程序理解的其他值。当然,在创建或更新堆栈时,可以覆盖此值。
你可以并且应该为每个参数提供一个简短而有意义的描述。这些描述会在网页控制台的每个参数字段旁边显示。当正确使用时,它们为执行你 CloudFormation 模板的人提供了提示和上下文。
在这一点上,我们需要介绍内置的Ref
函数。当你需要引用一个参数值时,可以使用这个函数:
KeyName:
Ref: EC2KeyName
虽然Ref
并不是你需要了解的唯一内置函数,但它几乎肯定是你将使用最多的一个。我们将在本章后面详细讨论内置函数。
资源是你实际的 AWS 基础设施组件。这些包括 EC2 实例、S3 存储桶、ELB 等。几乎你可以通过 AWS 网页控制台点击和选择创建的任何资源类型,都可以通过 CloudFormation 来创建。
在本章中列出所有 AWS 资源类型并不实际,尽管在你完成本书的食谱时,你会熟悉最常见的资源类型。AWS 在这里保留了一个资源类型的完整列表
docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html
关于 CloudFormation 资源,有一些重要的事项需要记住:
新的或领先的 AWS 资源通常不会立即得到支持。CloudFormation 支持通常滞后于新 AWS 功能发布几周(有时几个月)。对于基础设施自动化至关重要的人员来说,过去这是非常令人沮丧的。快进到今天,通过使用自定义资源,这种情况在一定程度上得到了缓解。本章后面将进一步讨论这些内容。
资源有一个默认的返回值。您可以使用 Ref
获取这些返回值,以在模板的其他位置使用。例如,AWS::EC2::VPC
资源类型有一个默认返回值,即 VPC 的 ID。它们看起来像这样:vpc-11aa111a
。
资源通常包含额外的返回值。使用内置的 Fn::GetAtt
函数来获取这些额外的值。继续上一个示例,AWS::EC2::VPC
资源类型还返回以下内容:
CidrBlock
DefaultNetworkAcl
DefaultSecurityGroup
Ipv6CidrBlocks
就像 AWS 资源一样,CloudFormation 堆栈也可以有返回值,称为 outputs。这些值完全由用户定义。如果您没有指定任何输出,则在堆栈完成时不返回任何内容。
当您使用 CI/CD 工具创建 CloudFormation 堆栈时,输出可以非常有用。例如,您可能希望输出 ELB 的公共主机名,以便您的 CI/CD 工具可以在作业输出中将其转换为可点击的链接。
当您连接层次蛋糕的各个部分时,也会使用它们。您可能希望引用另一个堆栈中创建的 S3 存储桶或安全组。这在新的跨堆栈引用功能中更加容易,我们稍后会在本章讨论。您可以预期在任何 CloudFormation 模板的输出部分经常看到 Ref
和 Fn::GetAtt
函数。
映射部分用于定义一组键/值对。如果您需要任何类型的 AWS 区域可移植性,例如用于灾难恢复或可用性目的,或仅仅为了使您的应用程序更接近最终用户,那么几乎肯定需要在模板中指定一些映射。如果您在模板中引用了任何区域特定的内容,则特别需要这样做。
典型的例子是在模板中指定一组 EC2 AMI ID 的映射。这是因为 AMI 是区域特定的资源,因此在一个区域中对有效 Amazon Machine Image (AMI) ID 的引用在另一个区域中是无效的。
映射看起来像这样:
Mappings:
RegionMap:
us-east-1:
AMIID: ami-9be6f38c
ap-southeast-2:
AMIID: ami-28cff44b
在执行模板时,CloudFormation 将自动确定资源之间的依赖关系,并相应地按顺序创建它们。此外,资源的创建尽可能并行化,以使您的堆栈执行尽快完成。然而,有时会出现问题。
假设应用服务器依赖于数据库服务器。在连接数据库之前,应用服务器需要知道数据库的 IP 地址或主机名。实际上,这种情况需要你先创建数据库服务器,然后使用 Ref
获取其 IP 地址,并将其提供给应用服务器。由于 CloudFormation 并不了解这两个资源之间的耦合关系,因此它会按任意顺序(或者如果可能,则并行)创建这些资源。
为了解决这个问题,我们使用 DependsOn
属性告诉 CloudFormation 应用服务器依赖于数据库服务器。事实上,DependsOn
实际上可以接收一个字符串列表,如果某个资源依赖于多个资源才能创建。例如,如果我们的应用服务器还依赖于一个 Memcached 服务器,那么我们可以使用 DependsOn
来声明这两个依赖关系。
如果需要,你可以进一步扩展这个过程。假设数据库服务器启动后,它将自动启动数据库、设置模式并导入大量数据。我们可能需要等待此过程完成,然后再创建一个应用服务器,该服务器试图连接到一个期望已完成模式和数据集的数据库。在这种情况下,我们希望有一种方法向 CloudFormation 发出信号,表示数据库服务器已完成初始化,以便它可以继续创建依赖于它的资源。这就是 WaitCondition
和 WaitConditionHandle
的作用。
首先,你创建一个 AWS::CloudFormation::WaitConditionHandle
类型,之后你可以通过 Ref
来引用它。
接下来,你创建一个 AWS::CloudFormation::WaitCondition
类型。在我们的例子中,我们希望等待时间从数据库服务器创建开始,因此我们指定该 WaitCondition
资源依赖于我们的数据库服务器(DependsOn
)。
在数据库服务器完成数据导入并准备接受连接后,它会调用由 WaitConditionHandle
资源提供的回调 URL,向 CloudFormation 发出信号,表示它可以停止等待并开始执行其余的 CloudFormation 堆栈。该 URL 通过 UserData
提供给数据库服务器,仍然使用 Ref
。通常,curl
、wget
或类似工具用于调用该 URL。
WaitCondition
资源也可以设置 Timeout
时间。这是一个以秒为单位的值。在我们的示例中,我们可能会设置为 900
,因为我们知道启动数据库并导入数据不应该超过 15 分钟。
下面是一个 DependsOn
、WaitConditionHandle
和 WaitCondition
组合使用的示例:
ExampleWaitHandle:
Type: AWS::CloudFormation::WaitConditionHandle
Properties:
ExampleWaitCondition:
Type: AWS::CloudFormation::WaitCondition
DependsOn: ExampleEC2Instance
Properties:
Handle:
Ref: ExampleWaitHandle
Timeout: 600
CloudFormation 提供了一些内置函数,使得编写模板变得更加简单。我们已经了解了 Ref
和 Fn::GetAtt
。接下来我们看看你可能会遇到的其他一些函数。
使用 Fn::Join
将一组字符串通过指定的分隔符连接起来,例如:
"Fn::Join": [ ".", [ 1, 2, 3, 4 ] ]
这将产生以下值:
"1.2.3.4"
使用 Fn::Sub
执行字符串替换。请考虑以下情况:
DSN: "Fn::Sub"
- mysql://${db_user}:${db_pass}@${db_host}:3306/wordpress
- { db_user: lchan, db_pass: ch33s3, db_host: localhost }
这将产生以下值:
mysql://lchan:ch33s3@localhost:3306/wordpress
当你将这些函数与 Ref
和 Fn::GetAtt
结合使用时,你可以开始做一些非常强大的事情,正如我们将在本书的配方中看到的那样。
其他可用的内置函数包括:
Fn::Base64
Fn::FindInMap
Fn::GetAZs
Fn::ImportValue
Fn::Select
所有这些功能的文档可以在这里找到 docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/intrinsic-function-reference.html
。
根据你的堆栈运行的环境,通常会根据需要配置一个相似但不同的资源集。例如,在开发环境中,你可能不希望创建一整套数据库服务器(HA 主服务器和只读副本),而是选择仅创建一个数据库服务器。你可以通过使用条件语句来实现这一点:
Fn::And
Fn::Equals
Fn::If
Fn::Not
Fn::Or
关于 CloudFormation,有一点很重要:它基本上只是代表你进行 API 调用。这意味着 CloudFormation 将使用你执行模板时所用的相同权限或角色。例如,如果你没有权限在 Route 53 中创建新的托管区域,那么你尝试运行的任何包含新 Route 53 托管区域的模板都将失败。
另一方面,这创造了一个相对棘手的情况,任何开发 CloudFormation 的人通常都具有非常高的权限,并且这些权限在每次执行模板时都会被不必要地授予给 CloudFormation。
如果我的 CloudFormation 模板仅包含一个资源,即一个 Route 53 托管区域,那么让该模板以完全管理员权限执行就没有意义。给 CloudFormation 一个非常有限的权限集来执行模板,更有意义,这样如果执行了一个错误的模板(即错误的复制粘贴操作导致资源被删除),爆炸半径也会受到限制。
幸运的是,最近引入了服务角色,你现在可以定义一个 IAM 角色,并告知 CloudFormation 在执行堆栈时使用该角色,从而为你提供了一个更安全的操作空间。
如本章前面所讨论的那样,在发布新的 AWS 功能和你能够在 CloudFormation 中使用该功能之间,通常会有一个较长的等待期。
在自定义资源出现之前,这将 AWS 开发人员带入了在 CloudFormation 中执行超过 95% 自动化任务的路径,然后再运行一些 CLI 命令来填补空白。通常很难准确地知道哪些资源属于哪个堆栈,并且也很难确定你的堆栈何时完成执行,这成了一个猜谜游戏。
快进到今天,新的趋势是使用自定义资源委托给 AWS Lambda函数。Lambda 可以通过代表你进行 API 调用来填补空白,并且更容易追踪这些资源的来源和完成情况。
如果运气好的话,你暂时不需要使用这个功能。与此同时,AWS 自定义资源的文档非常全面。如果你尝试使用 CloudFormation 创建一个在 AWS 文档中找不到的资源,那么很可能它在 CloudFormation 中还不被支持,这时候使用自定义资源就是解决方案。更多信息请参考docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-custom-resources.html
。
在使用分层结构方法时,常常需要将一个堆栈的输出作为另一个堆栈的输入。例如,你可能在一个堆栈中创建了一个 VPC,并且在创建另一个堆栈中的资源时需要其 VPC ID。
长时间以来,创建堆栈时需要提供一些辅助机制来传递堆栈之间的输出。AWS 最近引入了跨堆栈引用,这提供了一种更原生的方式来实现这一目标。
你现在可以导出一个或多个堆栈的输出。这使得这些输出可以在其他堆栈中使用。请注意,这些值的名称需要是唯一的,因此最好在导出的名称中包括 CloudFormation 堆栈名称,以确保唯一性。
一旦某个值被导出,它就可以通过Fn::ImportValue
函数在另一个堆栈中导入,非常方便!
但是,请确保在导出的值被引用期间,你无法删除或修改它。此外,你也不能删除包含导出值的堆栈。一旦某个东西引用了一个导出的值,它就会一直存在,直到没有堆栈再引用它为止。
基础设施即代码(IaC)的一个原则是,所有的变更都应该以代码的形式进行表示,以便于审查和测试。这一点在使用 CloudFormation 时尤为重要。
在为你创建堆栈后,CloudFormation 服务实际上是“放手”的。如果你对 CloudFormation 创建的任何资源进行更改(无论是在 Web 控制台、命令行,还是通过其他方法),你实际上是在导致配置漂移。CloudFormation 此时已经无法准确了解堆栈中资源的状态。
正确的方法是在 CloudFormation 模板中进行这些更改,并对堆栈执行更新操作。这确保了 CloudFormation 始终知道堆栈的状态,并使你能够保持信心,认为你的基础设施代码是正在运行环境的完整且准确的表示。
在执行堆栈更新时,可能无法清楚地了解将对堆栈进行哪些更改。根据你要更改的资源,你可能会发现它需要被删除并重新创建,以便实现更改。当然,如果相关资源包含你希望保留的数据,这种行为是完全不希望发生的。请记住,RDS 数据库可能是一个特别的痛点。
为了缓解这种情况,CloudFormation 允许你在执行更新之前创建并查看变更集。变更集显示了 CloudFormation 打算在你的资源上执行哪些操作。如果变更集看起来没问题,你可以选择继续。如果你不满意看到的内容,可以删除变更集并选择另一个行动方案——也许选择创建并切换到一个全新的堆栈以避免服务中断。
在你开始构建自己的 CloudFormation 堆栈时,还有一些其他事项需要放在心上。我们来看看。
通常,如果你省略了资源的名称属性,CloudFormation 会为你生成一个名称。这可能导致奇怪的资源名称,但它会增加模板的可重放性。以 AWS::S3::Bucket
为例,如果你指定了 BucketName
参数但没有确保其唯一性,CloudFormation 在第二次执行模板时会失败,因为该桶已存在。省略 BucketName
可以解决此问题。或者,你可以选择每次运行模板时生成一个独特的名称。这里可能没有对错之分,所以做最适合你的方式就好。
在创建 CloudFormation 堆栈时,你可以选择禁用回滚。在你决定将其设置为 true
之前,请记住,这个设置会在堆栈创建后持续存在。我们曾经遇到过在更新现有堆栈失败(由于某种原因)但回滚已被禁用的危险情况。这对任何人来说都不是一种愉快的处境。
最有可能让你担心的限制如下:
CloudFormation 模板的最大大小为 50 KB。这个限制相当宽松,如果你达到了这个限制,那么几乎可以肯定需要考虑将模板拆分成多个较小的模板。如果你确实需要超过 50 KB 的限制,最常见的方法是先将模板上传到 S3,然后提供 S3 URL 给 CloudFormation 执行。
你可以指定的最大参数数量为60。如果你需要更多,那么再次考虑是否需要为你的“蛋糕”添加更多的层次。否则,使用列表或映射可能会帮你脱困。
输出数量也限制为60。如果你达到了这个限制,可能是时候考虑使用多个较小的模板了。
资源数量限制为200。这里的规则与之前相同。
默认情况下,你的 CloudFormation 堆栈数量被限制为200个。你只需联系 AWS 即可增加这个限制。
需要牢记的一点是,你可能会遇到循环依赖的情况,即多个资源在创建时相互依赖。一个常见的例子是两个安全组互相引用,以便允许彼此之间的访问。
针对这种特定场景的解决方法是使用 AWS::EC2::SecurityGroupEgress
和 AWS::EC2::SecurityGroupIngress
类型,而不是 AWS::EC2::SecurityGroup
的入口和出口规则类型。
DSL 和生成器是基础设施编码人员之间热烈辩论的焦点。一些人喜欢它们,另一些人则讨厌它们。人们喜欢它们的原因包括以下几点:
它们允许用更本地化的语言或团队语言编写 CloudFormation。
它们允许使用一些高级编程构造。迭代就是一个被广泛引用的例子。
在 CloudFormation 支持 YAML 之前,使用 DSL 通常能使代码更易读,且冗长度大大降低。
人们不喜欢它们的原因包括以下几点:
DSL 在历史上曾经成为废弃软件,或与 CloudFormation 版本差距较大,尽管现在有一些得到良好支持的 DSL。
开发人员可能需要学习一门新语言,并且还要应对另一个新的文档体系,除了要学习 CloudFormation 和浏览 AWS 文档。
Google 和 Stack Overflow 的作用会略显不足,因为需要翻译问题和答案。
除了这里写的内容外,本书中不会再涉及这个话题。我们不能给出具体的建议,让你选择哪条路,因为这几乎总是一个高度个人化和情境化的选择。不过,特别是在熟悉 AWS 和 CloudFormation 的过程中,一个明智的做法是坚持使用 YAML(或 JSON),直到你认为 DSL 或生成器可能有用为止。
无论如何,你都不希望在模板中硬编码凭证或将其提交到源码仓库中。这样做不仅增加了凭证被盗用的风险,还降低了模板的可移植性。如果凭证被硬编码且需要更改,这显然需要你编辑 CloudFormation 模板。
相反,你应该将凭证作为参数添加到模板中。确保在这样做时使用 NoEcho
参数,以便 CloudFormation 在显示参数时屏蔽其值。
如果您的堆栈中有资源希望保护免受意外删除或修改,可以应用堆栈策略来实现这一点。默认情况下,所有资源都可以被删除或修改。当您应用堆栈策略时,所有资源将被保护,除非您在策略中明确允许它们被删除或修改。请注意,堆栈策略在堆栈创建期间不生效——它们仅在您尝试更新堆栈时生效。
AWS 命令行界面 (CLI) 工具是 AWS 管理员工具包中的一个重要组成部分。
CLI 工具通常是与 API 交互的最快和最简单的方法之一。作为一种基于文本的工具,它比使用网页控制台更容易扩展。与控制台不同,它可以通过脚本等方式进行自动化。AWS 应用程序编程接口 (API) 表示作为 AWS 管理员可用的所有功能。它也更容易通过命令行历史记录进行跟踪。像所有优秀的 CLI 工具一样,简单的单个命令可以串联(或管道)在一起,执行复杂的任务。
CLI 工具是开源软件,维护在 GitHub 上 github.com/aws/aws-cli
。更多详细文档,请参考 AWS CLI 主页 aws.amazon.com/cli
。
CLI 工具需要 Python 2.6.5 或更高版本。
安装它的最简单方法是使用 Python 包管理器pip
:
pip install awscli
这将使得aws
命令在您的系统上可用。
AWS 经常发布新服务和新功能。为了使用这些新功能,您需要升级 CLI 工具。
要升级,请定期运行以下pip
命令:
pip install --upgrade awscli
CLI 工具与 AWS API 之间的认证是通过两项信息完成的:
访问密钥 ID
秘密访问密钥
顾名思义,您应该保密您的秘密访问密钥!小心存储或发送它的地方。
创建用户后,您可以配置工具以用于认证目的。
虽然您可以直接用访问密钥配置 CLI 工具,但不推荐这样做。相反,您应该使用配置文件来存储凭证。使用配置文件可以让您在一个一致的、易于管理的集中位置来保护您的秘密密钥。
在没有任何额外配置或选项的情况下,您的 CLI 工具命令将使用默认配置文件。
要设置默认配置文件,您可以使用以下命令:
aws configure
这将提示您输入访问密钥 ID、秘密访问密钥、区域和输出格式。
除了默认配置文件外,您还可以配置其他命名的配置文件。这对于在具有不同访问权限级别的用户之间切换(例如,只读用户和管理员)或甚至在不同帐户的用户之间切换非常有用。
aws configure --profile
在响应提示后,你可以通过在命令中传递 --profile
选项来引用命名的配置文件。
你还可以通过使用环境变量来配置 CLI:
export AWS_PROFILE=
虽然你应该优先使用配置文件,而不是直接设置访问 ID 和密钥,但有时你可能不得不这么做。如果你必须直接设置密钥,请通过环境变量来设置,这样你就不需要传递密钥或将其硬编码:
export AWS_ACCESS_KEY_ID=
export AWS_SECRET_ACCESS_KEY=
在 EC2 实例上运行 CLI 工具时,你可以利用实例的 IAM 角色进行调用。这意味着你不需要手动配置凭证或设置环境变量。
在幕后,实例将检索并设置它自己的 AWS 环境变量,以允许 API 调用。你需要确保该实例具有适当的权限。
AWS CLI 工具在 AWS 基于 Linux 的实例上预装。
所有 CLI 工具命令都是基于服务的。通过使用服务命令和子命令,你可以直接向 AWS API 发出调用。
每个命令代表一个 AWS 服务。虽然大多数服务只有一个命令与之关联,但有些服务有多个命令(例如,S3 有 s3
和 s3api
)。
运行 aws help
查看所有可用的命令/服务—它们可能会在本书打印时有所变化!
每个命令都有一组子命令,用于执行特定服务的操作。
运行 aws
查看所有子命令。
子命令接受以 --
开头的选项。
使用 aws
查看所有选项及其用途。
虽然大多数是可选的(因此得名),但那些没有被方括号([]
)括起来的选项是必需的。如果你没有包含它们,将会收到错误信息(并附有相关细节)。
内置文档是开始寻找答案的最佳地方。通常在所有选项描述之后会有示例。否则,网上有很多可用的示例。
有些选项适用于所有或大多数命令,因此它们特别有用,值得了解。
CLI 工具可以配置为以 JSON、表格或文本格式输出。要控制输出类型,请使用 --output
选项。
要为所有命令设置默认的输出类型,可以为你的配置文件设置 output
参数。
JavaScript 对象表示法 (JSON) (json.org/
),一种标准的、机器和人类可读的信息交换格式。以下是 us-east-1
(北弗吉尼亚)区域的可用可用区(AZ)在 JSON 格式中的表示:
aws ec2 describe-availability-zones --output json
{
"AvailabilityZones": [
{
"State": "available",
"RegionName": "us-east-1",
"Messages": [],
"ZoneName": "us-east-1a"
},
{
"State": "available",
"RegionName": "us-east-1",
"Messages": [],
"ZoneName": "us-east-1c"
},
{
"State": "available",
"RegionName": "us-east-1",
"Messages": [],
"ZoneName": "us-east-1d"
},
{
"State": "available",
"RegionName": "us-east-1",
"Messages": [],
"ZoneName": "us-east-1e"
}
]
}
表格格式会显示一个文本/ASCII 表格的结果。这对于生成可打印报告非常有用:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06326_01_03.png
文本输出格式仅显示结果的键/值响应。没有添加任何额外的格式或显示字符。
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06326_01_04.png
CLI 工具支持使用 --query
选项转换 API 的响应。此选项将 JMESPath 查询作为参数,并返回查询结果。
JMESPath 是一种用于查询 JSON 的语言。有关更多信息,请访问 jmespath.org/
。
由于查询作为命令的一部分在服务器上处理,而不是在客户端处理,因此可以通过将工作卸载到服务器,减少生成的有效负载的大小并提高响应时间。
JMESPath 可用于转换你收到的响应:
$ aws ec2 describe-availability-zones \
--output json \
--query 'AvailabilityZones[].ZoneName'
[
"us-east-1a",
"us-east-1c",
"us-east-1d",
"us-east-1e"
]
它也可以用来过滤接收到的数据:
$ aws ec2 describe-availability-zones
--output json
--query "AvailabilityZones[?ZoneName == 'us-east-1a'].State"
[
"available"
]
在使用 CLI 工具执行复杂任务时,传递一个包含选项的 JSON 对象可能会更简单。这种交互方式可能意味着你应该使用某个 AWS 软件开发工具包(SDK)。
要生成一个示例 JSON 对象(它将被接受),可以使用 --generate-cli-skeleton
选项运行命令:
$ aws ec2 describe-availability-zones --generate-cli-skeleton
{
"DryRun": true,
"ZoneNames": [
""
],
"Filters": [
{
"Name": "",
"Values": [
""
]
}
]
}
你可以复制、编辑并使用此对象来定义你的命令选项,而无需传递多个单独的选项。这对于包含选项数组或选项数量可变的命令效果最佳。
你还可以通过调用带有 --generate-cli-skeleton output
选项的命令,预览命令的输出。这可以加速合并 CLI 命令的过程,因为你可以在不实际调用 API 的情况下查看响应:
$ aws ec2 describe-availability-zones --generate-cli-skeleton output
{
"AvailabilityZones": [
{
"ZoneName": "ZoneName",
"State": "State",
"RegionName": "RegionName",
"Messages": [
{
"Message": "Message"
}
]
}
]
}
CLI 工具返回的结果默认限制为 1,000 个资源。
通常这不是问题,但在某些规模下,你可能会遇到分页问题。一个常见的例子是 S3 桶中的文件。
如果你完全确定应该在响应中看到某个特定资源但没有看到,请检查你的分页设置。该资源可能已经包含在匹配的资源中,只是没有出现在返回的响应部分。
以下选项允许你控制从 API 返回的结果的数量和起始位置:
--page-size
:此选项限制显示给你的资源数量,但不会实际限制返回的资源数量。默认的项目数(即 1,000 个)仍将被处理并返回给你。
--max-items
:此选项设置响应中实际返回的项目数量的上限。你可能会收到更少的项目,但不会收到超过此数量的项目。
--starting-token
:此选项更改响应的起始位置。使用此选项可以显示后续的结果,超出第一页的内容。
aws s3 ls --bucket bucket-name --max-items 100 --starting-token None___100
你可以通过配置 CLI 工具中包含的自动完成器来启用命令、子命令和选项的制表符自动完成。
在 OS X、Linux 和 Windows 系统中使用 bash shell,你可以使用以下命令加载自动完成器:
complete -C 'which aws_completer'aws
默认情况下,aws_completer
程序安装在 /usr/local/bin
。如果你的工具安装在非标准位置,你需要找到它并将 which aws_completer
命令更改为相关路径。
以下程序与 AWS CLI 工具配合良好,可能会派上用场。
jq 是一个轻量级的工具,用于处理和转换 JSON。它遵循 Unix 哲学:做一件事,并做到最好。可以在 stedolan.github.io/jq/
找到它。
虽然 jq 和 JMESPath 很相似,但 jq 更容易上手。它还支持将 JSON 转换为纯文本;而 JMESPath 查询总是返回更多的 JSON 数据。
你可以将来自 CLI 工具的 JSON 结果传递给它,并轻松转换结果以供其他地方使用。这个示例使用 jq 的属性名称选择器将 JSON 输出转换为文本:
$ aws ec2 describe-availability-zones --output json | jq '.AvailabilityZones[].ZoneName'
"us-east-1a"
"us-east-1c"
"us-east-1d"
"us-east-1e"
在本章中,我们将介绍以下主题:
设置主账户
创建会员账户
邀请账户
管理你的账户
添加服务控制策略
我们与许多公司合作,这些公司管理着大量不断增长的 AWS 账户。保持对所有这些账户的控制通常是非常困难的——即使对于经验丰富的 AWS 用户来说也是如此。
随着 AWS Organizations 的发布,你现在可以集中管理 AWS 账户,将它们安排成逻辑分组和层级结构,并对它们进行以前在 AWS 平台上无法实现的控制。
所有使用 AWS Organizations 进行计费和控制的账户都必须拥有一个主账户。该账户控制组织的成员资格,并支付所有成员的账单(总得有人做这个事情)。
要设置主账户,请执行以下步骤:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_001.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_002.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_003.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_004.png
虽然这是一个非常简单的流程,但它是你在使用 AWS Organizations 的任何有用功能之前必须做的第一件事。
在这里你可以看到主账户、成员和组织单位(OUs)之间关系的高层次图示:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06236_02_05.png
我们故意启用所有组织功能。合并计费选项用于向后兼容——在组织功能之前,合并计费是唯一可以链接账户的选项。
不要将主账户用于日常任务。由于主账户非常重要,因此不建议冒险使用它或为其设置访问密钥。如果主账户被不正当地访问,将会影响所有成员账户。最好避免这样做。
主账户的名称旁边将始终有一个星标。
所有组织功能都通过 API 提供。这意味着你可以使用 AWS SDK 或 CLI 工具执行你在 Web 控制台中执行的相同操作。
如在合并账单确认邮件中所提到,建议在控制台上配置多因素认证(MFA)。为此,请以根用户身份登录(即你首次创建账户时使用的凭证),进入身份与访问管理(IAM)控制台,并按照激活根账户 MFA 的提示操作。
你可以轻松使用 CLI 工具创建你的主账户。以下命令将使你的账户成为主账户,并启用所有组织功能:
aws organizations create-organization
邀请账户的操作步骤
创建成员账户的操作步骤
一旦你的组织启动并运行,最常见的用途就是自动化账户创建过程。组织内创建的账户被称为成员账户。
所有由成员账户产生的费用将由主账户进行计费。
显然,你需要一个组织来执行这个操作步骤。请参阅本章中的其他操作步骤来开始使用。
aws organizations create-account \
--email \
--account-name \
--query 'CreateAccountStatus.Id'
create account status
请求 ID,你可以用它来检查状态: aws organizations describe-create-account-status \
--create-account-request-id
在你的组织中创建成员账户的命令非常简单。
使用的电子邮件地址不能与其他 AWS 账户关联。
账户创建过程需要一些时间,因此是异步进行的。这意味着你不会立即收到create-account
命令的状态。相反,本操作步骤中的命令将返回一个请求 ID。
该 ID 会被传递到另一个账户中,用于检查创建的状态。当状态为CREATED
时,你就可以开始使用新账户了。
虽然这个功能确实很有用,但 AWS 组织服务相对较新。这意味着你需要了解一些功能。
一旦你创建了成员账户,就可以开始使用它了!
新账户中将存在一个 IAM 角色,默认名称为OrganizationAccountAccessRole
。这是为了让你能够(从主账户)承担该角色并管理成员账户。虽然这个名称已经足够好,但你也可以在创建账户时传递--role-name
参数来配置该名称。
为了承担该角色,你需要知道它的Amazon 资源名称(ARN)。计算 ARN 是一个多步骤过程:
aws organizations list-accounts
arn:aws:iam:::role/OrganizationAccountAccessRole
请参见第八章中的配方,安全性与身份,了解如何最佳地管理多个账户。
服务控制策略(SCPs)是 AWS Organizations 的另一个主要功能。你可以在多个级别/资源上应用它们,包括账户(成员账户和被邀请账户)。查看本章中的其他配方,获取更多细节。
一些活动仍然需要账户的根凭证。一个示例活动是关闭(或删除)账户(更多细节请参见下一节)。
为了做到这一点,你需要进行与账户关联的电子邮件的密码恢复过程,尤其是在发送 create-account
请求时。
在撰写本文时,无法通过 API 删除在你的组织中创建的账户。我们只能推测,能够通过编程删除组织中创建的成员账户将是一个高度需求的功能,并将在不久的将来得到解决。你仍然可以进入成员账户并使用根凭证关闭它,但这些凭证默认并不存在。
虽然你可以通过 API 删除你的组织,但如果你在组织中创建了任何成员账户,就无法进行删除(因为你不能删除它们,所以你的组织永远不会为空)。这一点在不久的将来会有所改进,但现在仍然值得注意。
设置主账户 配方
添加服务控制策略 配方
第八章中的跨账户用户角色 配方,安全性与身份
虽然创建新账户进入你的组织是有意义的,但你现在该如何处理所有其他账户呢?
你可以邀请现有账户加入你的组织,这意味着你可以从管理角度将它们视为成员账户。这极大简化了账户的管理工作量,因为旧账户和新账户没有单独的处理流程。
由于这通常仅针对每个现有账户执行一次,我们将使用控制台。
所有 AWS 组织功能都可以通过 SDK 和 AWS CLI 工具访问。如果你需要自动化此过程,完全可以实现。
你必须为其中一个账户(主账户)启用了 AWS Organizations,并且有另一个尚未成为组织一部分的账户(你将邀请它)。
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_006.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_007.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_008.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_009.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_010.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_011.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_012.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_013.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_014.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_015.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_016.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_017.png
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_018.png
虽然有许多步骤,但邀请现有账户的过程是一个相对简单的握手过程。这意味着双方必须主动发起/接受邀请,才能成功——邀请无法被强制进行。
在指定目标账户的账户 ID(或电子邮件地址)后,关联的电子邮件地址将收到通知。
作为握手过程的一部分,受邀账户必须明确接受邀请。
需要注意的是,默认的邀请类型(以及我们在此过程中使用的)是使用 AWS Organizations 的完整功能集。如控制台中所述,这意味着如果相关策略已配置,受邀账户可能会被阻止离开组织。
确认后,双方将收到一封详细说明会员资格的电子邮件。从此时起,受邀账户的账单将由主账户支付。
受邀账户与通过组织功能创建的账户有所不同。
与成员账户(通过 AWS Organizations API 创建的账户)不同,受邀账户可以从组织中移除。
作为全功能邀请的替代方案,可以仅为组织指定合并账单模式。在这种模式下,不会有 OU 或策略,仅会在账户之间共享账单关系(即主账户将支付成员账户的账单)。
任何预先配置为使用合并账单的账户将自动迁移到 AWS Organizations 合并账单模式中。
有多种方法可以对 AWS 帐户进行分组和排列。如何做完全取决于您,但以下是一些考虑的示例:
业务单元(BU)或位置:您可能希望允许每个 BU 在其自己的产品或服务上独立工作,按照自己的时间表进行工作,而不会影响业务的其他部分。
成本中心:根据成本分组可能有助于您跟踪支出与分配预算的情况。
环境类型:将开发、测试和生产环境合理地分组,有助于您跨每个环境管理控制。
工作负载类型或数据分类:您的公司可能希望将工作负载类型相互隔离,或者确保所有包含特定数据类型的帐户应用特定的控制。
在下面的虚构示例中,我们通过将其放入名为突然谷的 OU 中,将Sitwell Enterprises 帐户与组织的其他部分隔离开来。也许他们在不同的地理位置运营,并且对控制和访问有不同的法规要求。
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_019.png
组织层次结构
请注意,虽然我们也可以将主帐户放入 OU 中,但我们避免这样做是为了明确以下事实:
它是主帐户,并且对整个组织拥有控制权。
我们设置的规则,使用 SCP 来控制组织中的成员帐户,不适用于主帐户(因为它们不能)。
在本章节的添加服务控制策略食谱中了解更多关于 SCP 的信息。
在继续之前,您应该已经完成了以下工作:
设置主 AWS 帐户
创建了一个组织
在您的组织中创建成员帐户,或者通过邀请手动添加成员帐户
现在我们将介绍执行管理 OU 所需的常见任务的单行命令。这些命令只能在您的主帐户中执行。
您可以运行此命令来获取组织的根 ID。当您在主帐户中创建组织时,根会自动为您创建。返回给您的 ID 看起来会像这样:r-bmdw
。
aws organizations list-roots
要创建 OU,请执行以下步骤:
确定您希望此 OU 存在的位置。如果它直接位于根目录下,那么根 ID 将作为父级。或者,如果此 OU 将作为另一个 OU 的子级,使用该 OU 的 ID。显然,如果这是您创建的第一个 OU,则根将作为父级。
使用 CLI 像这样创建您的 OU:
aws organizations create-organizational-unit \
--parent-id \ --name
如果您需要获取 OU 的 ID,可以使用 CLI 进行操作;请注意,您需要知道 OU 的父级。以下是如何在根或 OU 中获取所有 OU 及其 ID 列表的方法:
aws organizations list-organizational-units-for-parent \
--parent-id
要将账户添加到 OU,执行以下步骤:
aws organizations move-account \
--account-id \
--source-parent-id \
--destination-parent-id
要从 OU 中移除账户,执行以下步骤:
如果你希望将一个账户从 OU 中移除,你有两个选择。你可以将它移动到另一个 OU,或者将它移回根目录。如果你决定删除一个 OU,你需要首先确保它里面没有账户(我们接下来会展示如何操作)。
运行以下命令将账户移回根目录:
aws organizations move-account \
--account-id \
--source-parent-id \
--destination-parent-id
要删除一个 OU,你首先需要确保它是空的,通过移除它的子账户(如前所述)。然后你可以像下面这样删除 OU:
aws organizations delete-organizational-unit \
--organizational-unit-id
如果操作得当,使用 OU 将你的账户分组在一起,将帮助你简化管理和操作它们的方式。尽量只使用刚好够用的 OU 来完成任务。我们的目标是使用 OU 让你的工作更轻松,而不是更困难。
组织控制策略(OCPs)可以附加到你的根目录、OU 或 AWS 账户上。目前,只支持一种 OCP 类型:SCP。
账户只能属于一个组织单位(OU)或根目录。
同样地,OU 只能属于一个 OU 或根目录。
最好避免在主账户中部署资源,因为该账户无法通过 SCP 进行控制。主账户应仅作为审计、控制和计费的管理账户使用。
在开始之前,我们应该先讲一下 SCP 是什么,它是如何应用到你的组织中的。
SCP 由一个策略文档组成,通过过滤定义了哪些服务和操作可以在 OU 或 AWS 账户内使用和执行。如果你之前配置过 IAM 策略,那么你已经有了足够的背景知识来开始使用 SCP。除了少数几个小例外,它们看起来完全一样。
SCP 可以在组织的不同级别应用。以下是这些级别,从下到上:
AWS 账户级别:应用于 AWS 账户的 SCP 只会对该账户生效。需要注意的是,SCP 与账户内的 IAM 策略是完全独立的。例如,SCP 可能允许 AWS 账户完全访问 S3,但账户内的 IAM 策略可能会拒绝访问(针对某些角色和/或用户)。
OU 级别:在 OU 级别应用的 SCP 将适用于该 OU 中的所有 AWS 账户以及任何子 OU(记住,OU 可以是另一个 OU 的成员)。
根级别:如果在此级别应用 SCP,它将应用于组织内所有 AWS 账户。
当你在多个层次上应用 SCP 时,事情可能会变得非常有趣。在根、OU、账户和 IAM 层次上的策略交集将被评估,并决定是否允许 API 调用。例如,即使某人属于具有账户完全管理员访问权限的 IAM 角色,如果任何上层 SCP(账户、OU、根)拒绝 EC2 访问,他们仍然无法调用任何 EC2 API。
在下面的示例中,我们有一个顶级组织单元(OU),Austero Bluth,附加了一个 SCP,该 SCP 允许对其下所有 OU 和账户的所有 AWS 资源访问:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_020.png
组织层级和策略
Austero Bluth 有两个子 OU;让我们专注于 Sudden Valley。它有一个 SCP,只允许 EC2 和 S3。通过使用白名单方法,除了这两个服务,其他任何服务都会被拒绝访问。记住,SCP 像一个过滤器,任何位于 Sudden Valley OU 下的 OU 或 AWS 账户,最多只能访问 EC2 和 S3。
Sitwell Enterprises 账户也附加了一个 SCP。这个特定的 SCP 允许 S3 和 SQS。请注意,由于 Sitwell 账户位于一个不允许 SQS 的 OU 中,SQS 声明在这里不会生效。还要注意,尽管Sudden Valley OU允许 EC2,但该账户无法访问 EC2,这是因为附加在账户上的 SCP 中没有明确允许 EC2。
在 IAM 级别,我们在 Sitwell AWS 账户中有一个角色,允许完全的管理员权限。但由于管理此账户的 SCP 交集只允许 S3,因此任何使用该角色的人,如果尝试使用 EC2 或 SQS 等服务,将被拒绝访问。
让我们再看一下Bluth Company 账户。附加在该账户上的 SCP 允许完全的 AWS 访问;然而,它位于一个仅允许 EC2、RDS 和 S3 的 OU(Balboa Bay)中。该账户内有一个 IAM 角色,也允许完全的管理员访问,但同样,该账户中的管理员将被限制在 EC2、RDS 和 S3 之内。
我们将一步步创建一个 SCP 并将其添加到 OU 中。
你需要该 OU 的 ID;你可以从组织的网页控制台获取,或者使用 CLI。它看起来像这样:ou-bmdw-omzypry7
。
我们还将准备一个策略文档。在这个例子中,我们将向 Sudden Valley OU 添加一个 SCP,允许访问 EC2 和 S3。以下是我们的 SCP 的样子:
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":["EC2:*","S3:*"],
"Resource":"*"
}
]
}
在文本编辑器中打开一个新文件,添加你的 JSON 策略文档,并保存。
像这样运行create-policy
CLI 命令。我们在这里使用tr
命令稍微有些技巧:我们用它来移除策略文档中的回车符,因此请特别注意示例中的语法。不幸的是,组织 CLI 不允许我们直接提供策略文档的路径:
aws organizations create-policy \
--content "$(tr -d '\n' < my-policy-file.json)" \
--description "A policy description goes here" \
--name "My policy" \
--type SERVICE_CONTROL_POLICY
如果前面的 CLI 命令成功执行,将返回一些 JSON,包含我们刚刚添加的策略 ID。它看起来像这样:p-o9to04s7
。
现在你可以继续将此策略附加到 OU。使用以下 CLI 命令来执行此操作:
aws organizations attach-policy \
--target-id \
--policy-id
aws organizations list-targets-for-policy \
--policy-id
再次强调,你添加的策略将在组织结构的每一层充当过滤器。考虑到这一点,可能是时候指出,在将策略应用于整个组织之前,先在单一账户上测试策略将为你节省许多麻烦。对组织顶层的 SCP 进行大范围更改可能会在链条底部的 AWS 账户层面产生意想不到的情况。AWS 账户中的本地管理员无法覆盖 SCP。
在发布时,你只能在一个组织中拥有一个根(当你创建组织时,它会自动为你创建)。
出于显而易见的原因,主账户不会受到附加到它的任何 SCP 的影响。你还可能注意到,技术上是可以将主账户放置到 OU 中的;同样,它也不会受到附加到该 OU 的任何 SCP 的影响。
由于主账户不受 SCP 的影响,最好尽可能保持它为空,并且不要在其中创建任何资源。使用子 AWS 账户,这样你可以对其应用细粒度控制。
每个组织单元(OU)和账户都需要使用 SCP,但不应将其视为 AWS 账户的唯一访问控制方式。根据需要应用 IAM。
创建策略时,我们必须指定--type
参数。在发布时,AWS 仅支持一种 OCP 变体:SERVICE_CONTROL_POLICY
。
尽可能遵循最小权限原则。你应该只给予 AWS 账户访问它们所需的服务。这有助于减少误操作、编程错误或账户被攻破所带来的损害。
从长远来看,你可能会发现不在根级别分配控制更有利。相反,可能更好将所有账户添加到一个 OU,并将控制应用于该 OU。
你的策略可以采用白名单或黑名单方法。在这个示例中,我们使用了白名单方法,但你也可以选择允许你的组织单元(OU)和账户使用所有服务,除了那些你明确禁止的服务。你应该选择其中一种方法并坚持使用,因为混合这两种方法会在未来造成很多困惑。
与 IAM 策略不同,你不能在 SCP 文档中指定条件,并且Resource
必须是*
。
在本章中,我们将涵盖以下方案:
托管静态网站
缓存网站
使用网络存储
用于合规的备份数据
每个这些方案都由 CloudFormation 模板支持,使其可以快速、轻松地复现和修改。
存储是任何组织云计算使用的关键部分。正确使用时,服务器是短生命周期且可替换的。这意味着拥有一个耐用、可用的存储服务对于持久化和共享状态至关重要。
下面是 AWS 提供的存储服务的高级概述:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06236_03_01.png
AWS 的存储服务
弹性块存储(EBS)为 EC2 实例提供块设备存储。它的行为类似于存储区域网络(SAN),并且提供了各种存储服务中最低延迟的访问。EBS 卷一次只能被一个实例访问。卷的大小必须在创建时指定,并且之后不能更改。
卷托管在特定可用区的冗余硬件上,但它们不提供跨可用区的冗余。
EBS 的一些推荐使用场景:
实例启动卷
强大的数据处理
事务性写入
我们将在第四章中更详细地讨论 EBS,使用 AWS 计算,因为它的主要用途是作为 EC2 实例的底层存储。
弹性文件系统(EFS)提供一种文件存储服务,多个实例可以同时访问,类似于网络附加存储(NAS)。虽然它的速度不如 EBS 快,但仍提供低延迟访问。由于可以被多个客户端同时访问,因此它的吞吐量可以远高于 EBS。EFS 文件系统的大小会动态扩展,因此不需要预分配或在使用过程中进行修改。文件系统会在可用区(AZ)之间冗余存储。
EFS 的一些推荐使用场景:
主页目录
提供共享网站内容
内容管理
EFS 的性能会根据文件系统的大小进行扩展。由于文件系统的大小不是预分配的,唯一增加性能的方法是向其中添加更多数据。
简单存储服务(S3)提供一个基于 Web 的文件托管服务。文件被称为对象,并分组在存储桶中。对象实际上是一个键值对,类似于文档数据库。键像文件路径一样使用,/
用作分隔符和分组字符。存储桶可以像网站一样通过自动生成的域名轻松访问。
由于与域名相关联,存储桶名称必须是全局唯一的。
S3 的一些推荐使用场景:
静态网站资产
共享大文件
短期(也称为温暖)备份
Glacier 是 S3 的配套服务,但它是 冷 存储选项。冷存储是一种你无法直接访问数据的服务;你必须提出数据恢复请求(恢复到 S3),并在数据准备好时收到通知。冷存储的物理例子可能是存放在安全位置的备份磁带。与 S3 类似,文件被称为 对象。文件被分组存储在 归档 中。归档可以创建和删除,但不能修改。归档被分组存储到 金库 中,金库让你能够控制访问。
最短的恢复时间是 1-5 分钟(有一些限制)。标准恢复时间需要 3-5 小时,还有其他选项可用。
Glacier 的一些推荐用例包括:
长期(即 冷)备份
合规性备份
内容交付的目标是快速、高效地将内容分发给用户。最佳实践是利用 内容分发网络(CDN)。亚马逊的 CDN 服务是 Amazon CloudFront。
虽然 AWS 目前有 14 个区域,但它还有 68 个额外的边缘位置,可以作为 CloudFront 的一部分使用。这为你提供了一个庞大的全球网络资源,你可以利用这些资源提升用户对你应用的体验。
CloudFront 与 S3 紧密合作,提供静态资源。除此之外,它还可以配置缓存动态内容。这为你提供了一种简单的方式来提升不直接与 CloudFront 配合使用的应用的性能。
CloudFront 网站被称为 分发,这突出了它们作为 CDN 的角色。
分发也可以用于为多个不同的内容来源提供共同的前端。
在 AWS 上托管静态网站非常简单。事实证明,它不仅成本低廉、快速、可靠,而且具备大规模扩展能力。
你可以通过将内容存储在 S3 桶中,并配置该桶使其像网站一样运行来实现这一点。
需要注意的是,我们这里只讨论静态内容。此方法不适用于需要服务器端处理或其他后端功能的网站。例如,WordPress 需要 PHP,这意味着你需要一个完全功能的 web 服务器来运行它。S3 无法为你解析 PHP 页面,它只会直接将文件提供给浏览器。
那么,为什么你会想要在 S3 中托管静态网站呢?我们常见的场景有:
简单来说,你的网站完全是静态的,而且你不经常更改它。
你的公司正在推出一款新产品或服务。你预计在短时间内会有大量客户访问一个迷你网站;流量可能远超你现有的 web 托管环境所能承受的。
你需要为故障转移或 维护中 页面提供一个托管位置,这个页面应该与现有的 web 托管环境分开。
当 S3 用于提供静态内容时,不支持 HTTPS。
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06236_03_02-1.png
这个配方为你提供了创建所需 CloudFormation 配置:
一个用于托管内容的 S3 存储桶
一个 Route 53 托管区和必要的 DNS 记录
从www
到root/apex
的重定向,适用于你的域名
在运行完 CloudFormation 后,你当然需要将内容上传到 CloudFormation 为你创建的存储桶中。
在这个例子中,我们将为我们的网站www.example.org/
创建两个 S3 存储桶。它们分别对应以下主机名:
www.example.org
example.org
也许现在是时候提醒你,S3 存储桶名称是全局唯一的。你还需要用你拥有的域名替换example.org
。
example.org
存储桶中,并告诉 S3 请求www.example.org
时应重定向到另一个存储桶。以下是 CloudFormation 的相关部分,展示如何创建这些存储桶(请注意,随着我们继续本配方,我们将扩展这个例子): Resources:
ApexBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref DomainName
WWWBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub
- www.${Domain}
- Domain: !Ref DomainName
我们不会将域名硬编码到存储桶名称中。相反,我们将作为参数将域名传递给 CloudFormation 模板,以最大化其可重用性,然后通过!Ref DomainName
引用它。为了简化这个配方,我们将设置一个单页网站。在现实中,你的网站当然会由多个文件组成,但你需要遵循的过程完全相同。
配置索引文档:
索引文档是 S3 在用户在浏览器的地址栏中输入域名时默认提供的文件。这避免了用户需要输入文件的完整路径,即example.org/index.html
。
通常,你的索引文档会被命名为index.html
。我们将在本章最后提供该文件的代码片段。
配置错误文档:
error.html
。同样,我们将在本章稍后提供该文件的代码片段。在存储桶上启用网站托管:
example.org
存储桶提供静态网站内容。通常用户会通过 S3 Web 控制台进行此配置,但我们将使用 CloudFormation 来完成此操作。CLI 也提供了一个简便的命令行来完成这个操作。你无需运行这个命令,我们在这里仅作为参考添加它: aws s3 website s3://example.org/
--index-document index.html --error-document error.html
设置从www
主机名的重定向:
www.example.org
存储桶配置为重定向到 example.org
存储桶。没有简便的一行 CLI 命令可以做到这一点。幸运的是,在 CloudFormation 中,这很容易,正如你将在接下来的 CloudFormation 代码片段中看到的那样。配置权限:
如果我们手动配置存储桶,我们会应用类似下面这样的存储桶策略:
{
"Version":"2012-10-17",
"Statement": [{
"Sid": "Allow Public Access to everything in our bucket",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example.org/*"
}
]
}
Resources
部分现在看起来是这样的: ApexBucket:
Type: AWS::S3::Bucket
Properties:
BucketName:
Ref: DomainName
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
WWWBucket:
Type: AWS::S3::Bucket
Properties:
BucketName:
Fn::Join: [ ., [ www, Ref: DomainName ] ]
AccessControl: BucketOwnerFullControl
WebsiteConfiguration:
RedirectAllRequestsTo:
HostName:
Ref: ApexBucket
为了开始添加 DNS 记录,我们首先需要向 Route 53 添加一个托管区域。如以下代码所示,这相对简单。我们将提供的 Name
将作为参数传递给我们的 CloudFormation 模板:
DNSHostedZone:
Type: "AWS::Route53::HostedZone"
Properties:
Name:
Ref: DomainName
现在我们有了托管区域,可以继续为它创建 DNS 记录了。为此,我们使用 AWS 资源类型 AWS::Route53::RecordSetGroup
。
我们将为我们域名的 root/apex
项创建一个 A 记录,并且我们会将它设置为别名。这个别名将配置为指向我们选择的区域内 S3 托管网站的 AWS 终端节点。
为了实现模板中的区域可移植性,我们将使用映射来提供所有终端节点。这个映射中的值由 AWS 在其 API 终端节点文档中发布。不过,你不需要查找这些值,因为我们的代码示例提供了最新的终端节点(截至写作时)。终端节点通常不会更改,但随着 AWS 增加更多区域,列表显然会增长。
映射看起来是这样的:
us-east-1:
S3HostedZoneID: Z3AQBSTGFYJSTF
S3AliasTarget: s3-website-us-east-1.amazonaws.com
us-east-2:
S3HostedZoneID: Z2O1EMRO9K5GLX
S3AliasTarget: s3-website.us-east-2.amazonaws.com
我们还需要为 www
创建一个 CNAME
,它将指向我们的 WWWBucket
,以便进行重定向。我们的 DNS 记录的最终资源将如下所示:
DNSRecords:
Type: "AWS::Route53::RecordSetGroup"
Properties:
HostedZoneId:
Ref: DNSHostedZone
RecordSets:
- Name:
Ref: DomainName
Type: A
AliasTarget:
HostedZoneId:
Fn::FindInMap: [ RegionMap, Ref: "AWS::Region",
S3HostedZoneID ]
DNSName:
Fn::FindInMap: [ RegionMap, Ref: "AWS::Region",
S3AliasTarget ]
- Name:
Fn::Join: [ ., [ www, Ref: DomainName ] ]
Type: CNAME
TTL: 300
ResourceRecords:
- Fn::GetAtt: WWWBucket.DomainName
aws cloudformation create-stack \
--stack-name static-website-1 \
--template-body file://03-hosting-a-static-website.yaml \
--parameters \
ParameterKey=DomainName,ParameterValue=
现在是时候将一些内容上传到我们的 S3 存储桶了。这里是我们之前承诺给你的代码片段。内容并不复杂。一旦你成功运行了这些示例,你可以尝试将它们替换为你真实的网站内容:
index.html
Welcome to exmaple.org
example.org
Hello World!
error.html
Error
example.org
Something went wrong!
就这样!一旦 S3 有了一个 index.html
文件来提供服务,你就可以在 S3 上托管一个单页网站了。去试试看吧。提供的 CloudFormation 示例将输出一个 URL,你可以用它来查看你新建的网站。在验证其正常工作后,你可以继续上传你真实的静态网站,享受快速、廉价且无需服务器的托管服务。
让我们来看看一些需要考虑的额外事项。
虽然我们已经在 Route 53 中创建了托管区域和一些 DNS 记录,但实际上还没有人能看到它们。为了将你的网站访客引导到新的 S3 静态网站,你需要将域名委托给 Route 53。这部分留给你作为练习;不过,有一些重要事项需要记住:
你需要将域名委托给的 DNS 服务器可以在你的托管区域的 NS 记录中找到。
如果你的域名已经上线并接近生产环境,你需要确保你的区域 DNS 记录都已经在 Route 53 中重新创建,包括如 MX 记录这类对邮件服务持续性至关重要的内容。
在委托给 AWS 之前,你可以考虑减少 DNS 记录的 TTL 值。如果你需要重新委托或更改记录,这将非常有用。一旦你的 DNS 设置稳定,可以增加 TTL 值。
在这里值得讨论一下跨源资源共享(CORS),因为你在 S3 上托管更多静态网页内容时,了解 CORS 的可能性会更高,尤其是在涉及网页字体时。
一些浏览器实施了同源策略限制。这会阻止浏览器从与当前显示给用户的页面不同的主机名加载某些类型的资源。网页字体就是一个常见的例子,因为如果它们无法正确加载,通常会导致你的网站看起来与预期大相径庭。解决方案是为你的存储桶添加 CORS 配置,允许特定来源或主机名加载其内容。
我们将会把 CORS 配置从完整示例中省略,但如果你需要为存储桶添加一个,下面是如何操作的。更新你的AllowedOrigins
属性,格式可以参考下面的 CloudFormation,你应该就能设置好:
ApexBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Ref DomainName
AccessControl: PublicRead
WebsiteConfiguration:
IndexDocument: index.html
ErrorDocument: error.html
CorsConfiguration:
CorsRules:
- AllowedOrigins:
- example.net
- www.example.net
- example.com
- www.example.com
AllowedMethods:
- GET
MaxAge: 3000
AllowedHeaders:
- Content-*
- Host
在这个操作中,我们将向你展示如何使用 AWS CloudFront 来缓存你的网站。
你考虑执行此操作的主要原因如下:
你内容的副本将地理上靠近你的终端用户,从而改善他们的体验,并更快地为他们提供内容。
内容的提供负担将从你的服务器群上移除。如果你能够关闭一些服务器或减少带宽账单,可能会带来巨大的成本节约。
你可能需要保护自己免受大规模且意外的流量激增。
虽然这章的重点不是这个,CloudFront 让你能够实现Web 应用防火墙(WAF),为你提供额外的保护层,防止恶意攻击者。
不同于大多数 AWS 服务是区域特定的,CloudFront 是一个全球服务。
首先,你需要一个公开可访问的网站。这可以是托管在 S3 上的静态网站,也可以是托管在 EC2 上的动态生成网站。事实上,你的网站甚至不需要托管在 AWS 上也能使用 CloudFront。只要你的网站是公开可访问的,就可以使用 CloudFront。
你还需要能够修改网站的 DNS 记录。我们最终将把它们指向 CloudFront,而不是指向你的 Web 服务器(或 S3 存储桶)。
如果你的网站主要由动态内容组成,你仍然可以通过实施 CloudFront 受益。
首先,CloudFront 将保持与源服务器的持久连接池。这减少了文件传输到用户所需的时间,因为需要执行的三次握手次数减少了。
其次,CloudFront 在 TCP 连接方面实施了一些额外的优化,以提高性能。由于 CloudFront 使用更大的初始 TCP 窗口,因此能够更快地传输更多的数据。
最后,实施像 CloudFront 这样的 CDN 确实给你提供了审查缓存策略和使用缓存控制头的机会。如果你的首页是动态生成的,通过 CloudFront 服务它你会立刻得到一些好处,但如果你让 CloudFront 缓存几分钟,效果会更好。再次强调,成本、最终用户体验和后台性能都是你需要考虑的因素。
分发可以配置多种选项。我们的配置将相对简单,以便你能够尽快上手。但我们会讨论一些更常见的配置选项:
源:一个分发需要至少有一个源。正如其名称所示,源是你的网站内容的来源,来自你公开面向用户的网站。你最关心的属性通常是:
源域名:这是你公开面向用户的网站的主机名。我们提供的 CloudFormation 模板将这个主机名作为参数接受。
源路径:可以配置分发从源站的目录或子文件夹获取内容,例如,如果你只使用 CloudFront 缓存图片,可以设置 /content/images
。在我们的案例中,我们缓存的是整个网站,因此我们根本不指定源路径。
源 ID:当你使用非默认的缓存行为设置并配置多个源时,这一点尤其重要。你需要为源分配唯一的 ID,以便缓存行为知道要针对哪个源进行操作。稍后会对缓存行为进行更多讨论。
HTTP 端口,HTTPS 端口:如果你的源在非标准端口上监听 HTTP 或 HTTPS,你可以使用这些参数来定义这些端口。
源协议策略:你可以配置分发与源服务器进行通信的方式:
仅支持 HTTP
仅支持 HTTPS
匹配查看者
匹配查看者选项根据用户在浏览器中请求的协议将请求转发到源服务器。由于我们在这个方案中保持简单,所以我们选择了仅支持 HTTP。
日志记录:请记住,由于流量减少,访问源服务器的请求也会减少,因此捕获的访问日志也会较少。将这些日志存储在 S3 桶中由 CloudFront 来管理是有意义的。在这个方案中,CloudFormation 模板已经包括了这项内容:
缓存行为:在这个方案中,我们将配置一个单一的(默认)缓存行为,它将把所有请求转发到我们的源服务器。
CloudFront:它允许你对配置的行为进行非常精细的控制。例如,你可能想要对源服务器上的所有.js
和.css
文件应用一个规则。也许你希望将查询字符串转发到源服务器针对这些文件类型。类似地,你可能希望忽略源服务器尝试为图像文件设置的 TTL,而是指示 CloudFront 缓存至少 24 小时。
别名:这些是你希望分发为其提供流量的附加主机名。例如,如果你的源域名配置为loadbalancer.example.org
,你可能希望添加类似以下的别名:
example.org
www.example.org
本方案提供的 CloudFormation 模板期望至少包含一个或多个
别名应以逗号分隔的字符串列表的形式提供。
允许的 HTTP 方法:默认情况下,CloudFront 只会将 GET 和 HEAD 请求转发到源服务器。这个方案没有更改这些默认设置,因此我们没有在提供的模板中声明这个参数。如果你的源服务器提供动态生成的内容,你可能希望声明此参数,并将其值设置为 GET、HEAD、OPTIONS、PUT、POST、PATCH 和 DELETE。
TTL(最小/最大/默认):你可以选择定义对象在 CloudFront 缓存中保留多长时间,直到过期并从源服务器重新获取。由于我们选择保持 CloudFront 的默认值以简化方案,因此在模板中没有包含这个参数。默认值如下:
最小 TTL:0 秒
默认 TTL:1 天
最大 TTL:1 年
价格类别:默认情况下,CloudFront 会从所有的边缘位置提供内容,从而提供最佳的性能。我们将使用最低的价格类别 Price Class 100来部署我们的分发。这对应于美国、加拿大和欧洲的边缘位置。来自澳大利亚的用户可能不会从这个价格类别中受益太多,但你也支付的费用较少。价格类别200增加了亚洲地区,价格类别All则包括南美洲和澳大利亚。
创建 CloudFront 分发时可以指定的值的详细列表和解释,请参见此链接:docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/distribution-web-values-specify.html
。
我们需要做的第一件事(也是唯一的事)是按照下图所示配置 CloudFront 分发:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_03_003.png
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
OriginDomainName:
Description: The hostname of your origin
(i.e. www.example.org.s3-website-ap-southeast-2.amazonaws.com)
Type: String
Aliases:
Description: Comma delimited list of aliases
(i.e. example.org,www.example.org)
Type: CommaDelimitedList
Resources:
DistributionALogBucket:
Type: AWS::S3::Bucket
DistributionA:
Type: AWS::CloudFront::Distribution
Properties:
DistributionConfig:
Origins:
- DomainName:
Ref: OriginDomainName
Id: OriginA
CustomOriginConfig:
OriginProtocolPolicy: http-only
Enabled: true
Logging:
IncludeCookies: false
Bucket:
Fn::GetAtt: DistributionALogBucket.DomainName
Prefix: cf-distribution-a
Aliases:
Ref: Aliases
DefaultCacheBehavior:
TargetOriginId: OriginA
ForwardedValues:
QueryString: false
ViewerProtocolPolicy: allow-all
PriceClass: PriceClass_100
Outputs:
DistributionDomainName:
Description: The domain name of the CloudFront Distribution
Value:
Fn::GetAtt: DistributionA.DomainName
LogBucket:
Description: Bucket where CloudFront logs will be stored
Value:
Ref: DistributionALogBucket
aws cloudformation create-stack \
--stack-name cloudfont-cache-1 \
--template-body file://03-caching-a-website.yaml \
--parameters \
ParameterKey=OriginDomainName,ParameterValue= \
ParameterKey=Aliases,ParameterValue='\,'
在这个教程中,我们将使用 Amazon EFS 为实例提供基于网络的存储。
使用 EFS 与其他 AWS 服务相比的一些好处如下:
保证分布式客户端之间的写入顺序
自动调整大小——无需预分配,也无需缩小
你只需为你使用的空间付费(按 GB 计),无需支付传输或额外费用
这个示例使用的是默认 VPC 和子网,这些在所有 AWS 账户创建时都会自动创建。即使你已经更改了网络配置,本教程所需的仅是一个包含两个或更多不同可用区(AZ)的工作 VPC。
AWSTemplateFormatVersion
和Description
来开始一个新的 CloudFormation 模板: AWSTemplateFormatVersion: "2010-09-09"
Description: Create an EFS file system and endpoints.
Parameters
部分,并在其中定义必需的参数VpcId
和SubnetIds
: VpcId:
Description: VPC ID that contains the subnets that will
access the file system
Type: AWS::EC2::VPC::Id
SubnetIds:
Description: Subnet IDs allowed to access the EFS file system
Type: List
创建一个顶级Resources
属性,用来包含所有定义的资源。
在Resources
属性下,添加EFS
文件系统资源:
FileSystem:
Type: AWS::EFS::FileSystem
Properties:
FileSystemTags:
- Key: Name
Value:
Fn::Sub: "${AWS::StackName} EFS File System"
PerformanceMode: generalPurpose
MountTargetA:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId:
Ref: FileSystem
SecurityGroups:
- Fn::GetAtt: MountTargetSecurityGroup.GroupId
SubnetId:
Fn::Select: [ 0, Ref: SubnetIds ]
MountTargetB:
Type: AWS::EFS::MountTarget
Properties:
FileSystemId:
Ref: FileSystem
SecurityGroups:
- Fn::GetAtt: MountTargetSecurityGroup.GroupId
SubnetId:
Fn::Select: [ 1, Ref: SubnetIds ]
MountTargetSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: EFS endpoint security group
Tags:
- Key: Name
Value: MountTargetSecurityGroup
VpcId:
Ref: VpcId
MountTargetAccessSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: EFS endpoint access security group
Tags:
- Key: Name
Value: MountTargetAccessSecurityGroup
VpcId:
Ref: VpcId
MountTargetIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
FromPort: 2049
GroupId:
Fn::GetAtt: MountTargetSecurityGroup.GroupId
IpProtocol: tcp
SourceSecurityGroupId:
Fn::GetAtt: MountTargetAccessSecurityGroup.GroupId
ToPort: 2049
MountTargetEgress:
Type: AWS::EC2::SecurityGroupEgress
Properties:
DestinationSecurityGroupId:
Fn::GetAtt: MountTargetAccessSecurityGroup.GroupId
FromPort: 2049
GroupId:
Fn::GetAtt: MountTargetSecurityGroup.GroupId
IpProtocol: tcp
ToPort: 2049
MountTargetAccessIngress:
Type: AWS::EC2::SecurityGroupIngress
Properties:
FromPort: 22
GroupId:
Fn::GetAtt: MountTargetAccessSecurityGroup.GroupId
IpProtocol: tcp
CidrIp: 0.0.0.0/0
ToPort: 22
MountTargetAccessEgress:
Type: AWS::EC2::SecurityGroupEgress
Properties:
DestinationSecurityGroupId:
Fn::GetAtt: MountTargetSecurityGroup.GroupId
FromPort: 2049
GroupId:
Fn::GetAtt: MountTargetAccessSecurityGroup.GroupId
IpProtocol: tcp
ToPort: 2049
将你的模板保存为03-working-with-network-storage.yaml
。
使用以下 AWS CLI 命令启动 CloudFormation 堆栈,替换成你自己的 VPC ID 和子网 ID:
aws cloudformation create-stack \
--stack-name wwns1 \
--template-body file://03-working-with-network-storage.yaml \
--parameters \
ParameterKey=VpcId,ParameterValue= \
ParameterKey=SubnetIds,ParameterValue="\, \
"
这是在教程结束时创建的资源的样子:
https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_03_004.png
使用网络存储
我们从第 1 步开始创建标准的 CloudFormation 模板属性。
在第 2 步中,你定义了模板的参数,这些参数将在配置资源时使用。
第 3 步和第 4 步是指定 EFS 资源的地方。它们由一个 EFS 文件系统和在每个可用区(AZ)中的挂载目标组成,这些挂载目标将访问该文件系统。
然后,我们在步骤 5 和 6 中创建安全组:一个用于挂载目标,另一个用于允许连接到挂载目标的实例。
由于这两个安全组之间有双向(或循环)引用,我们必须在步骤 7 和 8 中将它们之间的规则定义为单独的资源。
在步骤 9 中,你将以特定的文件名保存模板,以便在步骤 10 中的命令中引用它来启动堆栈。
为了确认你的 EFS 文件系统、挂载目标和安全组是否正常工作,你还可以配置一些客户端实例来连接它们。将以下资源和参数添加到你已经创建的模板中:
Parameters
部分以配置你的实例: MountPoint:
Description: The path on disk to mount the EFS file system
Type: String
Default: /mnt/efs
KeyName:
Description: The SSH key pair allowed to connect to the client
instance
Type: AWS::EC2::KeyPair::KeyName
Resources
部分添加一个 AutoScalingGroup
;无论你的服务器被配置到哪个可用区,它们都可以通过本地挂载点访问 EFS
文件系统: AutoScalingGroup:
Type: AWS::AutoScaling::AutoScalingGroup
DependsOn: MountTargetA
Properties:
MinSize: 2
MaxSize: 2
LaunchConfigurationName:
Ref: LaunchConfiguration
Tags:
- Key: Name
Value:
Fn::Sub: "${AWS::StackName} EFS Client"
PropagateAtLaunch: true
VPCZoneIdentifier:
Ref: SubnetIds
Resources
部分,添加一个启动配置: LaunchConfiguration:
Type: AWS::AutoScaling::LaunchConfiguration
DependsOn: FileSystem
Properties:
ImageId: ami-1e299d7e
SecurityGroups:
- Ref: MountTargetAccessSecurityGroup
InstanceType: t2.micro
KeyName:
Ref: KeyName
UserData:
Fn::Base64:
Fn::Sub: |
#!/bin/bash -xe
mkdir -p ${MountPoint}
echo 'Waiting for mount target DNS to propagate'
sleep 90
echo '${FileSystem}.efs.${AWS::Region}.amazonaws.com:/
${MountPoint} nfs4
nfsvers=4.1,rsize=1048576,wsize=1048576,hard,timeo=600,
retrans=2 0 0' >>
/etc/fstab
mount -a\nchown ec2-user: ${MountPoint}\n"
aws cloudformation create-stack \
--stack-name wwns1 \
--template-body file://03-working-with-network-storage.yaml \
--parameters \
ParameterKey=VpcId,ParameterValue= \
ParameterKey=SubnetIds,ParameterValue='\, \
' \
ParameterKey=MountPoint,ParameterValue= \
ParameterKey=KeyName,ParameterValue=
一旦新堆栈准备就绪,你将能够 SSH 连接到你的实例并进行验证。
确保它们已经挂载了 EFS 文件系统。
我们与许多公司合作(尤其是在金融行业),这些公司对数据需要保存的最短时间有严格的规定。例如,如果你需要保存客户记录至少 7 年,这可能会变得非常繁琐和昂贵。
使用 S3、Glacier 和生命周期规则,我们可以创建一个灵活的长期备份解决方案,同时自动化备份的归档和清除,降低成本。
我们还将利用 版本控制 来减轻由于文件在备份桶中被意外删除或覆盖而造成的损坏。
首先,我们需要定义一些参数:
ExpirationInDays
:这是我们希望将文件保存在备份中的最大时间。我们已将此值的默认设置为 2,555 天(7 年)。
TransitionToInfrequentAccessInDays
:在备份复制到 S3 后,我们希望将其转移到 不常访问 存储类,以减少成本。这不会影响备份的持久性,但会对其可用性产生轻微影响。我们将其设置为 30 天。
TransitionToGlacierInDays
:在备份保留在不常访问的存储类一段时间后,我们希望将其转移到 Glacier。这样做有助于我们降低成本,但会牺牲检索时间。如果我们需要从 Glacier 恢复备份,等待时间大约为 3-5 小时。我们将默认设置为 60 天。
PreviousVersionsExpirationInDays
:鉴于我们将在桶中启用版本控制,我们希望确保旧版本的文件不会被永久保留——我们使用此功能仅是为了防止意外。我们将此值设置为 60 天,这样我们就有足够的时间识别并从意外删除或覆盖中恢复。
PreviousVersionsToInfrequentAccessInDays
:就像我们的其他备份文件一样,我们希望在一段时间后将旧版本移动到不常访问的存储类,以最小化成本。我们将此值设置为 30 天:
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
ExpirationInDays:
Description: The maximum amount of time to keep files
for
Type: Number
Default: 2555
TransitionToInfrequentAccessInDays:
Description: How many days until files are moved to
the Infrequent Access class
Type: Number
Default: 30
TransitionToGlacierInDays:
Description: How many days until files are moved
to Glacier
Type: Number
Default: 60
PreviousVersionsExpirationInDays:
Description: The maximum amount of time to keep previous
versions of files for
Type: Number
Default: 60
PreviousVersionsToInfrequentAccessInDays:
Description: How many days until previous versions
of files are moved to the Infrequent Access class
Type: Number
Default: 30
name
属性,以避免桶名冲突并最大化区域可移植性。我们还启用了版本控制,并添加了之前 Parameters
中的生命周期规则: Resources:
BackupBucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
LifecycleConfiguration:
Rules:
- Status: Enabled
ExpirationInDays:
Ref: ExpirationInDays
Transitions:
- StorageClass: STANDARD_IA
TransitionInDays:
Ref: TransitionToInfrequentAccessInDays
- StorageClass: GLACIER
TransitionInDays:
Ref: TransitionToGlacierInDays
NoncurrentVersionExpirationInDays:
Ref: PreviousVersionsExpirationInDays
NoncurrentVersionTransitions:
- StorageClass: STANDARD_IA
TransitionInDays:
Ref: PreviousVersionsToInfrequentAccessInDays
Outputs:
BackupBucket:
Description: Bucket where backups are stored
Value:
Ref: BackupBucket
继续并启动此 CloudFormation 堆栈。如果您对参数的默认值感到满意,则无需在 CLI 命令中提供它们:
aws cloudformation create-stack \
--stack-name backup-s3-glacier-1 \
--template-body file://03-backing-up-data-for-compliance.yaml
一旦堆栈创建完成,您就可以开始将备份复制到 S3 桶中,并且不再需要过多担心备份的生命周期和管理。如果在创建桶之后,您决定需要更改过期或转换时间,可以通过简单地更新堆栈的参数来实现。