AWS 管理秘籍(一)

原文: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,并注册以将文件直接通过电子邮件发送给你。

你可以按照以下步骤下载代码文件:

  1. 使用你的电子邮件地址和密码登录或注册我们的网站。

  2. 将鼠标指针悬停在顶部的 SUPPORT 标签上。

  3. 点击“代码下载与勘误”。

  4. 在搜索框中输入书籍名称。

  5. 选择你想下载代码文件的书籍。

  6. 从下拉菜单中选择你购买此书的地方。

  7. 点击“代码下载”。

你还可以通过点击书籍网页上的“代码文件”按钮下载代码文件。此页面可以通过在搜索框中输入书籍名称访问。请注意,你需要登录 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 基础知识

在本章中,我们将介绍:

  • 基础设施即代码

  • 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 网页控制台

创建 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 以编程方式控制服务,接下来我们将更详细地讨论这些内容。

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

DevOps 和 IaC 是密切相关的。将你的基础设施(传统上是运营的关注点)作为代码(传统上是开发的关注点)进行存储的做法,促使了责任的共享,从而促进了协作。

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/B06326_01_02.png

图片来源:维基百科

通过自动化软件开发生命周期中的PACKAGERELEASECONFIGURE活动(如图所示),你可以提高发布速度,同时增加信心。

基于云的 IaC 鼓励为故障做架构设计:因为你的资源是虚拟化的,所以必须为物理(主机)硬件故障的可能性做计划,尽管这种情况不太可能发生。

能够在几分钟内重建整个环境是终极的恢复解决方案。

与物理硬件不同,你可以通过删除关键组件来轻松模拟和测试软件架构中的故障——反正它们都是虚拟的!

服务器配置

服务器端的 IaC 示例包括配置管理工具,如 Ansible、Chef 和 Puppet。

虽然重要,这些配置管理工具并非 AWS 特有,因此我们在此不会详细介绍。如果你需要了解更多,市面上有无数书籍和课程专门讲解此话题。

AWS 上的 IaC

CloudFormation 是 AWS 的 IaC 服务。

使用特定格式和语言编写的模板定义了应当配置的 AWS 资源。CloudFormation 是声明式的,不仅可以配置资源,还可以更新它们。

我们将在下一个主题中详细介绍 CloudFormation。

CloudFormation

本书中我们将广泛使用 CloudFormation,因此理解它是什么以及它如何融入 AWS 生态系统非常重要。这里的信息应该足以帮助你入门,但在必要时,我们会参考 AWS 的官方文档。

什么是 CloudFormation?

CloudFormation 服务允许你以自动化和可重复的方式配置和管理一组 AWS 资源。在 AWS 术语中,这些资源集合被称为堆栈。不过请注意,堆栈的大小可以根据需要调整。它可以由一个单一的 S3 桶组成,也可以包含托管你三层 Web 应用所需的一切。

在本章中,我们将向你展示如何定义要包含在 CloudFormation 堆栈中的资源。我们会进一步讨论这些堆栈的组成,以及何时和为何更倾向于将资源分配到多个堆栈中。最后,我们将分享一些在构建无数 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 模板

这时我们开始动手实践。CloudFormation 模板文件是你堆栈的编程表示,通常以 YAML 或 JSON 形式表达。当你希望创建 CloudFormation 堆栈时,你将这个模板文件通过 API、Web 控制台、命令行工具或其他方法(例如 SDK)推送到 CloudFormation。

模板可以被 CloudFormation 一次又一次地重放,创建多个堆栈实例。

YAML 与 JSON

直到最近,JSON 是唯一的选择。我们实际上鼓励你采用 YAML,并且我们将在本书中使用它作为所有示例。以下是其中一些原因:

  • 它看起来更美观。语法更简洁,如果你选择生成 CloudFormation 模板,几乎每种编程语言都有某种形式的 YAML 库。

  • 你的模板大小将会更小。这从开发人员的角度来看更实用,同时也意味着你更不容易遇到 CloudFormation 模板文件大小限制(50 KB)。

  • 字符串替换功能更易于使用和解释。

  • 你的 EC2 UserData(当 EC2 实例启动时运行的脚本)将更容易实现和维护。

进一步了解 CloudFormation 模板

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的参数,用来指示应用程序以调试模式运行。你通常不希望默认启用此模式,因此可以将此参数的默认值设置为falsedisabled或应用程序理解的其他值。当然,在创建或更新堆栈时,可以覆盖此值。

你可以并且应该为每个参数提供一个简短而有意义的描述。这些描述会在网页控制台的每个参数字段旁边显示。当正确使用时,它们为执行你 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 模板的输出部分经常看到 RefFn::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 发出信号,表示数据库服务器已完成初始化,以便它可以继续创建依赖于它的资源。这就是 WaitConditionWaitConditionHandle 的作用。

首先,你创建一个 AWS::CloudFormation::WaitConditionHandle 类型,之后你可以通过 Ref 来引用它。

接下来,你创建一个 AWS::CloudFormation::WaitCondition 类型。在我们的例子中,我们希望等待时间从数据库服务器创建开始,因此我们指定该 WaitCondition 资源依赖于我们的数据库服务器(DependsOn)。

在数据库服务器完成数据导入并准备接受连接后,它会调用由 WaitConditionHandle 资源提供的回调 URL,向 CloudFormation 发出信号,表示它可以停止等待并开始执行其余的 CloudFormation 堆栈。该 URL 通过 UserData 提供给数据库服务器,仍然使用 Ref。通常,curlwget 或类似工具用于调用该 URL。

WaitCondition 资源也可以设置 Timeout 时间。这是一个以秒为单位的值。在我们的示例中,我们可能会设置为 900,因为我们知道启动数据库并导入数据不应该超过 15 分钟。

下面是一个 DependsOnWaitConditionHandleWaitCondition 组合使用的示例:

ExampleWaitHandle: 
  Type: AWS::CloudFormation::WaitConditionHandle 
  Properties: 
ExampleWaitCondition: 
  Type: AWS::CloudFormation::WaitCondition 
  DependsOn: ExampleEC2Instance 
  Properties: 
    Handle: 
      Ref: ExampleWaitHandle 
    Timeout: 600

函数

CloudFormation 提供了一些内置函数,使得编写模板变得更加简单。我们已经了解了 RefFn::GetAtt。接下来我们看看你可能会遇到的其他一些函数。

Fn::Join

使用 Fn::Join 将一组字符串通过指定的分隔符连接起来,例如:

"Fn::Join": [ ".", [ 1, 2, 3, 4 ] ]

这将产生以下值:

"1.2.3.4"

Fn::Sub

使用 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

当你将这些函数与 RefFn::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::SecurityGroupEgressAWS::EC2::SecurityGroupIngress 类型,而不是 AWS::EC2::SecurityGroup 的入口和出口规则类型。

DSL 和生成器

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 有 s3s3api)。

运行 aws help 查看所有可用的命令/服务—它们可能会在本书打印时有所变化!

子命令

每个命令都有一组子命令,用于执行特定服务的操作。

运行 aws help 查看所有子命令。

选项

子命令接受以 -- 开头的选项。

使用 aws help 查看所有选项及其用途。

虽然大多数是可选的(因此得名),但那些没有被方括号([])括起来的选项是必需的。如果你没有包含它们,将会收到错误信息(并附有相关细节)。

内置文档是开始寻找答案的最佳地方。通常在所有选项描述之后会有示例。否则,网上有很多可用的示例。

有些选项适用于所有或大多数命令,因此它们特别有用,值得了解。

输出

CLI 工具可以配置为以 JSON、表格或文本格式输出。要控制输出类型,请使用 --output 选项。

要为所有命令设置默认的输出类型,可以为你的配置文件设置 output 参数。

JSON

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 骨架

在使用 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

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 用户来说也是如此。

随着 AWS Organizations 的发布,你现在可以集中管理 AWS 账户,将它们安排成逻辑分组和层级结构,并对它们进行以前在 AWS 平台上无法实现的控制。

设置主账户

所有使用 AWS Organizations 进行计费和控制的账户都必须拥有一个主账户。该账户控制组织的成员资格,并支付所有成员的账单(总得有人做这个事情)。

如何操作…

要设置主账户,请执行以下步骤:

  1. 转到你希望成为主账户的账户的我的组织部分。你必须使用根凭证登录(即你用来创建账户的凭证):

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_001.png

  1. 在 AWS 控制台的 AWS Organizations 部分,点击创建组织,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_002.png

  1. 除非有特定需求,否则选择启用所有功能,以便充分利用 AWS Organizations,如下图所示:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_003.png

  1. 现在你的账户已经转换,你可以返回 AWS Organizations 页面查看所有账户的列表:

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

你可以轻松使用 CLI 工具创建你的主账户。以下命令将使你的账户成为主账户,并启用所有组织功能:

aws organizations create-organization

另见

  • 邀请账户的操作步骤

  • 创建成员账户的操作步骤

创建成员账户

一旦你的组织启动并运行,最常见的用途就是自动化账户创建过程。组织内创建的账户被称为成员账户

所有由成员账户产生的费用将由主账户进行计费。

准备工作

显然,你需要一个组织来执行这个操作步骤。请参阅本章中的其他操作步骤来开始使用。

操作步骤…

  1. 运行 CLI 工具命令以创建一个新账户,并填写适当的值:
 aws organizations create-account \
 --email  \
 --account-name  \ 
 --query 'CreateAccountStatus.Id'

  1. 此命令将返回一个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 是一个多步骤过程:

  1. 在主账户中运行以下命令以列出你的成员账户:
 aws organizations list-accounts

  1. 找到你创建的账户(根据其名称),并记录下记录中的 ID 值。使用该 ID,按照以下模式生成角色的 ARN:
 arn:aws:iam:::role/OrganizationAccountAccessRole

  1. 如果你更改了创建的角色名称,请相应更新 ARN 的最后部分。

请参见第八章中的配方,安全性与身份,了解如何最佳地管理多个账户。

服务控制策略

服务控制策略SCPs)是 AWS Organizations 的另一个主要功能。你可以在多个级别/资源上应用它们,包括账户(成员账户和被邀请账户)。查看本章中的其他配方,获取更多细节。

根凭证

一些活动仍然需要账户的根凭证。一个示例活动是关闭(或删除)账户(更多细节请参见下一节)。

为了做到这一点,你需要进行与账户关联的电子邮件的密码恢复过程,尤其是在发送 create-account 请求时。

删除账户

在撰写本文时,无法通过 API 删除在你的组织中创建的账户。我们只能推测,能够通过编程删除组织中创建的成员账户将是一个高度需求的功能,并将在不久的将来得到解决。你仍然可以进入成员账户并使用根凭证关闭它,但这些凭证默认并不存在。

虽然你可以通过 API 删除你的组织,但如果你在组织中创建了任何成员账户,就无法进行删除(因为你不能删除它们,所以你的组织永远不会为空)。这一点在不久的将来会有所改进,但现在仍然值得注意。

另见

  • 设置主账户 配方

  • 添加服务控制策略 配方

  • 第八章中的跨账户用户角色 配方,安全性与身份

邀请账户

虽然创建新账户进入你的组织是有意义的,但你现在该如何处理所有其他账户呢?

你可以邀请现有账户加入你的组织,这意味着你可以从管理角度将它们视为成员账户。这极大简化了账户的管理工作量,因为账户和账户没有单独的处理流程。

由于这通常仅针对每个现有账户执行一次,我们将使用控制台。

所有 AWS 组织功能都可以通过 SDK 和 AWS CLI 工具访问。如果你需要自动化此过程,完全可以实现。

准备工作

你必须为其中一个账户(主账户)启用了 AWS Organizations,并且有另一个尚未成为组织一部分的账户(你将邀请它)。

如何操作…

  1. 从主账户的 AWS 控制台中,点击你的用户名,并从下拉菜单中选择“我的组织”:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_006.png

  1. 你将被带到 AWS Organizations 控制台,在那里你会看到当前账户:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_007.png

  1. 点击控制台右上角的“邀请”标签:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_008.png

  1. 点击“邀请账户”按钮,指定要邀请的账户 ID(或主电子邮件地址):

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_009.png

  1. 一旦点击“邀请”,你将被带到一个邀请列表页面,在那里可以查看状态:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_010.png

  1. 在这个阶段,目标/受邀账户将收到一封通知他们邀请的电子邮件:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_011.png

  1. 登录受邀账户,并在用户菜单下点击“我的组织”链接:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_012.png

  1. 在 AWS Organizations 控制台中,你可以在左侧看到待处理的邀请:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_013.png

  1. 点击邀请,你可以查看其详细信息:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_014.png

  1. 当邀请包含所有功能时,你将被要求确认接受:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_015.png

  1. 确认后,你现在可以看到你已加入的组织的详细信息:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_016.png

  1. 在这个阶段,主账户会收到已接受邀请的通知:

https://github.com/OpenDocCN/freelearn-devops-pt8-zh/raw/master/docs/aws-adm-cb/img/image_02_017.png

  1. 返回主账户,现在你可以看到新账户与主账户一起显示:

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。当您在主帐户中创建组织时,根会自动为您创建。返回给您的 ID 看起来会像这样:r-bmdw

aws organizations list-roots

创建一个 OU

要创建 OU,请执行以下步骤:

  1. 确定您希望此 OU 存在的位置。如果它直接位于根目录下,那么根 ID 将作为父级。或者,如果此 OU 将作为另一个 OU 的子级,使用该 OU 的 ID。显然,如果这是您创建的第一个 OU,则根将作为父级。

  2. 使用 CLI 像这样创建您的 OU:

aws organizations create-organizational-unit \
 --parent-id  \ --name 

获取 OU 的 ID

如果您需要获取 OU 的 ID,可以使用 CLI 进行操作;请注意,您需要知道 OU 的父级。以下是如何在根或 OU 中获取所有 OU 及其 ID 列表的方法:

aws organizations list-organizational-units-for-parent \
  --parent-id 

将帐户添加到 OU 中

要将账户添加到 OU,执行以下步骤:

  1. 当账户首次添加到你的组织时,它将是组织根目录的子账户。要将其添加到你刚刚创建的 OU,你需要使用以下 CLI 命令将其移动:
aws organizations move-account \
 --account-id  \
 --source-parent-id  \
 --destination-parent-id 

  1. 如果你希望将账户从一个 OU 移动到另一个 OU,只需使用相同的命令,但使用现有父 OU 的 ID,而不是根目录的 ID。

从 OU 中移除账户

要从 OU 中移除账户,执行以下步骤:

  1. 如果你希望将一个账户从 OU 中移除,你有两个选择。你可以将它移动到另一个 OU,或者将它移回根目录。如果你决定删除一个 OU,你需要首先确保它里面没有账户(我们接下来会展示如何操作)。

  2. 运行以下命令将账户移回根目录:

 aws organizations move-account \
 --account-id  \
 --source-parent-id  \
 --destination-parent-id 

删除 OU

要删除一个 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":"*" 
        } 
    ] 
}

如何操作…

  1. 在文本编辑器中打开一个新文件,添加你的 JSON 策略文档,并保存。

  2. 像这样运行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

  1. 如果前面的 CLI 命令成功执行,将返回一些 JSON,包含我们刚刚添加的策略 ID。它看起来像这样:p-o9to04s7

  2. 现在你可以继续将此策略附加到 OU。使用以下 CLI 命令来执行此操作:

 aws organizations attach-policy \
 --target-id  \
 --policy-id 

  1. 不幸的是,前面的命令如果成功执行,则不会输出任何内容。你可以通过 AWS Web 控制台重新检查你的操作,或者使用以下 CLI 命令来验证它是否成功:
 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必须*

另请参见

  • 第八章中的与 AWS 账户联邦示例,安全与身份章节,涉及一些关于 IAM 角色的讨论。

第三章:存储与内容交付

在本章中,我们将涵盖以下方案:

  • 托管静态网站

  • 缓存网站

  • 使用网络存储

  • 用于合规的备份数据

介绍

每个这些方案都由 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

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 记录

  • wwwroot/apex的重定向,适用于你的域名

在运行完 CloudFormation 后,你当然需要将内容上传到 CloudFormation 为你创建的存储桶中。

创建 S3 存储桶并托管内容

在这个例子中,我们将为我们的网站www.example.org/创建两个 S3 存储桶。它们分别对应以下主机名:

  • www.example.org

  • example.org

也许现在是时候提醒你,S3 存储桶名称是全局唯一的。你还需要用你拥有的域名替换example.org

  1. 我们将把所有内容放在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

  1. 我们不会将域名硬编码到存储桶名称中。相反,我们将作为参数将域名传递给 CloudFormation 模板,以最大化其可重用性,然后通过!Ref DomainName引用它。为了简化这个配方,我们将设置一个单页网站。在现实中,你的网站当然会由多个文件组成,但你需要遵循的过程完全相同。

  2. 配置索引文档:

    • 索引文档是 S3 在用户在浏览器的地址栏中输入域名时默认提供的文件。这避免了用户需要输入文件的完整路径,即example.org/index.html

    • 通常,你的索引文档会被命名为index.html。我们将在本章最后提供该文件的代码片段。

  3. 配置错误文档:

    • 错误文档是 S3 在出现问题时(如文件丢失、访问禁止、请求错误等)提供的文件。为了保持一致性,我们将其命名为error.html。同样,我们将在本章稍后提供该文件的代码片段。
  4. 在存储桶上启用网站托管:

    • 如前所述,我们需要告诉 S3 它应该从我们的example.org存储桶提供静态网站内容。通常用户会通过 S3 Web 控制台进行此配置,但我们将使用 CloudFormation 来完成此操作。CLI 也提供了一个简便的命令行来完成这个操作。你无需运行这个命令,我们在这里仅作为参考添加它:
 aws s3 website s3://example.org/ 
                  --index-document index.html --error-document error.html

  1. 设置从www主机名的重定向:

    • 在手动执行此任务时,你几乎没有选择,只能打开 Web 控制台并将 www.example.org 存储桶配置为重定向到 example.org 存储桶。没有简便的一行 CLI 命令可以做到这一点。幸运的是,在 CloudFormation 中,这很容易,正如你将在接下来的 CloudFormation 代码片段中看到的那样。
  2. 配置权限:

    • 最后一个存储桶设置任务是配置权限。默认情况下,S3 存储桶是私有的,只有存储桶的所有者可以查看其内容。在这种情况下,这对我们没有太大用处,因为我们需要每个人都能够看到我们的存储桶内容。毕竟,这是一个公共网站。
  3. 如果我们手动配置存储桶,我们会应用类似下面这样的存储桶策略:

      { 
        "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/*" 
        } 
       ] 
      }

  1. 幸运的是,在 CloudFormation 中,这个任务要简单得多。基于之前的示例,我们的 CloudFormation 模板的 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 记录

  1. 现在我们有了托管区域,可以继续为它创建 DNS 记录了。为此,我们使用 AWS 资源类型 AWS::Route53::RecordSetGroup

  2. 我们将为我们域名的 root/apex 项创建一个 A 记录,并且我们会将它设置为别名。这个别名将配置为指向我们选择的区域内 S3 托管网站的 AWS 终端节点。

  3. 为了实现模板中的区域可移植性,我们将使用映射来提供所有终端节点。这个映射中的值由 AWS 在其 API 终端节点文档中发布。不过,你不需要查找这些值,因为我们的代码示例提供了最新的终端节点(截至写作时)。终端节点通常不会更改,但随着 AWS 增加更多区域,列表显然会增长。

  4. 映射看起来是这样的:

        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

  1. 我们准备好发布了。是时候创建我们的 CloudFormation 堆栈了。你可以使用以下 CLI 命令来完成:
 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,你可以用它来查看你新建的网站。在验证其正常工作后,你可以继续上传你真实的静态网站,享受快速、廉价且无需服务器的托管服务。

还有更多……

让我们来看看一些需要考虑的额外事项。

将你的域名委托给 AWS

虽然我们已经在 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 缓存几分钟,效果会更好。再次强调,成本、最终用户体验和后台性能都是你需要考虑的因素。

配置 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

  1. 创建一个新的 CloudFormation 模板,并添加以下代码:
      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

  1. 使用我们上面创建的模板,继续创建 CloudFront 分发。预计需要等待约 20-25 分钟,直到这个堆栈完成创建。由于需要将你的分发配置推送到所有 AWS CloudFront 位置,所以这会花费一些时间:
 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。

如何操作…

  1. 打开你喜欢的文本编辑器,通过定义AWSTemplateFormatVersionDescription来开始一个新的 CloudFormation 模板:
        AWSTemplateFormatVersion: "2010-09-09" 
        Description: Create an EFS file system and endpoints.

  1. 创建一个顶级的Parameters部分,并在其中定义必需的参数VpcIdSubnetIds
        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

  1. 创建一个顶级Resources属性,用来包含所有定义的资源。

  2. Resources属性下,添加EFS文件系统资源:

        FileSystem: 
          Type: AWS::EFS::FileSystem 
          Properties: 
            FileSystemTags: 
              - Key: Name 
                Value: 
                  Fn::Sub: "${AWS::StackName} EFS File System" 
            PerformanceMode: generalPurpose

  1. 添加挂载目标资源,用于连接到你刚刚创建的文件系统:
      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  ]           

  1. 创建一个安全组来控制对挂载目标的访问:
      MountTargetSecurityGroup: 
        Type: AWS::EC2::SecurityGroup 
        Properties: 
          GroupDescription: EFS endpoint security group 
          Tags: 
            - Key: Name 
              Value: MountTargetSecurityGroup 
          VpcId: 
            Ref: VpcId

  1. 创建一个安全组以访问你在上一步创建的挂载目标安全组:
      MountTargetAccessSecurityGroup: 
        Type: AWS::EC2::SecurityGroup 
        Properties: 
          GroupDescription: EFS endpoint access security group 
        Tags: 
          - Key: Name 
            Value: MountTargetAccessSecurityGroup 
        VpcId: 
          Ref: VpcId

  1. 定义挂载目标安全组的入站和出站规则:
      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

  1. 定义挂载目标访问安全组的入站和出站规则:
      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

  1. 将你的模板保存为03-working-with-network-storage.yaml

  2. 使用以下 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 文件系统、挂载目标和安全组是否正常工作,你还可以配置一些客户端实例来连接它们。将以下资源和参数添加到你已经创建的模板中:

  1. 将以下参数添加到你的顶层 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

  1. 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

  1. 仍然在 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"

  1. 使用以下 AWS CLI 命令启动 CloudFormation 堆栈,替换为你自己的参数值:
 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 和生命周期规则,我们可以创建一个灵活的长期备份解决方案,同时自动化备份的归档和清除,降低成本。

我们还将利用 版本控制 来减轻由于文件在备份桶中被意外删除或覆盖而造成的损坏。

如何操作…

  1. 首先,我们需要定义一些参数:

    • 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

  1. 接下来,我们需要创建 S3 桶来存储备份。请注意,我们省略了该桶的 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

  1. 最后,让我们添加一个输出,以便我们知道将备份存储到哪个桶中:
      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 桶中,并且不再需要过多担心备份的生命周期和管理。如果在创建桶之后,您决定需要更改过期或转换时间,可以通过简单地更新堆栈的参数来实现。

你可能感兴趣的:(默认分类,默认分类)