65.9K
CodeProject 正在变化。 阅读更多。
Home

Amazon Web Services 第 4 部分 - 使用 EC2、RDS 和 Route53 创建负载均衡的 IIS/SQL Server 网站的 Cloudformation 模板

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2015 年 5 月 20 日

CPOL

26分钟阅读

viewsIcon

24391

一个功能齐全的示例 Cloudformation 模板,可生成基于 IIS/SQL Server 的负载均衡网站,以及用于在 EC2 实例上自动部署网站的 PowerShell 脚本

引言

这是关于将您的网站部署到 Amazon Web Services (AWS) 的一系列文章的第 4 部分,Amazon 的产品与 Windows Azure 相对。

在第 1、2 和 3 部分中,您学习了如何使用 AWS 服务 Elastic Beanstalk 来部署一个带有 SQL Server 数据库和自有域名的负载均衡的 IIS 网站应用程序。这涉及通过完成一系列菜单来定义您的 EC2 服务器、数据库服务器等。

本部分介绍了 AWS 服务 CloudFormation。这允许您在一个称为模板的文本文件中表达您的整个环境。

本文提出的解决方案使用一个模板来定义托管 Web 应用程序所需的所有 Web 服务器、数据库服务器、负载均衡器、名称服务器等。它还负责部署 Web 应用程序本身。运行一个 Publish.ps1 PowerShell 脚本将创建/更新所有基础设施组件并部署 Web 应用程序,完成后您将拥有一个正在运行的网站。

为什么选择 CloudFormation

通过填写几个表单来指定您的环境非常方便。然而,一旦您的环境变得更复杂,您就会很快遇到这种方法的缺点

  • 可重复性 - 您或您的同事需要在其他区域中拥有一个与您的基础设施完全相同的副本。或者您需要一个与您的生产环境相同的测试环境。使用菜单,您只能记录每一步并手动创建副本。

  • 源代码控制 - 没有系统来跟踪您或您的同事的更改。犯错时无法回滚。

  • 文档 - 要了解环境中有哪些内容,您必须在 AWS 控制台中搜索。

解决方案是将您的环境表示为一个文本文件。这易于存储、分发给他人并进行源代码控制。

AWS 服务 CloudFormation 正好可以实现这一点。您将所有内容定义为一个大的 JSON 对象,保存在一个模板文件中。CloudFormation 读取该文件并创建您指定的所有服务器、负载均衡器等。这个环境称为堆栈

当需要修改您的堆栈时 - 添加/删除服务器、升级/降级服务器等 - 您可以更改模板并再次调用 CloudFormation。它将计算出如何修改现有堆栈以达到您期望的新堆栈,并进行最少的更改,造成最小的中断。

堆栈有自己的名称,例如“测试”或“生产”。您可以拥有多个堆栈并独立管理它们。如果您想要 2 个相同的堆栈,您将使用相同的模板来创建它们。

除了基础设施,CloudFormation 还可以为您部署软件,例如 Web 应用程序。

关于本文

CloudFormation 是一个底层工具。而 Elastic Beanstalk 会处理许多细节,例如创建正确的安全组,您必须在模板中定义所有这些。有很多细节需要正确处理 - 并且有很多方法可以出错。我发现学习曲线可能相当陡峭。

当我开始使用 CloudFormation 创建带有 SQL Server 的 MVC Web 应用程序时,我发现

  • 即使是简单的东西也需要许多组件才能正常工作;
  • AWS 文档虽然广泛,但只能提供 90% 的帮助。您仍然需要自己弄清楚很多事情。
  • 尽管 AWS 和其他公司提供了示例代码,但这些代码对我来说太简单或太粗略了。

因此,我在这里发布了我最终找到的完全成熟的解决方案。您可以直接使用它来部署您自己的 Web 应用程序,或将其作为您自己解决方案的基础。

请注意,这不是 CloudFormation 或 AWS 的入门教程。本文的重点是描述我提出的解决方案。但是,它包含了许多指向 AWS 文档相关部分的链接,以便您了解所有细节。这并不难,而且您会学到很多东西。

本解决方案的目标

本文介绍的解决方案旨在实现两个目标:部署某些基础设施和部署 Web 应用程序及其更新

基础设施目标

基础设施目标是部署一个使用数据库且拥有自己域名的 Web 应用程序

让我们从图的中心开始

  • EC2 实例上的 Web 服务器 - Web 应用程序将在一个或多个 EC2 实例上运行 - 这些是 AWS 云中充当 Web 服务器的虚拟机。

  • SQL Server 数据库服务器 - Web 应用程序访问托管在 RDS (关系数据库服务) 实例上的 SQL Server 数据库。RDS 是一项完全托管的数据库服务,提供自动备份等功能。

  • SQL Server 备用节点 - 为了增强可用性,您可以使用 Multi-AZ 部署,当主数据库服务器发生故障时,备用数据库服务器会自动接管(仅在美国东部(弗吉尼亚北部)、美国西部(俄勒冈)和欧洲(爱尔兰)区域可用)。

    虽然对于公司来说价格合理,但此功能对于个人网站来说可能过于昂贵。因此,我创建了一个 不带备用节点的 CloudFormation 模板,以及一个 带备用节点的模板。

  • 自动扩展组 - 当现有实例过载时,自动扩展组会启动更多 EC2 实例,并在负载较低时终止实例。

  • 存储在 S3 存储桶中的代码包 - 鉴于自动扩展组会随意启动和终止 EC2 实例,因此将软件部署到单个服务器没有意义。相反,包含 Web 应用程序代码的包文件存储在 S3 存储桶中(S3 服务允许您在云中存储文件)。当自动扩展组启动新的 EC2 实例时,它会从 S3 存储桶中检索包并将其安装到新实例上。

  • 负载均衡器 - ELB (弹性负载均衡器) 接收来自 Internet 的 Web 请求,并将它们分发到可用的 Web 服务器。

  • DNS 名称服务器 - 用于将您的域名解析为负载均衡器的 IP 地址。由 Route 53 服务提供。

软件部署目标

该解决方案还实现了一些与软件部署相关的目标

  • 打包 - 将 ASP.NET Web 应用程序打包并存储在 S3 存储桶中。

  • 部署 - 使用 Deploy.ps1 脚本在新的 EC2 实例上安装 IIS 等。

  • 版本标签 - 向 EC2 实例添加带有当前软件版本标签,以便轻松查看特定实例正在运行的版本。

  • 终止和替换 - EC2 实例永远不会被更新的软件版本覆盖。而是终止运行旧软件的实例,并创建具有新软件的新 EC2 实例。这确保所有 EC2 实例都处于相同的已知状态,并且它们都具有最新的 Windows 补丁。

  • 滚动更新 - EC2 实例会逐个替换,因此始终有实例正在运行以处理请求。如果只有一个 EC2 实例,则会创建一个临时的第二个实例。

  • Web.config 更新 - 在部署期间,web.config 文件会使用软件版本、服务器名称、用户名和数据库服务器的密码进行更新。

我没有研究数据库架构更新。如果您使用 Entity Framework Code First,Web 应用程序本身将为您更新架构。但是,如果您无法使用 Entity Framework 或 Code First,则需要进行更多工作。

解决方案组件

解决方案由许多模板、脚本等组成,位于 下载中。 下一节展示了如何使用这些组件。

  • 不带数据库服务器备用节点的 CloudFormation 模板,该模板指定了不带数据库服务器备用节点的 infrastructure。

  • 带数据库服务器备用节点的 CloudFormation 模板,该模板指定了带数据库服务器备用节点的 infrastructure。

  • 非常简单的示例 Web 应用程序,它使用数据库。您可能希望在转向更复杂的内容之前使用它进行实验。

    如果您查看其 web.config 文件,您会发现它有一个 web.release.config 转换,用于生成 Release 版本。该 Release 版本包含占位符 {{DbUsername}}{{DbPassword}}{{DbServer}}{{Version}}。在部署期间,这些将被实际的数据库服务器详细信息和软件版本替换。

  • Deploy.ps1 PowerShell 脚本。
    • 在自动扩展组创建了新的 Web 服务器之后,Web 应用程序源代码树中的任何 Deploy.ps1 脚本都将由 CloudFormation 模板在新 Web 服务器上执行。
    • 但是,这个特定的 Deploy.ps1 文件对其放置位置有一些限制。它必须位于 Web 应用程序的根目录中,也就是主 web.config 所在的位置。
    • 通过参数接收软件版本、数据库服务器详细信息等。
    • 负责启动 IIS、替换 web.config 中的占位符等。

  • Publish.ps1 PowerShell 脚本,它将您的 Web 应用程序打包,存储在 S3 存储桶中,并调用 CloudFormation 服务来部署基础设施和 Web 应用程序。它还会更新现有的堆栈。

  • 堆栈策略,它确定在更新期间可以替换哪些服务器。使用此策略可防止 CloudFormation 例如替换数据库服务器(更多关于堆栈策略的信息)。

  • 用户策略,它为 Publish.ps1 脚本提供了启动基础设施所需的所有权限。

费用

使用 AWS 服务不是免费的。本节在此处说明这一点。我个人发现涉及的金额很少,除了 Multi-AZ 部署 - 不要让它们整夜运行。

定价页面 服务用途
CloudFormation 部署配置
EC2 实例 运行 Web 服务器的虚拟机
弹性负载均衡 负载均衡器
自动扩展 根据负载启动/停止 Web 服务器
Route53 DNS 名称服务器
S3 存储软件包
RDS, SQL Server 许可证 数据库服务器(见下文)

一些有用的工具

Multi-AZ 部署

Multi-AZ 部署比没有备用节点的数据库服务器昂贵得多。

Amazon 使用 SQL Server Mirroring 功能实现了 SQL Server 服务器的故障转移。此功能不适用于 SQL Server Express 或 SQL Server Web Edition。

截至 2015 年 3 月,支持镜像的最便宜的选择是在 db.m1.small 实例上使用 SQL Server Standard Edition 数据库(价格)。

请记住,AWS 将收取 SQL Server Standard Edition 许可证的费用,而 SQL Server Express 许可证是免费的。

此外,您还将为 2 个数据库服务器付费 - 主服务器和备用服务器。

如果您只是随便玩玩,我不会让 Multi-AZ 部署整夜运行。

详细安装步骤

本节介绍如何启动基础设施并部署 Web 应用程序。首先,我们需要完成一些一次性的准备工作,然后就可以运行 Publish.ps1 脚本来创建堆栈。您可以使用相同的脚本稍后更新您的堆栈。

1. AWS 账户

我假设您有一个 AWS 账户(获取一个)和一个密钥对(获取一个)。

2. 下载

将所有 组件下载到您计算机上的一个目录。最简单的方法可能是直接 下载整个 Github 项目(包含本系列的所有文章),然后获取所需组件。

3. 设置用户策略

运行 Publish.ps1 脚本的用户(可能是您自己)需要拥有启动所有不同基础设施元素所需的所有权限。

您可以将这些权限表示为 IAM 策略。然后将该策略附加到用户。

首先创建策略

  1. 登录 AWS 控制台
  2. 点击服务(屏幕顶部)| IAM | 策略 | 创建策略
  3. 点击选择创建您自己的策略
  4. 为您的新策略起一个好名字,例如“Publish-CloudFormation-Stack”。无论您选择什么名字,都将其记录下来。
  5. 打开您刚刚下载的 用户策略文件,并将其内容复制粘贴到策略文档中。您会看到策略只是一个 JSON 对象。
  6. 点击创建策略

然后将新策略附加到用户

  1. 点击用户
  2. 点击将运行 Publish.ps1 脚本的用户;
  3. 点击附加策略
  4. 在过滤器中输入您刚刚创建的策略。选择您的策略。点击附加策略

4. 将凭证存储在凭证存储中

当您运行 AWS PowerShell 命令时,它会向 AWS 发送一条消息以进行更新或检索信息。就像您需要手动登录 AWS 才能执行此操作一样,命令必须携带凭证,以便 AWS 能够对其进行身份验证。

您可以将凭证传递给每个命令,但这会使您的凭证暴露在 PowerShell 脚本中。

更好的方法是将您的凭证存储在 凭证存储中,它只是您机器上的一个文件

  1. 获取将运行 Publish.ps1 脚本的用户的访问密钥和秘密密钥(如何操作)。

  2. 为您的新凭证存储起一个名字,例如“mycredentials”。

  3. 打开 PowerShell 命令窗口并运行

    Set-AWSCredentials -AccessKey <acess key> -SecretKey <secret key> -StoreAs <store name>

顺便说一句,如果您查看 Publish.ps1 脚本,您会发现它使用此命令来告诉当前会话中的 PowerShell 命令使用凭证存储中的凭证。

Set-AWSCredentials -ProfileName <store name> 

5. 查找您的 CIDR

您不希望全世界的每个人都能尝试 RDP 登录您的 EC2 实例或 SSMS 登录您的数据库服务器。

要锁定此功能,Publish.ps1 脚本允许您传入可以 RDP 或 SSMS 登录您的服务器的机器的 CIDR

查找您计算机的 CIDR

  1. 获取您的外部 IP 地址;
  2. 在末尾添加/32。所以,如果您的 IP 地址是130.180.2.320,您的 CIDR 就是130.180.2.320/32

6. 创建 RDS 选项组以启用 SQL Server 镜像

如果您打算使用 Multi-AZ 部署,则只需执行此操作。

AWS 对 SQL Server 的 Multi-AZ 部署实现基于 SQL Server Mirroring 功能。要启用此功能,您需要将 RDS 实例与一个启用了镜像选项的 选项组关联。

因为这个选项组只是一个基础设施组件,您可能会认为可以在 CloudFormation 模板中创建它。奇怪的是,这行不通。您必须手动创建一次。当您运行 Publish.ps1 时,您将通过一个 参数传入您在此处创建的选项组的名称。

创建选项组

  1. 在 AWS 控制台中,点击服务 | RDS | 选项组 | 创建组
  2. 为您的选项组起一个名字,例如“sqlserver-mirroring”。填写名称和描述。写下这个名字,稍后会用到;
  3. 引擎设置为sqlserver-se(标准版)或sqlserver-ee(企业版);
  4. 主要引擎版本设置为版本 11(这与 CloudFormation 模板中指定的EngineVersion相同);
  5. 点击创建。这将创建您的选项组并将您带回到选项组列表;
  6. 选择您新的选项组;
  7. 点击添加选项(页面顶部附近);
  8. 镜像是唯一选项。您可能希望将立即应用设置为。点击添加选项

7. 运行 Publish.ps1 脚本

完成准备工作后,您现在可以运行 Publish.ps1 脚本来启动基础设施并部署 Web 应用程序。

运行时间

运行此脚本需要一段时间。根据我的经验,启动新堆栈和部署网站大约需要 20 分钟。如果您选择带有 Multi-AZ 数据库部署的堆栈,则可能需要 50 分钟。

幸运的是,更新(再次运行同一堆栈的脚本)通常需要更短的时间,因为 CloudFormation 只执行更新所需的最小操作。

定义域

如果您拥有一个要在此处使用的备用域名,您可以通过 websiteDomain 参数将其传递给脚本。

如果您现在没有域名可以使用,只需使用一个虚构域名,例如“mybogusdomain.com”。

Publish.ps1 脚本的用法

.\publish.ps1 -version <code version> -stackName <stack name> -websiteDomain <web site domain> 
    -keyName <key name> -credentialsStoreName <credential store name> -adminCidr <admin cidr> 
    -dbMasterUsername <database username> -dbMasterUserPassword <database password> 
    -bucketName <S3 bucket to store code> -templatePath <template file> 
    -csProjPath <.csproj file of your web application> -dbOptionGroupName <option group name> 
    -stackPolicyPath <file with stack policy>

示例

这只是一个启动基础设施而不带 Multi-AZ 部署的示例。它假定您已将下载的文件存储在目录“c:\aws”中。

请勿盲目复制此内容,而是使用您自己的 参数值,尤其是下面带下划线的参数。

.\publish.ps1 -version 1.0.0 -stackName teststack -websiteDomain mybogusdomain.com -keyName mykeyname 
    -credentialsStoreName mycredentials -adminCidr 130.180.2.320/32 
    -dbMasterUsername dbusername -dbMasterUserPassword 'MustBe$uperHardToGu3ss!' 
    -bucketName must-be-unique-across-all-S3-buckets-in-AWS 
    -templatePath 'c:\aws\Template with SQL Server Express\Ec2RdsRoute54.template' 
    -csProjPath 'c:\aws\SimpleSiteWithDb\SimpleSiteWithDb\SimpleSiteWithDb.csproj'
    -stackPolicyPath 'c:\aws\stackpolicy.txt'

PowerShell 特殊字符的参数值

如果任何参数值包含 $ 符号,请用单引号 (') 将参数值括起来,而不是双引号。这样,PowerShell 就不会将 $ 视为变量的开始并尝试进行扩展。

参数

version

您要部署的代码的版本。例如“2.1.0”。此版本也用作 S3 存储桶中代码包的名称。如果您正在运行 Publish.ps1 来更新基础设施但保持 Web 应用程序不变,请使用相同的版本。

stackName

例如,“Test”或“Live”。您使用模板创建的一组服务器等称为堆栈。通过传递不同的堆栈名称,您可以创建不同的服务器集。

websiteDomain

将与名称服务器关联的 Web 应用程序的域名。例如,Live 堆栈的“mydomain.com”,或 Test 堆栈的“test-domain.com”。

keyName

之前创建的密钥对的名称。您将使用它来登录您的 EC2 实例。请记住,密钥对与区域绑定。

credentialsStoreName

之前存储凭证的凭证存储的名称。

adminCidr

使用您之前找到的 CIDR。

dbMasterUsername
dbMasterUserPassword

RDS 仅支持 SQL Server 身份验证。这些是可以通过 SSMS 访问您的新数据库服务器,并且将被插入到您的 web.config 中的用户名和密码。

bucketName

存储代码包的 S3 存储桶。此名称在所有 AWS 托管的 S3 存储桶中必须是唯一的。为了确保给定的 S3 存储桶名称可用,最简单的方法是自行创建 S3 存储桶,然后通过此参数传递您选择的名称。要打开 S3 控制台,请点击服务 | S3

templatePath

要使用的 CloudFormation 模板的路径。使用下载内容中的模板之一,或使用您自己的模板。

如果您使用自己的模板并且它具有参数,请注意 Publish.ps1 脚本只设置有限数量的参数(在 launch-stack 方法中)。所有其他参数必须是可选的和/或具有默认值。

csProjPath

您要部署的 Web 应用程序的 .csproj 文件的路径。Publish.ps1 脚本将在发布模式下构建站点,打包代码并将其存储在 S3 存储桶中。

dbOptionGroupName (可选)

之前创建的具有镜像启用的选项组的名称。仅当您使用创建 SQL Server 标准版(或更高版本)数据库服务器的模板时才使用此选项(例如 此模板)。

如果您尝试将此类选项组与不支持镜像的引擎(如 SQL Server Express 或 SQL Server Web Edition)一起使用,CloudFormation 将无法创建您的堆栈。

stackPolicyPath (可选)

用于保护堆栈更新期间的数据库等的堆栈策略的文件路径(示例)。如果您不使用堆栈策略,请不要使用此参数。

8. 设置名称服务器

创建堆栈后,您需要更改域名的配置,使其使用您的 新的 Route53 名称服务器

本系列第 3 部分在此处描述了如何操作。

9. 从旧数据库复制数据和架构

如果您有现有数据库,您可能需要将其架构和数据复制到新的 RDS 数据库。本系列第 2 部分在此处描述了如何操作。

除非您删除数据库服务器,否则此操作只需在堆栈初始创建后执行一次。

实施说明

本节不是对 下载内容中每个文件的详细讨论。那会很无聊。我还提供了很多注释,除了模板之外,文件并不复杂。

相反,本节讨论了我在构建此解决方案时学到的一些更有趣的东西。

CloudFormation 模板

从高层次来看,CloudFormation 模板只是一个基础设施资源的列表。构建 CloudFormation 模板的介绍非常值得一读,用户指南也是如此。还有伪参数参考内在函数参考

通过查看 示例模板和代码片段,我学到了很多东西。此外,每个资源都有一个类型,例如AWS::RDS::DBInstance。谷歌搜索这些类型并理解它们的含义,让我对 AWS 的工作方式有了很多了解。

话虽如此,我还是遇到了一些棘手的问题,我想在这里讨论。

将代码包加载到新的 EC2 实例上

自动扩展组负责创建新的 EC2 实例。这包括安装 Web 应用程序、安装 IIS 等。

这项安装工作由启动配置处理 - 这是一个单独的资源。如果您在 模板中搜索 AWS::AutoScaling::AutoScalingGroup,您会发现它通过自动扩展组的 LaunchConfigurationName 属性与之关联。

如果您现在搜索 LaunchConfig,您会发现它包含了关于配置新 EC2 实例的所有信息,包括 AMI 映像 ID、实例类型以及与安装 Web 应用程序相关的所有内容。安装过程分布在两个属性中:UserData 属性和元数据属性中的 AWS::CloudFormation::Init 对象。

UserData 属性包含在新 EC2 实例创建后将在其上运行的脚本。奇怪的是,它是Base64 编码的。幸运的是,内置的 内在函数 Fn::Base64 为我们进行了 Base64 编码。

"LaunchConfig" : {
    "Type" : "AWS::AutoScaling::LaunchConfiguration",
    "Properties" : {
        "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [
            "<script>\n",
                "... MS-DOS commands ... \n"
            "</script>\n",
            "<powershell>\n",
                "... PowerShell commands ... \n"
            "</powershell>\n"
        ]] } }
    }
}

查看 模板,您会看到一个 MS-DOS 命令调用了 cfn-init.exe 程序。这个 CloudFormation 辅助脚本始终可以在 EC2 实例上使用。它处理 AWS::CloudFormation::Init 对象中的元数据。您会在下面看到,此模板中使用的 AWS::CloudFormation::Init 对象会促使 cfn-init.exe 从 S3 存储桶加载一个包文件(.zip 文件)并将其文件提取到 c:\inetpub\deploy 目录。

cfn-init.exe 执行之后,PowerShell 脚本开始运行。它查找代码包中所有名为 Deploy.ps1 的文件,并调用它们作为 PowerShell 脚本。请注意,它必须暂时设置执行策略Bypass 才能实现这一点。然后它会清理 c:\inetpub\deploy 目录。

值得一读的是 AWS::CloudFormation::Init 文档。它的一个有用技巧是 sources 部分,它允许您从 URL 下载 .zip 文件并将其解压到 EC2 实例上的目录中。这里的 URL 是 S3 存储桶中的包,但您也可以从 Github 加载 .zip 文件。

原则上,您可以将文件解压到任何目录。但是,请记住:

  • c:\inetpub\temp 被 IIS 用于自身目的。删除它会破坏功能。
  • c:\inetpub\wwwroot 被 IIS 中的默认网站使用。
  • %temp% 由 Windows Explorer 扩展为临时目录,但 AWS::CloudFormation::Init 不会。

这就是为什么最终我使用 c:\inetpub\deploy 作为临时目录来解压 Web 应用程序的原因。

启动软件更新过程

您可以运行 Publish.ps1 脚本来纯粹安装新版本的 Web 应用程序,而无需更改 CloudFormation 模板。作为其中的一部分,Publish.ps1 会将新包上传到 S3 存储桶。问题是如何让启动配置获取此新版本并用运行新版本的新 EC2 实例替换运行旧版本的 EC2 实例。幸运的是,AWS 使这相对容易。

首先,当您更新启动配置的属性时,该启动配置将被替换为一个新配置。然后,当其自动扩展组创建新的 EC2 实例时,这些实例将获得您的 Web 应用程序的最新版本

如果您查看启动配置中使用的 AWS::CloudFormation::Init 对象,您会看到当您更新 Version 参数时,sources 属性会发生变化。这是因为每个包的名称都基于版本。因此,这解决了如何为新 EC2 实例提供最新的 Web 应用程序版本的问题。

基于包版本来命名意味着会保留以前版本的包(除非您手动删除它们)。这显然会占用空间。为了节省空间,您可以给所有包相同的名称,这样旧包就会被覆盖(您需要修改 Publish.ps1 脚本来实现这一点)。但是,在这种情况下,sources 属性不再随版本变化。

在这种情况下,为了在版本更改时仍然替换启动配置,您可以将元数据中的Version属性设置为

"LaunchConfig" : {
    "Type" : "AWS::AutoScaling::LaunchConfiguration",
    "Metadata" : {
        "Version" : { "Ref" : "Version" },

确保新 EC2 实例获得最新的代码后,我们仍然需要处理掉运行旧代码的 EC2 实例。您可以通过为自动扩展组指定一个 UpdatePolicy 属性(在模板中搜索“UpdatePolicy”)来实现这一点。除了使自动扩展组以滚动更新的方式替换 EC2 实例之外,它还允许您指定一次替换多少个 EC2 实例等。

允许 EC2 实例从 S3 存储桶读取文件

EC2 实例要从 S3 存储桶加载包,它们必须具有读取权限。

这可以通过创建角色来完成。这是一组权限,可以暂时分配给例如用户。权限本身包含在策略中,该策略需要附加到角色。

在模板中,执行GetObject操作(即文件加载)的权限在类型为 AWS::IAM::PolicyRolePolicies资源中编码。它的Roles属性将策略附加到类型为 AWS::IAM::RoleInstanceRole资源。

一个额外的细节是,并不是 EC2 实例本身在加载包,而是运行在该虚拟机上的 Windows 软件。因此,InstanceRole需要首先被添加到 InstanceProfile详细信息)。在模板中,这个 InstanceProfile 被富有想象力地命名为 InstanceProfile

最后,我们可以通过其 IamInstanceProfile 属性将 InstanceProfile 附加到启动配置(资源 LaunchConfig)。

设置访问 AWS::CloudFormation::Init 中列出的资源的凭证

除了 允许 EC2 实例从 S3 存储桶读取文件之外,您还需要提供访问这些文件的凭证(除非它们根本不受保护)。

您可以通过向启动配置的元数据中添加 AWS::CloudFormation::Authentication 对象来实现这一点(在 模板中搜索“AWS::CloudFormation::Authentication”)。您可以使用它来提供任何资源或文件在您的 AWS::CloudFormation::Init 对象中的凭证。如果您要从例如 Github 中检索文件或资源,这将是提供 Github 凭证的地方。

就提供 S3 存储桶的凭证而言,这里最简单的方法是引用模板已创建的 InstanceRole 对象。

一些我发现有用的页面

向 EC2 实例添加版本标签

一个目标是为每个 EC2 实例添加一个版本标签,以便轻松了解它运行的软件版本。当然,EC2 实例会由自动扩展组创建和终止,所以您不能直接向 EC2 实例添加标签。

一个简单的解决方案是将版本标签添加到自动扩展组本身(详细信息)。如果您查看模板中的 WebServerGroup(类型为 AWS::AutoScaling::AutoScalingGroup),您会发现它有一个包含版本标签的Tags属性。将 PropagateAtLaunch 设置为true可确保标签将被复制到新启动的 EC2 实例。

Publish.ps1

您运行此 PowerShell 脚本来创建或更新堆栈。

此脚本使用 AWS Tools for Windows PowerShell 提供的 PowerShell Cmdlets 与 AWS 进行交互。我发现它工作得很好,并且文档也很完善。

我在此脚本编写过程中学到的一些东西

  • 互联网上的一些示例 CloudFormation 模板会硬编码 Amazon Machine Image (AMI) 的 ID 以便与 EC2 实例一起使用。我遵循了他们的做法,直到有一天我发现我硬编码的 AMI 不再存在。

    事实上,AWS 定期提供新的更新 AMI,具有新的 ID,因此硬编码 ID 无法长期有效。解决方案是每次创建或更新堆栈时获取最新的 EC2 实例 AMI。

    $imageId = (Get-EC2ImageByName -Names WINDOWS_2012R2_BASE | Select -ExpandProperty ImageId)

  • launch-stack 方法的末尾,它会等待堆栈完全创建或更新。它通过每 5 秒轮询一次堆栈状态来做到这一点(在 waitfor-stack-status 方法中)。我必须解释 AWS 堆栈状态(一个字符串)才能找出创建/更新是否成功/失败或仍在进行中。拥有完整的堆栈状态代码集使这变得更容易。

  • Cmdlets New-CFNStackUpdate-CFNStack 用于使用模板创建/更新堆栈。当您的模板创建例如用于授予 EC2 实例访问 S3 存储桶权限的 IAM Instance Profile 时,您必须通过传递“CAPABILITY_IAM”给 Capability 参数来允许 Cmdlets 使用该模板。
    New-CFNStack -Capability @( "CAPABILITY_IAM" ) ....
  • upload-deployment 方法中,我使用了 MSBuild,特别是它的 Package 目标,通过以下行来构建 Web 应用程序并将其打包成一个 .zip 文件
    msbuild $csProjPath /t:Package /p:Configuration=Release /p:PackageLocation=$releaseZip /p:AutoParameterizationWebConfigConnectionStrings=False

    我查看了替代方案,例如 OctoPack,但这是最简单的方法,并且效果很好。

    默认情况下,Package 目标会将 web.config 的连接替换为可替换的令牌,但这正是我不想要的。将 AutoParameterizationWebConfigConnectionStrings 设置为False会抑制此行为。

Deploy.ps1 PowerShell 脚本

此 PowerShell 脚本在 Web 应用程序包复制到 EC2 实例并解压缩后在其上运行。它并不复杂,并且有很好的文档记录。

一些有趣的事情

  • 您会看到我使用了 appcmd.exe 来处理 IIS,而不是更易于使用的 IIS Cmdlets

    这样做的原因是因为 IIS Cmdlets 需要加载 WebAdministration 模块,而我发现我无法保证这一点总是存在的。所以我使用了 appcmd.exe,它总是有效的。

  • 我有时会遇到错误消息HTTP Error 500.21 - Internal Server Error Handler "ExtensionlessUrlHandler-Integrated-4.0" has a bad module "ManagedPipelineHandler" in its module list

    解决方案是重新安装 .Net 框架(Stack Overflow 讨论),使用

    cmd /c %systemroot%\Microsoft.NET\Framework\v4.0.30319\aspnet_regiis.exe -i

  • 请小心 PowerShell Cmdlet Out-File。默认情况下,它会生成一个 Unicode 编码的文件。IIS 在读取例如 web.config 时对此感到困扰。我认为在大多数情况下,UTF8 更好。
    Out-File ..... -encoding UTF8

试用网站 Web.Release.config

这是生成 web.config 发布版本的 web.config 转换。您可以看到将由 Deploy.ps1 替换的占位符。

一些连接字符串使用Integrated Security=<a href="http://stackoverflow.com/questions/1229691/difference-between-integrated-security-true-and-integrated-security-sspi" target="_blank">SSPI;。不要在 AWS 托管的网站上使用此设置。它会导致 AWS 尝试使用NT AUTHORITY\ANONYMOUS LOGON账户登录您的数据库,而不是您自己的账户 - 这将失败。

后续章节

未来的章节中,我打算讨论如何从 TeamCity 部署堆栈,蓝绿部署以及将大型模板分解成可管理的块。

© . All rights reserved.