演练:更新堆栈 - Amazon CloudFormation
Amazon Web Services 文档中描述的 Amazon Web Services 服务或功能可能因区域而异。要查看适用于中国区域的差异,请参阅 中国的 Amazon Web Services 服务入门 (PDF)

演练:更新堆栈

借助 Amazon CloudFormation,您可以在您现有的堆栈中更新资源的属性。更改范围可包括从更新 CloudWatch 警报上的警报阈值等简单配置更改到更新 Amazon EC2 实例上运行之 Amazon 系统映像 (AMI) 等较复杂的更改。模板中的很多 Amazon 资源都可进行更新,我们会继续添加对更多资源的支持。

此部分将带您逐步了解更新正在运行堆栈的简单进展。此部分将向您展示,使用模板如何能将版本控制系统像用于您正在运行的软件那样用于您的 Amazon 基础设施的配置。我们将带您逐步了解以下步骤:

  1. 创建起始堆栈 - 使用基础 Amazon Linux AMI 创建堆栈,从而使用 Amazon CloudFormation 帮助程序脚本安装 Apache Web 服务器和简单 PHP 应用程序。

  2. 更新应用程序 - 使用 CloudFormation 更新应用程序中的一个文件并部署软件。

  3. 更新实例类型 - 更改底层 Amazon EC2 实例的实例类型。

  4. 更新 Amazon EC2 实例上的 AMI - 在您的堆栈中更改 Amazon EC2 实例的 Amazon 机器映像(AMI)。

  5. 将密钥对添加到实例 - 向实例中添加 Amazon EC2 密钥对,然后更新安全组以允许 SSH 访问实例。

  6. 更改堆栈的资源 - 在堆栈中添加和删除资源,从而通过更新模板将其转换为自动扩展的负载均衡应用程序。

简单的应用程序

我们将从创建可在本部分剩下的所有内容中使用的堆栈开始。我们已提供了一个简单的模板来启动在 Apache Web Server 中托管并在 Amazon Linux AMI 上运行的简单实例 PHP Web 应用程序。

Apache Web Server、PHP 和简单的 PHP 应用程序全部都由默认安装在 Amazon Linux AMI 上的 CloudFormation 帮助程序脚本进行安装。以下模板代码段显示描述待安装软件包和文件的元数据,此情况下为 Amazon Linux AMI 的 Yum 存储库中的 Apache Web Server 和 PHP 基础设施。代码段还显示 Services 部分,以确保 Apache Web Server 处于运行状态。Amazon EC2 实例定义的 Properties 部分中的 UserData 属性包含调用 cfn-init 来安装软件包和文件的 CloudInit 脚本。

"WebServerInstance": { "Type" : "AWS::EC2::Instance", "Metadata" : { "AWS::CloudFormation::Init" : { "config" : { "packages" : { "yum" : { "httpd" : [], "php" : [] } }, "files" : { "/var/www/html/index.php" : { "content" : { "Fn::Join" : ["", [ "<?php\n", "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n", "echo '<p>", { "Ref" : "WelcomeMessage" }, "</p>';\n", "?>\n" ]]}, "mode" : "000644", "owner" : "apache", "group" : "apache" }, }, : "services" : { "sysvinit" : { "httpd" : { "enabled" : "true", "ensureRunning" : "true" } } } } } }, "Properties": { : "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash\n", "yum install -y aws-cfn-bootstrap\n", : "# Install the files and packages from the metadata\n", "/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource WebServerInstance ", " --region ", { "Ref" : "AWS::Region" }, "\n", : ]]}} } },

应用程序本身是两行字“Hello World”示例,在模板中进行了完整定义。对于现实工作中的应用程序,文件可存储在 Amazon S3、GitHub 或另一个存储库中,并通过模板进行参考。CloudFormation 可下载软件包(如 RPM 或 RubyGem),并能引用单个的文件以及展开 .zip.tar 文件,以在 Amazon EC2 实例上创建应用程序项目。

模板用于启用和配置 cfn-hup 守护程序以侦听 Amazon EC2 实例元数据中所定义配置的更改。您可以使用 cfn-hup 后台程序更新应用程序软件,如 Apache 或 PHP 的版本,或可更新 Amazon CloudFormation 中的 PHP 应用程序文件。来自模板中同一个 Amazon EC2 资源的以下代码段显示的是,在检测到元数据的任何更改时配置 cfn-hup 以调用 cfn-init 来更新软件所需的部件:

"WebServerInstance": { "Type" : "AWS::EC2::Instance", "Metadata" : { "AWS::CloudFormation::Init" : { "config" : { : "files" : { : "/etc/cfn/cfn-hup.conf" : { "content" : { "Fn::Join" : ["", [ "[main]\n", "stack=", { "Ref" : "AWS::StackName" }, "\n", "region=", { "Ref" : "AWS::Region" }, "\n" ]]}, "mode" : "000400", "owner" : "root", "group" : "root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : { "content": { "Fn::Join" : ["", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, " -r WebServerInstance ", " --region ", { "Ref" : "AWS::Region" }, "\n", "runas=root\n" ]]} } }, : }, "Properties": { : "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ : "# Start up the cfn-hup daemon to listen for changes to the Web Server metadata\n", "/opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'\n", : ]]}} } },

为了完成堆栈,模板创建了一个 Amazon EC2 安全组。

{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "AWS CloudFormation Sample Template: Sample template that can be used to test EC2 updates. **WARNING** This template creates an Amazon Ec2 Instance. You will be billed for the AWS resources used if you create a stack from this template.", "Parameters" : { "InstanceType" : { "Description" : "WebServer EC2 instance type", "Type" : "String", "Default" : "t2.small", "AllowedValues" : [ "t1.micro", "t2.nano", "t2.micro", "t2.small", "t2.medium", "t2.large", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge", "c1.medium", "c1.xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "g2.2xlarge", "g2.8xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "d2.xlarge", "d2.2xlarge", "d2.4xlarge", "d2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge", "cg1.4xlarge" ], "ConstraintDescription" : "must be a valid EC2 instance type." } }, "Mappings" : { "AWSInstanceType2Arch" : { "t1.micro" : { "Arch" : "HVM64" }, "t2.nano" : { "Arch" : "HVM64" }, "t2.micro" : { "Arch" : "HVM64" }, "t2.small" : { "Arch" : "HVM64" }, "t2.medium" : { "Arch" : "HVM64" }, "t2.large" : { "Arch" : "HVM64" }, "m1.small" : { "Arch" : "HVM64" }, "m1.medium" : { "Arch" : "HVM64" }, "m1.large" : { "Arch" : "HVM64" }, "m1.xlarge" : { "Arch" : "HVM64" }, "m2.xlarge" : { "Arch" : "HVM64" }, "m2.2xlarge" : { "Arch" : "HVM64" }, "m2.4xlarge" : { "Arch" : "HVM64" }, "m3.medium" : { "Arch" : "HVM64" }, "m3.large" : { "Arch" : "HVM64" }, "m3.xlarge" : { "Arch" : "HVM64" }, "m3.2xlarge" : { "Arch" : "HVM64" }, "m4.large" : { "Arch" : "HVM64" }, "m4.xlarge" : { "Arch" : "HVM64" }, "m4.2xlarge" : { "Arch" : "HVM64" }, "m4.4xlarge" : { "Arch" : "HVM64" }, "m4.10xlarge" : { "Arch" : "HVM64" }, "c1.medium" : { "Arch" : "HVM64" }, "c1.xlarge" : { "Arch" : "HVM64" }, "c3.large" : { "Arch" : "HVM64" }, "c3.xlarge" : { "Arch" : "HVM64" }, "c3.2xlarge" : { "Arch" : "HVM64" }, "c3.4xlarge" : { "Arch" : "HVM64" }, "c3.8xlarge" : { "Arch" : "HVM64" }, "c4.large" : { "Arch" : "HVM64" }, "c4.xlarge" : { "Arch" : "HVM64" }, "c4.2xlarge" : { "Arch" : "HVM64" }, "c4.4xlarge" : { "Arch" : "HVM64" }, "c4.8xlarge" : { "Arch" : "HVM64" }, "g2.2xlarge" : { "Arch" : "HVMG2" }, "g2.8xlarge" : { "Arch" : "HVMG2" }, "r3.large" : { "Arch" : "HVM64" }, "r3.xlarge" : { "Arch" : "HVM64" }, "r3.2xlarge" : { "Arch" : "HVM64" }, "r3.4xlarge" : { "Arch" : "HVM64" }, "r3.8xlarge" : { "Arch" : "HVM64" }, "i2.xlarge" : { "Arch" : "HVM64" }, "i2.2xlarge" : { "Arch" : "HVM64" }, "i2.4xlarge" : { "Arch" : "HVM64" }, "i2.8xlarge" : { "Arch" : "HVM64" }, "d2.xlarge" : { "Arch" : "HVM64" }, "d2.2xlarge" : { "Arch" : "HVM64" }, "d2.4xlarge" : { "Arch" : "HVM64" }, "d2.8xlarge" : { "Arch" : "HVM64" }, "hi1.4xlarge" : { "Arch" : "HVM64" }, "hs1.8xlarge" : { "Arch" : "HVM64" }, "cr1.8xlarge" : { "Arch" : "HVM64" }, "cc2.8xlarge" : { "Arch" : "HVM64" } }, "AWSRegionArch2AMI" : { "us-east-1" : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"}, "us-west-2" : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"}, "us-west-1" : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"}, "eu-west-1" : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"}, "eu-west-2" : {"HVM64" : "ami-f976839e", "HVMG2" : "NOT_SUPPORTED"}, "eu-west-3" : {"HVM64" : "ami-0ebc281c20e89ba4b", "HVMG2" : "NOT_SUPPORTED"}, "eu-central-1" : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"}, "ap-northeast-1" : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"}, "ap-northeast-2" : {"HVM64" : "ami-0a10b2721688ce9d2", "HVMG2" : "NOT_SUPPORTED"}, "ap-northeast-3" : {"HVM64" : "ami-0d98120a9fb693f07", "HVMG2" : "NOT_SUPPORTED"}, "ap-southeast-1" : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"}, "ap-southeast-2" : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"}, "ap-south-1" : {"HVM64" : "ami-0912f71e06545ad88", "HVMG2" : "ami-097b15e89dbdcfcf4"}, "us-east-2" : {"HVM64" : "ami-0b59bfac6be064b78", "HVMG2" : "NOT_SUPPORTED"}, "ca-central-1" : {"HVM64" : "ami-0b18956f", "HVMG2" : "NOT_SUPPORTED"}, "sa-east-1" : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"}, "cn-north-1" : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"}, "cn-northwest-1" : {"HVM64" : "ami-6b6a7d09", "HVMG2" : "NOT_SUPPORTED"} } }, "Resources" : { "WebServerInstance": { "Type" : "AWS::EC2::Instance", "Metadata" : { "Comment" : "Install a simple PHP application", "AWS::CloudFormation::Init" : { "config" : { "packages" : { "yum" : { "httpd" : [], "php" : [] } }, "files" : { "/var/www/html/index.php" : { "content" : { "Fn::Join" : ["", [ "<?php\n", "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n", "?>\n" ]]}, "mode" : "000644", "owner" : "apache", "group" : "apache" }, "/etc/cfn/cfn-hup.conf" : { "content" : { "Fn::Join" : ["", [ "[main]\n", "stack=", { "Ref" : "AWS::StackId" }, "\n", "region=", { "Ref" : "AWS::Region" }, "\n" ]]}, "mode" : "000400", "owner" : "root", "group" : "root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : { "content": { "Fn::Join" : ["", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, " -r WebServerInstance ", " --region ", { "Ref" : "AWS::Region" }, "\n", "runas=root\n" ]]} } }, "services" : { "sysvinit" : { "httpd" : { "enabled" : "true", "ensureRunning" : "true" }, "cfn-hup" : { "enabled" : "true", "ensureRunning" : "true", "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]} } } } } }, "Properties": { "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] }, "InstanceType" : { "Ref" : "InstanceType" }, "SecurityGroups" : [ {"Ref" : "WebServerSecurityGroup"} ], "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash -xe\n", "yum install -y aws-cfn-bootstrap\n", "# Install the files and packages from the metadata\n", "/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource WebServerInstance ", " --region ", { "Ref" : "AWS::Region" }, "\n", "# Start up the cfn-hup daemon to listen for changes to the Web Server metadata\n", "/opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'\n", "# Signal the status from cfn-init\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource WebServerInstance ", " --region ", { "Ref" : "AWS::Region" }, "\n" ]]}} }, "CreationPolicy" : { "ResourceSignal" : { "Timeout" : "PT5M" } } }, "WebServerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP access via port 80", "SecurityGroupIngress" : [ {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"} ] } } }, "Outputs" : { "WebsiteURL" : { "Description" : "Application URL", "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "WebServerInstance", "PublicDnsName" ]}]] } } } }

此示例中采用的是单个 Amazon EC2 实例,但您可以在使用 Elastic Load Balancing 和 Amazon EC2 Auto Scaling 组管理应用程序服务器集合的更复杂解决方案上使用相同的机制。但是,自动扩缩组有很多特殊注意事项。有关更多信息,请参阅更新自动扩缩组

创建起始堆栈

我们将使用 Amazon Web Services Management Console 通过示例模板创建起始堆栈以实现此示例的目的。

警告

此程序完成后将会部署实时的 Amazon 服务。只要这些服务在运行,您就要按照标准使用费率付费。

要通过 Amazon Web Services Management Console创建堆栈
  1. 复制上一个模板并将其作为文本文件本地保存到您的系统中。注意保存位置,因为您需要在后续步骤中使用此文件。

  2. 通过以下网址登录 CloudFormation 控制台:https://console.aws.amazon.com/cloudformation

  3. 选择创建新堆栈

  4. Create New Stack (创建新堆栈) 向导中的 Select Template (选择模板) 屏幕上,在 Name (名称) 字段中键入 UpdateTutorial。在同一页上,选择将模板上传到 Amazon S3 并浏览到在第一步中下载的文件,然后选择下一步

  5. Specify Parameters (指定参数) 屏幕上的 Instance Type (实例类型) 框中,键入 t1.micro。然后选择下一步

  6. Options (选项)屏幕上,选择 Next (下一步)

  7. Review (审核) 屏幕上,确认所有设置都符合您的要求,然后选择 Create (创建)

当您的堆栈状态变成 CREATE_COMPLETE 后,输出选项卡会显示网站的 URL。如果您选择 WebsiteURL 的输出值,您将看到新 PHP 应用程序在工作。

更新应用程序

现在您已部署好堆栈,接下来更新应用程序吧。我们将对应用程序所打印出的文本进行简单更改。要执行此操作,我们将添加回显命令至 index.php 文件,如此模板代码段所示:

"WebServerInstance": { "Type" : "AWS::EC2::Instance", "Metadata" : { "AWS::CloudFormation::Init" : { "config" : { : "files" : { "/var/www/html/index.php" : { "content" : { "Fn::Join" : ["", [ "<?php\n", "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n", "echo '<p>Updated version via UpdateStack</p>';\n ", "?>\n" ]]}, "mode" : "000644", "owner" : "apache", "group" : "apache" }, : } },

使用文本编辑器手动编辑您保存在本地的模板文件。

现在,我们将更新堆栈。

要通过 Amazon Web Services Management Console更新堆栈
  1. 通过以下网址登录 Amazon CloudFormation 控制台:https://console.aws.amazon.com/cloudformation

  2. 在 Amazon CloudFormation 控制面板中,选择您之前创建的堆栈,然后选择 Update Stack (更新堆栈)

  3. Update Stack (更新堆栈)向导中的Select Template (选择模板)屏幕上,选择 Upload a template to Amazon S3 (将模板上传到 Amazon S3),选择修改后的模板,然后选择 Next (下一步)

  4. Options (选项)屏幕上,选择 Next (下一步)

  5. 因为堆栈没有堆栈策略,所以选择 Next (下一步)。在没有覆盖策略的情况下,所有资源均可更新。

  6. Review (审核) 屏幕上,确认所有设置都符合您的要求,然后选择 Update (更新)

如果您通过 Amazon Web Services Management Console 更新堆栈,您将会注意到创建起始堆栈所用参数已预填充到 Update Stack(更新堆栈)向导的 Parameters(参数)页面上。如果您使用 aws cloudformation update-stack 命令,请务必键入与您原先用于创建堆栈的参数相同的值。

当您的堆栈处于 UPDATE_COMPLETE 状态时,您可以再次选择 WebsiteURL 输出值以验证应用程序的更改已生效。默认状态下,cfn-hup 后台程序每 15 分钟运行一次,因此最多能花 15 分钟在堆栈更新后更改应用程序。

要查看更新的资源集,请转至 Amazon CloudFormation 控制台。在事件选项卡上,查看堆栈事件。在这种特殊情况下,Amazon EC2 实例 WebServerInstance 的元数据已更新,这导致 Amazon CloudFormation 也会重新评估其他资源(WebServerSecurityGroup)以确保没有其他更改。其他堆栈资源均未修改。Amazon CloudFormation 将只更新堆栈中受堆栈的任何更改影响的资源。此类更改可直接进行,如属性或元数据更改,也可由依赖性或 Ref 和 GetAtt 中的数据流或其他内部模板函数导致。

这一简单更新对此过程进行了阐述;但是,您可以对您的 Amazon EC2 实例中所部署文件和软件包进行更复杂的更改。例如,您可能会确定需要将 MySQL 与 MySQL 的 PHP 支持一起添加到实例中。要执行此操作,只需要将附加软件包和文件与任何附加服务一起添加到配置中,然后更新堆栈以部署更改。在以下模板代码段中,更改被红色高亮显示:

"WebServerInstance": { "Type" : "AWS::EC2::Instance", "Metadata" : { "Comment" : "Install a simple PHP application", "AWS::CloudFormation::Init" : { "config" : { "packages" : { "yum" : { "httpd" : [], "php" : [], "php-mysql" : [], "mysql-server" : [], "mysql-libs" : [], "mysql" : [] } }, : "services" : { "sysvinit" : { "httpd" : { "enabled" : "true", "ensureRunning" : "true" }, "cfn-hup" : { "enabled" : "true", "ensureRunning" : "true", "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]}, "mysqld" : { "enabled" : "true", "ensureRunning" : "true" } } } } } }, "Properties": { : } }

您可以更新 CloudFormation 元数据,将应用程序所使用的软件包更新到新版本。前述示例中,每个软件包的版本属性都为空,这表示 cfn-init 应安装最新版的软件包。

"packages" : { "yum" : { "httpd" : [], "php" : [] }

您可以视需要指定软件包的版本字符串。如果您在后续更新堆栈调用中更改版本字符串,则会部署新版软件包。此处显示 RubyGems 软件包版本号的使用示例。支持版本化的任何软件包都可以有特定版本。

"packages" : { "rubygems" : { "mysql" : [], "rubygems-update" : ["1.6.2"], "rake" : ["0.8.7"], "rails" : ["2.3.11"] } }

更新自动扩缩组

如果您在模板中使用与 Amazon EC2 实例资源截然相反的自动扩缩组,应用程序将会以完全相同的方式更新;但是,Amazon CloudFormation 在自动扩缩组中的所有 Amazon EC2 实例上都不会提供任何同步或序列化。每个主机上的 cfn-hup 后台程序都将独立运行且会按其自己的计划更新应用程序。当您使用 cfn-hup 更新实例上的配置时,每个实例都将按其自己的计划运行 cfn-hup 挂接;堆栈中的实例之间不协调。您应该考虑以下各项:

  • 如果自动扩缩组中所有 Amazon EC2 实例的 cfn-hup 更改都同时运行,更新期间您的服务可能不可用。

  • 如果 cfn-hup 更改在不同时间运行,则新旧版软件可能会同时运行。

要避免这些问题,请考虑在自动扩缩组中强制滚动更新您的实例。有关更多信息,请参阅UpdatePolicy 属性

更改资源属性

借助 Amazon CloudFormation,您可以更改堆栈中现有资源的属性。以下部分描述了解决特定问题的各种更新;但是,堆栈中支持更新的任何资源的任何属性都可视需要进行修改。

更新实例类型

我们到目前为止所建立的堆栈使用 t1.micro Amazon EC2 实例。假设您新建的网站获取的流量比 t1.micro 实例能处理的流量多,且您现在想移动到 m1.small Amazon EC2 实例类型中。如果实例类型的架构发生变化,则会使用不同的 AMI 创建实例。在检验模板中的映射时,您将会看到 t1.micro 和 m1.small 实例的架构相同且它们使用相同的 Amazon Linux AMI。

"Mappings" : { "AWSInstanceType2Arch" : { "t1.micro" : { "Arch" : "HVM64" }, "t2.nano" : { "Arch" : "HVM64" }, "t2.micro" : { "Arch" : "HVM64" }, "t2.small" : { "Arch" : "HVM64" }, "t2.medium" : { "Arch" : "HVM64" }, "t2.large" : { "Arch" : "HVM64" }, "m1.small" : { "Arch" : "HVM64" }, "m1.medium" : { "Arch" : "HVM64" }, "m1.large" : { "Arch" : "HVM64" }, "m1.xlarge" : { "Arch" : "HVM64" }, "m2.xlarge" : { "Arch" : "HVM64" }, "m2.2xlarge" : { "Arch" : "HVM64" }, "m2.4xlarge" : { "Arch" : "HVM64" }, "m3.medium" : { "Arch" : "HVM64" }, "m3.large" : { "Arch" : "HVM64" }, "m3.xlarge" : { "Arch" : "HVM64" }, "m3.2xlarge" : { "Arch" : "HVM64" }, "m4.large" : { "Arch" : "HVM64" }, "m4.xlarge" : { "Arch" : "HVM64" }, "m4.2xlarge" : { "Arch" : "HVM64" }, "m4.4xlarge" : { "Arch" : "HVM64" }, "m4.10xlarge" : { "Arch" : "HVM64" }, "c1.medium" : { "Arch" : "HVM64" }, "c1.xlarge" : { "Arch" : "HVM64" }, "c3.large" : { "Arch" : "HVM64" }, "c3.xlarge" : { "Arch" : "HVM64" }, "c3.2xlarge" : { "Arch" : "HVM64" }, "c3.4xlarge" : { "Arch" : "HVM64" }, "c3.8xlarge" : { "Arch" : "HVM64" }, "c4.large" : { "Arch" : "HVM64" }, "c4.xlarge" : { "Arch" : "HVM64" }, "c4.2xlarge" : { "Arch" : "HVM64" }, "c4.4xlarge" : { "Arch" : "HVM64" }, "c4.8xlarge" : { "Arch" : "HVM64" }, "g2.2xlarge" : { "Arch" : "HVMG2" }, "g2.8xlarge" : { "Arch" : "HVMG2" }, "r3.large" : { "Arch" : "HVM64" }, "r3.xlarge" : { "Arch" : "HVM64" }, "r3.2xlarge" : { "Arch" : "HVM64" }, "r3.4xlarge" : { "Arch" : "HVM64" }, "r3.8xlarge" : { "Arch" : "HVM64" }, "i2.xlarge" : { "Arch" : "HVM64" }, "i2.2xlarge" : { "Arch" : "HVM64" }, "i2.4xlarge" : { "Arch" : "HVM64" }, "i2.8xlarge" : { "Arch" : "HVM64" }, "d2.xlarge" : { "Arch" : "HVM64" }, "d2.2xlarge" : { "Arch" : "HVM64" }, "d2.4xlarge" : { "Arch" : "HVM64" }, "d2.8xlarge" : { "Arch" : "HVM64" }, "hi1.4xlarge" : { "Arch" : "HVM64" }, "hs1.8xlarge" : { "Arch" : "HVM64" }, "cr1.8xlarge" : { "Arch" : "HVM64" }, "cc2.8xlarge" : { "Arch" : "HVM64" } }, "AWSRegionArch2AMI" : { "us-east-1" : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"}, "us-west-2" : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"}, "us-west-1" : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"}, "eu-west-1" : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"}, "eu-west-2" : {"HVM64" : "ami-f976839e", "HVMG2" : "NOT_SUPPORTED"}, "eu-west-3" : {"HVM64" : "ami-0ebc281c20e89ba4b", "HVMG2" : "NOT_SUPPORTED"}, "eu-central-1" : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"}, "ap-northeast-1" : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"}, "ap-northeast-2" : {"HVM64" : "ami-0a10b2721688ce9d2", "HVMG2" : "NOT_SUPPORTED"}, "ap-northeast-3" : {"HVM64" : "ami-0d98120a9fb693f07", "HVMG2" : "NOT_SUPPORTED"}, "ap-southeast-1" : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"}, "ap-southeast-2" : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"}, "ap-south-1" : {"HVM64" : "ami-0912f71e06545ad88", "HVMG2" : "ami-097b15e89dbdcfcf4"}, "us-east-2" : {"HVM64" : "ami-0b59bfac6be064b78", "HVMG2" : "NOT_SUPPORTED"}, "ca-central-1" : {"HVM64" : "ami-0b18956f", "HVMG2" : "NOT_SUPPORTED"}, "sa-east-1" : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"}, "cn-north-1" : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"}, "cn-northwest-1" : {"HVM64" : "ami-6b6a7d09", "HVMG2" : "NOT_SUPPORTED"} }

让我们使用在前述部分中进行修改的模板更改实例类型。由于 InstanceType 是模板的输入参数,我们不需要修改模板;我们能在“Stack Update (堆栈更新)”向导的“Specify Parameters (指定参数)”页面上更改参数值。

要通过 Amazon Web Services Management Console更新堆栈
  1. 通过以下网址登录 Amazon CloudFormation 控制台:https://console.aws.amazon.com/cloudformation

  2. 在 CloudFormation 控制面板中,选择您之前创建的堆栈,然后选择 Update Stack (更新堆栈)

  3. Update Stack (更新堆栈) 向导中的 Select Template (选择模板) 屏幕上,选择 Use current template (使用当前模板),然后选择 Next (下一步)

    此时将显示“Specify Details”页,其中的 Specify Parameters 部分预填充了创建初始堆栈所用的参数。

  4. InstanceType 文本框的值从 t1.micro 更改为 m1.small。然后选择下一步

  5. Options (选项)屏幕上,选择 Next (下一步)

  6. 因为堆栈没有堆栈策略,所以选择 Next (下一步)。在没有覆盖策略的情况下,所有资源均可更新。

  7. Review (审核) 屏幕上,确认所有设置都符合您的要求,然后选择 Update (更新)

可以通过启动和停止实例来动态更改 EBS 支持的 Amazon EC2 实例的实例类型。Amazon CloudFormation 将尝试通过更新实例类型和重启实例来优化更改,因此实例 ID 不会更改。但是,实例重启时,实例的公用 IP 地址会更改。为了确保弹性 IP 地址在更改后被正确捆绑,Amazon CloudFormation 还会更新弹性 IP 地址。您可以在“Events”选项卡上的 Amazon CloudFormation 控制台中看到更改。

要通过 Amazon Web Services Management Console 检查实例类型,请打开 Amazon EC2 控制台并在其中查找您的实例。

更新 Amazon EC2 实例上的 AMI

现在让我们来看看如何更改实例上所运行的 Amazon 系统映像 (AMI)。我们将通过更新堆栈来启动 AMI 更改,从而使用新的 Amazon EC2 实例类型,如实例类型为 HVM64 的 t2.medium。

如之前部分所述,我们将使用现有模板更改示例堆栈所使用的实例类型。在“堆栈更新”向导中的“指定参数”页上,更改实例类型的值。

在这种情况下,您不能只通过启动和停止实例来修改 AMI;Amazon CloudFormation 将其视为对资源不可变属性的更改。为了对不可变属性进行更改,Amazon CloudFormation 必须启动替代资源,此情况下为运行新 AMI 的新 Amazon EC2 实例。

在新实例运行之后,Amazon CloudFormation 将更新堆栈中的其他资源以指向新资源。所有新资源被创建且旧资源被删除的过程被称为 UPDATE_CLEANUP。此时,您将注意到堆栈中实例的实例 ID 和应用程序 URL 已随着更新而更改。“Event”表中的事件包含描述“Requested update has a change to an immutable property and hence creating a new physical resource”,以指示资源已被替代。

如果您已将应用程序代码写入您想更新的 AMI 中,您可以使用同一堆栈更新机制更新 AMI 以加载您的新应用程序。

要更新您的堆栈中的实例之 AMI
  1. 创建含有应用程序或操作系统更改的新 AMI。有关更多信息,请转至《Amazon EC2 用户指南(适用于 Linux 实例)》中的创建您自己的 AMI

  2. 更新您的模板以合并新 AMI ID。

  3. 通过 Amazon Web Services Management Console(如更新应用程序中所述)或使用 Amazon 命令 aws cloudformation update-stack 更新堆栈。

在您更新堆栈时,CloudFormation 检测到 AMI ID 已更改,然后用我们启动前一个更新所使用的方法触发堆栈更新。

更新自动扩缩组的 Amazon EC2 启动配置

如果您使用的是自动扩缩组而不是 Amazon EC2 实例,更新正在运行实例的过程会有点不同。借助 Auto Scaling 资源,可将实例类型或 AMI ID 等 Amazon EC2 实例配置封装到 Auto Scaling 启动配置中。您可以用我们在前述部分中对 Amazon EC2 实例资源进行更改时所用的方法对启动配置进行更改。但是,启动配置的更改不会影响自动扩缩组中任何正在运行的 Amazon EC2 实例。更新后的启动配置只适用于更新之后创建的新实例。

如果要将更改传播到自动扩缩组中所有实例的启动配置,则可以使用更新属性。有关更多信息,请参阅UpdatePolicy 属性

添加资源属性

到目前为止,我们已在模板中查看了资源现有属性的更改。您还可以添加原先未在模板中指定的属性。为了阐明上述操作,我们将会添加 Amazon EC2 密钥对到现有 EC2 实例中,然后在 Amazon EC2 安全组中打开端口 22,从而使您可以使用 Secure Shell(SSH)访问实例。

将密钥对添加到实例

向现有 Amazon EC2 实例添加 SSH 访问权限
  1. 向模板额外添加两个参数,从而以现有 Amazon EC2 密钥对和 SSH 位置的名称进行传递。

    "Parameters" : { "KeyName" : { "Description" : "Name of an existing Amazon EC2 key pair for SSH access", "Type": "AWS::EC2::KeyPair::KeyName" }, "SSHLocation" : { "Description" : " The IP address range that can be used to SSH to the EC2 instances", "Type": "String", "MinLength": "9", "MaxLength": "18", "Default": "0.0.0.0/0", "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x." } : },
  2. 将 KeyName 属性添加到 Amazon EC2 实例。

    "WebServerInstance": { "Type" : "AWS::EC2::Instance", : "Properties": { : "KeyName" : { "Ref" : "KeyName" }, : } },
  3. 将端口 22 和 SSH 位置添加到 Amazon EC2 安全组的入口规则。

    "WebServerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP and SSH", "SecurityGroupIngress" : [ {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"}}, {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "CidrIp" : "0.0.0.0/0"} ] } },
  4. 通过 Amazon Web Services Management Console(如更新应用程序中所述)或使用 Amazon 命令 aws cloudformation update-stack 更新堆栈。

更改堆栈的资源

应用程序需求可能会随着时间的推移而变化,Amazon CloudFormation 允许您更改构成堆栈的资源集。为了进行演示,我们从 添加资源属性 中获取单个实例应用程序并通过更新堆栈将其转换成自动扩展型负载均衡应用程序。

这一操作会使用弹性 IP 地址创建简单的单实例 PHP 应用程序。现在,我们将在更新时更改应用程序资源,以将应用程序转变成可用性高、可自动扩展的负载均衡型应用程序。

  1. 添加 Elastic Load Balancer 资源。

    "ElasticLoadBalancer" : { "Type" : "AWS::ElasticLoadBalancing::LoadBalancer", "Properties" : { "CrossZone" : "true", "AvailabilityZones" : { "Fn::GetAZs" : "" }, "LBCookieStickinessPolicy" : [ { "PolicyName" : "CookieBasedPolicy", "CookieExpirationPeriod" : "30" } ], "Listeners" : [ { "LoadBalancerPort" : "80", "InstancePort" : "80", "Protocol" : "HTTP", "PolicyNames" : [ "CookieBasedPolicy" ] } ], "HealthCheck" : { "Target" : "HTTP:80/", "HealthyThreshold" : "2", "UnhealthyThreshold" : "5", "Interval" : "10", "Timeout" : "5" } } }
  2. 将模板中的 EC2 实例转换成 Auto Scaling 启动配置。由于属性都相同,所以我们只需要更改类型名称,从:

    "WebServerInstance": { "Type" : "AWS::EC2::Instance",

    更改为:

    "LaunchConfig": { "Type" : "AWS::AutoScaling::LaunchConfiguration",

    为了使模板更清楚,我们已将资源名称从 WebServerInstance 更改为 LaunchConfig,因此您将需要更新由 cfn-init 和 cfn-hup 引用的资源名称(只需搜索 WebServerInstance 并将其替换为 LaunchConfig(cfn-signal 除外))。对于 cfn-signal,您需要向自动扩缩组 (WebServerGroup) 而非实例发送信号,如以下代码段所示:

    "# Signal the status from cfn-init\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource WebServerGroup ", " --region ", { "Ref" : "AWS::Region" }, "\n"
  3. 添加自动扩缩组资源。

    "WebServerGroup" : { "Type" : "AWS::AutoScaling::AutoScalingGroup", "Properties" : { "AvailabilityZones" : { "Fn::GetAZs" : "" }, "LaunchConfigurationName" : { "Ref" : "LaunchConfig" }, "MinSize" : "1", "DesiredCapacity" : "1", "MaxSize" : "5", "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ] }, "CreationPolicy" : { "ResourceSignal" : { "Timeout" : "PT15M" } }, "UpdatePolicy": { "AutoScalingRollingUpdate": { "MinInstancesInService": "1", "MaxBatchSize": "1", "PauseTime" : "PT15M", "WaitOnResourceSignals": "true" } } }
  4. 更新安全组定义以锁定通过负载均衡器分配至实例的流量。

    "WebServerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP access via port 80 locked down to the ELB and SSH access", "SecurityGroupIngress" : [ {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupOwnerId" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias"]}, "SourceSecurityGroupName" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.GroupName"]}}, {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"}} ] } }
  5. 更新 Outputs 以返回 Elastic Load Balancer 的 DNS 名称,以作为应用程序的位置,从:

    "WebsiteURL" : { "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "WebServerInstance", "PublicDnsName" ]}]]}, "Description" : "Application URL" }

    更改为:

    "WebsiteURL" : { "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ]}]]}, "Description" : "Application URL" }

为方便参考,以下示例显示了完整模板。如果您使用此模板更新堆栈,则会将您的单实例简单应用程序转换成可用性高、可自动扩展的多可用区负载均衡型应用程序。只有需要更新的资源会被修改,所以,如果此应用程序有任何数据存储,该数据都会保持原样。现在,您可以使用 Amazon CloudFormation 在您的要求更改时增大或增强您的堆栈。

{ "AWSTemplateFormatVersion" : "2010-09-09", "Description" : "AWS CloudFormation Sample Template: Sample template that can be used to test EC2 updates. **WARNING** This template creates an Amazon Ec2 Instance. You will be billed for the AWS resources used if you create a stack from this template.", "Parameters" : { "KeyName": { "Description" : "Name of an existing EC2 KeyPair to enable SSH access to the instance", "Type": "AWS::EC2::KeyPair::KeyName", "ConstraintDescription" : "must be the name of an existing EC2 KeyPair." }, "SSHLocation" : { "Description" : " The IP address range that can be used to SSH to the EC2 instances", "Type": "String", "MinLength": "9", "MaxLength": "18", "Default": "0.0.0.0/0", "AllowedPattern": "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})/(\\d{1,2})", "ConstraintDescription": "must be a valid IP CIDR range of the form x.x.x.x/x." }, "InstanceType" : { "Description" : "WebServer EC2 instance type", "Type" : "String", "Default" : "t2.small", "AllowedValues" : [ "t1.micro", "t2.nano", "t2.micro", "t2.small", "t2.medium", "t2.large", "m1.small", "m1.medium", "m1.large", "m1.xlarge", "m2.xlarge", "m2.2xlarge", "m2.4xlarge", "m3.medium", "m3.large", "m3.xlarge", "m3.2xlarge", "m4.large", "m4.xlarge", "m4.2xlarge", "m4.4xlarge", "m4.10xlarge", "c1.medium", "c1.xlarge", "c3.large", "c3.xlarge", "c3.2xlarge", "c3.4xlarge", "c3.8xlarge", "c4.large", "c4.xlarge", "c4.2xlarge", "c4.4xlarge", "c4.8xlarge", "g2.2xlarge", "g2.8xlarge", "r3.large", "r3.xlarge", "r3.2xlarge", "r3.4xlarge", "r3.8xlarge", "i2.xlarge", "i2.2xlarge", "i2.4xlarge", "i2.8xlarge", "d2.xlarge", "d2.2xlarge", "d2.4xlarge", "d2.8xlarge", "hi1.4xlarge", "hs1.8xlarge", "cr1.8xlarge", "cc2.8xlarge", "cg1.4xlarge" ], "ConstraintDescription" : "must be a valid EC2 instance type." } }, "Mappings" : { "AWSInstanceType2Arch" : { "t1.micro" : { "Arch" : "HVM64" }, "t2.nano" : { "Arch" : "HVM64" }, "t2.micro" : { "Arch" : "HVM64" }, "t2.small" : { "Arch" : "HVM64" }, "t2.medium" : { "Arch" : "HVM64" }, "t2.large" : { "Arch" : "HVM64" }, "m1.small" : { "Arch" : "HVM64" }, "m1.medium" : { "Arch" : "HVM64" }, "m1.large" : { "Arch" : "HVM64" }, "m1.xlarge" : { "Arch" : "HVM64" }, "m2.xlarge" : { "Arch" : "HVM64" }, "m2.2xlarge" : { "Arch" : "HVM64" }, "m2.4xlarge" : { "Arch" : "HVM64" }, "m3.medium" : { "Arch" : "HVM64" }, "m3.large" : { "Arch" : "HVM64" }, "m3.xlarge" : { "Arch" : "HVM64" }, "m3.2xlarge" : { "Arch" : "HVM64" }, "m4.large" : { "Arch" : "HVM64" }, "m4.xlarge" : { "Arch" : "HVM64" }, "m4.2xlarge" : { "Arch" : "HVM64" }, "m4.4xlarge" : { "Arch" : "HVM64" }, "m4.10xlarge" : { "Arch" : "HVM64" }, "c1.medium" : { "Arch" : "HVM64" }, "c1.xlarge" : { "Arch" : "HVM64" }, "c3.large" : { "Arch" : "HVM64" }, "c3.xlarge" : { "Arch" : "HVM64" }, "c3.2xlarge" : { "Arch" : "HVM64" }, "c3.4xlarge" : { "Arch" : "HVM64" }, "c3.8xlarge" : { "Arch" : "HVM64" }, "c4.large" : { "Arch" : "HVM64" }, "c4.xlarge" : { "Arch" : "HVM64" }, "c4.2xlarge" : { "Arch" : "HVM64" }, "c4.4xlarge" : { "Arch" : "HVM64" }, "c4.8xlarge" : { "Arch" : "HVM64" }, "g2.2xlarge" : { "Arch" : "HVMG2" }, "g2.8xlarge" : { "Arch" : "HVMG2" }, "r3.large" : { "Arch" : "HVM64" }, "r3.xlarge" : { "Arch" : "HVM64" }, "r3.2xlarge" : { "Arch" : "HVM64" }, "r3.4xlarge" : { "Arch" : "HVM64" }, "r3.8xlarge" : { "Arch" : "HVM64" }, "i2.xlarge" : { "Arch" : "HVM64" }, "i2.2xlarge" : { "Arch" : "HVM64" }, "i2.4xlarge" : { "Arch" : "HVM64" }, "i2.8xlarge" : { "Arch" : "HVM64" }, "d2.xlarge" : { "Arch" : "HVM64" }, "d2.2xlarge" : { "Arch" : "HVM64" }, "d2.4xlarge" : { "Arch" : "HVM64" }, "d2.8xlarge" : { "Arch" : "HVM64" }, "hi1.4xlarge" : { "Arch" : "HVM64" }, "hs1.8xlarge" : { "Arch" : "HVM64" }, "cr1.8xlarge" : { "Arch" : "HVM64" }, "cc2.8xlarge" : { "Arch" : "HVM64" } }, "AWSRegionArch2AMI" : { "us-east-1" : {"HVM64" : "ami-0ff8a91507f77f867", "HVMG2" : "ami-0a584ac55a7631c0c"}, "us-west-2" : {"HVM64" : "ami-a0cfeed8", "HVMG2" : "ami-0e09505bc235aa82d"}, "us-west-1" : {"HVM64" : "ami-0bdb828fd58c52235", "HVMG2" : "ami-066ee5fd4a9ef77f1"}, "eu-west-1" : {"HVM64" : "ami-047bb4163c506cd98", "HVMG2" : "ami-0a7c483d527806435"}, "eu-west-2" : {"HVM64" : "ami-f976839e", "HVMG2" : "NOT_SUPPORTED"}, "eu-west-3" : {"HVM64" : "ami-0ebc281c20e89ba4b", "HVMG2" : "NOT_SUPPORTED"}, "eu-central-1" : {"HVM64" : "ami-0233214e13e500f77", "HVMG2" : "ami-06223d46a6d0661c7"}, "ap-northeast-1" : {"HVM64" : "ami-06cd52961ce9f0d85", "HVMG2" : "ami-053cdd503598e4a9d"}, "ap-northeast-2" : {"HVM64" : "ami-0a10b2721688ce9d2", "HVMG2" : "NOT_SUPPORTED"}, "ap-northeast-3" : {"HVM64" : "ami-0d98120a9fb693f07", "HVMG2" : "NOT_SUPPORTED"}, "ap-southeast-1" : {"HVM64" : "ami-08569b978cc4dfa10", "HVMG2" : "ami-0be9df32ae9f92309"}, "ap-southeast-2" : {"HVM64" : "ami-09b42976632b27e9b", "HVMG2" : "ami-0a9ce9fecc3d1daf8"}, "ap-south-1" : {"HVM64" : "ami-0912f71e06545ad88", "HVMG2" : "ami-097b15e89dbdcfcf4"}, "us-east-2" : {"HVM64" : "ami-0b59bfac6be064b78", "HVMG2" : "NOT_SUPPORTED"}, "ca-central-1" : {"HVM64" : "ami-0b18956f", "HVMG2" : "NOT_SUPPORTED"}, "sa-east-1" : {"HVM64" : "ami-07b14488da8ea02a0", "HVMG2" : "NOT_SUPPORTED"}, "cn-north-1" : {"HVM64" : "ami-0a4eaf6c4454eda75", "HVMG2" : "NOT_SUPPORTED"}, "cn-northwest-1" : {"HVM64" : "ami-6b6a7d09", "HVMG2" : "NOT_SUPPORTED"} } }, "Resources" : { "ElasticLoadBalancer" : { "Type" : "AWS::ElasticLoadBalancing::LoadBalancer", "Properties" : { "CrossZone" : "true", "AvailabilityZones" : { "Fn::GetAZs" : "" }, "LBCookieStickinessPolicy" : [ { "PolicyName" : "CookieBasedPolicy", "CookieExpirationPeriod" : "30" } ], "Listeners" : [ { "LoadBalancerPort" : "80", "InstancePort" : "80", "Protocol" : "HTTP", "PolicyNames" : [ "CookieBasedPolicy" ] } ], "HealthCheck" : { "Target" : "HTTP:80/", "HealthyThreshold" : "2", "UnhealthyThreshold" : "5", "Interval" : "10", "Timeout" : "5" } } }, "WebServerGroup" : { "Type" : "AWS::AutoScaling::AutoScalingGroup", "Properties" : { "AvailabilityZones" : { "Fn::GetAZs" : "" }, "LaunchConfigurationName" : { "Ref" : "LaunchConfig" }, "MinSize" : "1", "DesiredCapacity" : "1", "MaxSize" : "5", "LoadBalancerNames" : [ { "Ref" : "ElasticLoadBalancer" } ] }, "CreationPolicy" : { "ResourceSignal" : { "Timeout" : "PT15M" } }, "UpdatePolicy": { "AutoScalingRollingUpdate": { "MinInstancesInService": "1", "MaxBatchSize": "1", "PauseTime" : "PT15M", "WaitOnResourceSignals": "true" } } }, "LaunchConfig": { "Type" : "AWS::AutoScaling::LaunchConfiguration", "Metadata" : { "Comment" : "Install a simple PHP application", "AWS::CloudFormation::Init" : { "config" : { "packages" : { "yum" : { "httpd" : [], "php" : [] } }, "files" : { "/var/www/html/index.php" : { "content" : { "Fn::Join" : ["", [ "<?php\n", "echo '<h1>AWS CloudFormation sample PHP application</h1>';\n", "echo 'Updated version via UpdateStack';\n ", "?>\n" ]]}, "mode" : "000644", "owner" : "apache", "group" : "apache" }, "/etc/cfn/cfn-hup.conf" : { "content" : { "Fn::Join" : ["", [ "[main]\n", "stack=", { "Ref" : "AWS::StackId" }, "\n", "region=", { "Ref" : "AWS::Region" }, "\n" ]]}, "mode" : "000400", "owner" : "root", "group" : "root" }, "/etc/cfn/hooks.d/cfn-auto-reloader.conf" : { "content": { "Fn::Join" : ["", [ "[cfn-auto-reloader-hook]\n", "triggers=post.update\n", "path=Resources.LaunchConfig.Metadata.AWS::CloudFormation::Init\n", "action=/opt/aws/bin/cfn-init -s ", { "Ref" : "AWS::StackId" }, " -r LaunchConfig ", " --region ", { "Ref" : "AWS::Region" }, "\n", "runas=root\n" ]]} } }, "services" : { "sysvinit" : { "httpd" : { "enabled" : "true", "ensureRunning" : "true" }, "cfn-hup" : { "enabled" : "true", "ensureRunning" : "true", "files" : ["/etc/cfn/cfn-hup.conf", "/etc/cfn/hooks.d/cfn-auto-reloader.conf"]} } } } } }, "Properties": { "ImageId" : { "Fn::FindInMap" : [ "AWSRegionArch2AMI", { "Ref" : "AWS::Region" }, { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } ] }, "InstanceType" : { "Ref" : "InstanceType" }, "KeyName" : { "Ref" : "KeyName" }, "SecurityGroups" : [ {"Ref" : "WebServerSecurityGroup"} ], "UserData" : { "Fn::Base64" : { "Fn::Join" : ["", [ "#!/bin/bash -xe\n", "yum install -y aws-cfn-bootstrap\n", "# Install the files and packages from the metadata\n", "/opt/aws/bin/cfn-init -v ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource LaunchConfig ", " --region ", { "Ref" : "AWS::Region" }, "\n", "# Start up the cfn-hup daemon to listen for changes to the Web Server metadata\n", "/opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup'\n", "# Signal the status from cfn-init\n", "/opt/aws/bin/cfn-signal -e $? ", " --stack ", { "Ref" : "AWS::StackName" }, " --resource WebServerGroup ", " --region ", { "Ref" : "AWS::Region" }, "\n" ]]}} } }, "WebServerSecurityGroup" : { "Type" : "AWS::EC2::SecurityGroup", "Properties" : { "GroupDescription" : "Enable HTTP access via port 80 locked down to the ELB and SSH access", "SecurityGroupIngress" : [ {"IpProtocol" : "tcp", "FromPort" : "80", "ToPort" : "80", "SourceSecurityGroupOwnerId" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.OwnerAlias"]},"SourceSecurityGroupName" : {"Fn::GetAtt" : ["ElasticLoadBalancer", "SourceSecurityGroup.GroupName"]}}, {"IpProtocol" : "tcp", "FromPort" : "22", "ToPort" : "22", "CidrIp" : { "Ref" : "SSHLocation"}} ] } } }, "Outputs" : { "WebsiteURL" : { "Description" : "Application URL", "Value" : { "Fn::Join" : ["", ["http://", { "Fn::GetAtt" : [ "ElasticLoadBalancer", "DNSName" ]}]] } } } }

可用性和影响注意事项

不同的属性会对堆栈中的资源造成不同的影响。您可以使用 CloudFormation 更新任何属性,但是您应该在进行任何更改之前考虑以下问题:

  1. 更新会如何影响资源本身? 例如,更新警报阈值会使警报在更新期间处于非活动状态。正如我们所见,更改实例类型时需要停止和重启实例。Amazon CloudFormation 使用底层资源的 Update 或 Modify 操作来对资源进行更改。要了解更改的影响,您应该查看特定资源的文档。

  2. 更改可变还是不可变? 对资源属性的某些更改,如更改 Amazon EC2 实例上的 AMI,不受基础服务的支持。如果更改可变,CloudFormation 将使用适用于基础资源的“Update”或“Modify”类型 API。对于不可变的属性更改,CloudFormation 将用更新后的属性创建新资源,然后再删除旧资源之前将此资源链接至堆栈。虽然 CloudFormation 尝试减少堆栈资源的停机时间,但替代资源是一个多步骤过程,需要时间。重新配置堆栈期间,您的应用程序不能全面运行。例如,它可能不能为请求提供服务或访问数据库。

相关资源

有关使用 CloudFormation 启动应用程序的更多信息以及集成其他配置与 Puppet 和 Opscode Chef 等部署服务的更多信息,请参阅以下白皮书:

此部分使用的模板为“Hello World”PHP 应用程序。模板库中还有一个 Amazon ElastiCache 示例模板,该模板显示如何使用 cfn-hup 和 cfn-init 集成 PHP 应用程序和 ElasticCache,以响应 Amazon ElastiCache 缓存集群配置中的更改,这所有的操作都可通过更新堆栈执行。