本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
更新 CloudFormation 堆疊
注意
本教學課程以在 Amazon EC2 上部署應用程式教學課程中的概念為基礎。如果您尚未完成該教學課程,我們建議您先這麼做,以了解使用 CloudFormation 的 EC2 引導。
本主題示範對執行中堆疊的簡單更新進度。我們將逐步解說以下步驟:
-
建立初始堆疊 – 使用基本 Amazon Linux 2 AMI 建立堆疊,並使用 CloudFormation 協助程式指令碼安裝 Apache Web Server和簡單的 PHP 應用程式。
-
更新應用程式 – 更新應用程式中的其中一個檔案,並使用 CloudFormation 部署軟體。
-
新增金鑰對 – 將 Amazon EC2 金鑰對新增至執行個體,然後更新安全群組以允許 SSH 存取執行個體。
-
更新執行個體類型 – 變更基礎 Amazon EC2 執行個體的執行個體類型。
-
更新 AMI – 變更堆疊中 Amazon EC2 執行個體的 Amazon Machine Image (AMI)。
注意
CloudFormation 是免費的,但需要為您建立的 Amazon EC2 資源付費。不過,如果您是新手 AWS,則可以利用 免費方案
步驟 1:建立初始堆疊
首先,我們會建立堆疊,供本主題的其餘部分使用。我們提供了簡單的範本,可啟動在 上託管Apache Web Server並在 Amazon Linux 2 AMI 上執行的單一執行個體 PHP Web 應用程式。
Apache Web Server、PHP 和簡易 PHP 應用程式都是由預設安裝在 Amazon Linux 2 AMI 上的 CloudFormation 協助程式指令碼所安裝。下列範本程式碼片段顯示描述要安裝的套件和檔案的中繼資料,在此情況下,Amazon Linux 2 AMI 儲存Yum庫中的 Apache Web Server和 PHP 基礎設施。程式碼片段也會顯示 Services區段,這可確保 Apache Web Server 正在執行 。
WebServerInstance: Type: AWS::EC2::Instance Metadata: AWS::CloudFormation::Init: config: packages: yum: httpd: [] php: [] files: /var/www/html/index.php: content: | <?php echo '<h1>Hello World!</h1>'; ?> mode: '000644' owner: apache group: apache services: systemd: httpd: enabled: true ensureRunning: true
應用程式本身是完全在範本中定義的「Hello World」範例。若是實際的應用程式,系統可能會將檔案存放在 Amazon S3、GitHub 或其他儲存庫上,並參考範本的內容。CloudFormation 能夠下載 RPM 或 RubyGems 等套件、參考個別檔案以及解壓縮 .zip 與 .tar 檔案,藉此在 Amazon EC2 執行個體上建立應用程式成品。
範本會啟用和設定cfn-hup協助程式,以接聽 Amazon EC2 執行個體中繼資料中定義的組態變更。透過使用 cfn-hup 協助程式,您可以更新應用程式軟體,例如 Apache 或 PHP 的版本,也可以從 CloudFormation 更新 PHP 應用程式檔案本身。範本中相同 Amazon EC2 資源的下列程式碼片段顯示設定 cfn-init每兩分鐘cfn-hup呼叫 以通知中繼資料並套用更新所需的片段。否則, cfn-init只會在啟動時執行一次。
files: /etc/cfn/cfn-hup.conf: content: !Sub | [main] stack=${AWS::StackId} region=${AWS::Region} # The interval used to check for changes to the resource metadata in minutes. Default is 15 interval=2 mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Sub | [cfn-auto-reloader-hook] triggers=post.update path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region} runas=root services: systemd: cfn-hup: enabled: true ensureRunning: true files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.conf
為了完成堆疊,在 Amazon EC2 執行個體定義的 Properties區段中, UserData 屬性包含呼叫 cfn-init 來安裝套件和檔案的cloud-init指令碼。如需詳細資訊,請參閱《CloudFormation 範本參考指南》中的 CloudFormation 協助程式指令碼參考。範本也會建立 Amazon EC2 安全群組。
AWSTemplateFormatVersion: 2010-09-09 Parameters: LatestAmiId: Description: The latest Amazon Linux 2 AMI from the Parameter Store Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2' InstanceType: Description: WebServer EC2 instance type Type: String Default: t3.micro AllowedValues: - t3.nano - t3.micro - t3.small - t3.medium - t3a.nano - t3a.micro - t3a.small - t3a.medium - m5.large - m5.xlarge - m5.2xlarge - m5a.large - m5a.xlarge - m5a.2xlarge - c5.large - c5.xlarge - c5.2xlarge - r5.large - r5.xlarge - r5.2xlarge - r5a.large - r5a.xlarge - r5a.2xlarge ConstraintDescription: must be a valid EC2 instance type. Resources: WebServerInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref LatestAmiId InstanceType: !Ref InstanceType SecurityGroupIds: - !Ref WebServerSecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash -xe # Get the latest CloudFormation package yum update -y aws-cfn-bootstrap # Run cfn-init /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} || error_exit 'Failed to run cfn-init' # Start up the cfn-hup daemon to listen for changes to the EC2 instance metadata /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup' # Signal success or failure /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} Metadata: AWS::CloudFormation::Init: config: packages: yum: httpd: [] php: [] files: /var/www/html/index.php: content: | <?php echo "<h1>Hello World!</h1>"; ?> mode: '000644' owner: apache group: apache /etc/cfn/cfn-hup.conf: content: !Sub | [main] stack=${AWS::StackId} region=${AWS::Region} # The interval used to check for changes to the resource metadata in minutes. Default is 15 interval=2 mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Sub | [cfn-auto-reloader-hook] triggers=post.update path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region} runas=root services: systemd: 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 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: Value: !Sub 'http://${WebServerInstance.PublicDnsName}' Description: URL of the web application
從此範本啟動堆疊
-
複製範本,並將其儲存為文字檔案於本機系統。請記下檔案位置,因為後續步驟仍需使用到該檔案。
-
登入 AWS 管理主控台 ,並在 https://https://console.aws.amazon.com/cloudformation
開啟 CloudFormation 主控台。 -
選擇使用新資源建立堆疊 (標準)。
-
選擇選擇現有的範本。
-
在指定範本下,選擇上傳範本檔案,瀏覽至您在第一個步驟中建立的檔案,然後選擇下一步。
-
在指定堆疊詳細資訊頁面上,輸入
UpdateTutorial做為堆疊名稱。 -
在參數下,保持所有參數相同,然後選擇下一步兩次。
-
在檢閱和建立畫面上,選擇提交。
堆疊的狀態為 之後CREATE_COMPLETE,輸出索引標籤會顯示您網站的 URL。如果您選擇WebsiteURL輸出的值,您會看到新的 PHP 應用程式正在運作。
步驟 2:更新應用程式
既然我們已經將堆疊部署完成,接下來便要更新應用程式。我們會簡單地更改應用程式所印出的文字。若要執行此作業,便需要將 echo 命令新增至 index.php 檔案,如下列範本程式碼片段所示:
files: /var/www/html/index.php: content: | <?php echo "<h1>Hello World!</h1>";echo "<p>This is an updated version of our application.</p>";?> mode: '000644' owner: apache group: apache
透過文字編輯器,即可手動編輯儲存在本機上的範本檔案。
現在,請更新堆疊。
使用已更新的範本更新堆疊
-
在 CloudFormation 主控台中,選取您的
UpdateTutorial堆疊。 -
選擇更新,直接更新。
-
選擇取代現有範本。
-
在指定範本下,選擇上傳範本檔案並上傳修改後的範本檔案,然後選擇下一步。
-
在指定堆疊詳細資訊頁面上,保持所有參數相同,然後選擇下一步兩次。
-
在檢閱頁面上,檢閱變更。在變更下,您應該會看到 CloudFormation 會更新
WebServerInstance資源。 -
選擇提交。
當您的堆疊處於 UPDATE_COMPLETE 狀態時,您可以再次選擇WebsiteURL輸出值,以確認應用程式的變更已生效。根據預設,cfn-hup協助程式每 2 分鐘執行一次,因此更新堆疊後,應用程式最多可能需要 2 分鐘才能變更。
前往 CloudFormation 主控台,即可查看更新後的資源集。您可以在 Events (事件) 標籤上檢視堆疊事件。在此特定情況下,Amazon EC2 執行個體的中繼資料WebServerInstance已更新,這會導致 CloudFormation 也重新評估其他資源 (WebServerSecurityGroup),以確保沒有其他變更。系統並不會修改其他堆疊資源。唯有堆疊中的資源受到任何堆疊變更影響時,CloudFormation 才會更新這些資源。這類變更可以是直接的,例如屬性或中繼資料變更,也可能是由於相依性或透過 Ref、 GetAtt或其他內部範本函數的資料流程所造成。如需詳細資訊,請參閱內建函數參考。
這個簡單的更新說明了程序。不過,您可以對部署到 Amazon EC2 執行個體的檔案和套件進行更複雜的變更。例如,您可能會認為需要將 MySQL 與 MySQL 的 PHP 支援新增至執行個體。若要執行此作業,只需將其他套件、檔案與任何其他服務一併新增至組態,接著更新堆疊,即可部署變更。
packages: yum: httpd: [] php: []mysql: []php-mysql: []mysql-server: []mysql-libs: []...services: systemd: httpd: enabled: true ensureRunning: true cfn-hup: enabled: true ensureRunning: true files: - /etc/cfn/cfn-hup.conf - /etc/cfn/hooks.d/cfn-auto-reloader.confmysqld:enabled: trueensureRunning: true
您可以更新 CloudFormation 中繼資料,藉此將應用程式所使用的套件更新至新版本。在上述範例中,每個套件的版本屬性都是空的,表示 cfn-init應該安裝最新版本的套件。
packages: yum: httpd: [] php: []
您可以選擇指定套件的版本字串;若您在後續的更新堆疊呼叫中更改該版本字串,則系統將部署新版本的套件。下方為使用 RubyGems 套件版本編號的範例。而支援版本控制的任何套件皆可擁有特定版本。
packages: rubygems: mysql: [] rubygems-update: - "1.6.2" rake: - "0.8.7" rails: - "2.3.11"
步驟 3:使用金鑰對新增 SSH 存取
您也可以更新範本中的資源,以新增最初未在範本中指定的屬性。為了說明這一點,我們會將 Amazon EC2 金鑰對新增至現有的 EC2 執行個體,然後在 Amazon EC2 安全群組中開啟連接埠 22,以便您可以使用 Secure Shell (SSH) 存取執行個體。
在現有的 Amazon EC2 執行個體中新增 SSH 存取
-
將兩個額外參數新增至範本,藉此傳遞現有的 Amazon EC2 金鑰對名稱與 SSH 位置。
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 that can be used to SSH to the EC2 instances in CIDR format (e.g. 203.0.113.1/32) Type: String MinLength: 9 MaxLength: 18 Default: 0.0.0.0/0 AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$' ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. -
將
KeyName屬性新增至 Amazon EC2 執行個體。WebServerInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref LatestAmiId InstanceType: !Ref InstanceType KeyName: !Ref KeyName SecurityGroupIds: - !Ref WebServerSecurityGroup -
將連接埠 22 與 SSH 位置新增至 Amazon EC2 安全群組的輸入規則。
WebServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable HTTP access via port 80 and SSH access via port 22 SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: !Ref SSHLocation -
使用與 中說明的相同步驟來更新堆疊步驟 2:更新應用程式。
步驟 4:更新執行個體類型
現在,讓我們示範如何透過變更執行個體類型來更新基礎基礎設施。
到目前為止,我們建置的堆疊使用 t3.micro Amazon EC2 執行個體。假設您新建立的網站流量超過 t3.micro 執行個體可以處理的流量,現在您想要移至 m5.large Amazon EC2 執行個體類型。如果執行個體類型的架構變更,則必須使用不同的 AMI 建立執行個體。不過,t3.micro 和 m5.large 都使用相同的 CPU 架構,並執行 Amazon Linux 2 (x86_64) AMIs。如需詳細資訊,請參閱《Amazon EC2 使用者指南》中的變更執行個體類型的相容性。
讓我們使用我們在上一個步驟中修改的範本來變更執行個體類型。由於 InstanceType 是範本的輸入參數,因此我們不需要修改範本;我們可以在指定堆疊詳細資訊頁面上變更 參數的值。
使用新的參數值更新堆疊
-
在 CloudFormation 主控台中,選取您的
UpdateTutorial堆疊。 -
選擇更新、直接更新。
-
選擇使用現有範本,然後選擇下一步。
-
在指定堆疊詳細資訊頁面上,將 InstanceType 文字方塊的值從
t3.micro變更為m5.large。然後,選擇下一步兩次。 -
在檢閱頁面上,檢閱變更。在變更下,您應該會看到 CloudFormation 會更新
WebServerInstance資源。 -
選擇提交。
透過啟動和停用執行個體,即可動態變更 EBS 後端 Amazon EC2 執行個體的執行個體類型。CloudFormation 會更新執行個體類型並重新啟動該執行個體,藉此嘗試將變更內容最佳化,讓執行個體 ID 不會因而改變。然而,重新啟動執行個體時,該執行個體的公有 IP 地址會隨之變更。為了確保彈性 IP 位址在變更後仍能正確繫結,CloudFormation 將一併更新彈性 IP 地址。您可以在 CloudFormation CloudFormation 主控台的事件索引標籤上查看變更。
若要從 檢查執行個體類型 AWS 管理主控台,請開啟 Amazon EC2 主控台,並在該處找到您的執行個體。
步驟 5:更新 AMI
現在,讓我們更新堆疊以使用 Amazon Linux 2023,這是新一代的 Amazon Linux。
更新 AMI 是一項需要取代執行個體的主要變更。我們不能只啟動和停止執行個體來修改 AMI;CloudFormation 會將此視為對資源不可變屬性的變更。CloudFormation 必須啟動替代資源,才能更改不可變屬性;此處將以新的 Amazon EC2 執行個體執行新的 AMI 為例。
我們來看看如何更新堆疊範本以使用 Amazon Linux 2023。關鍵變更包括更新 AMI 參數,以及從 yum 變更為dnf套件管理員。
AWSTemplateFormatVersion: 2010-09-09 Parameters: LatestAmiId: Description: The latest Amazon Linux 2023 AMI from the Parameter Store Type: AWS::SSM::Parameter::Value<AWS::EC2::Image::Id> Default: '/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64' InstanceType: Description: WebServer EC2 instance type Type: String Default: t3.micro AllowedValues: - t3.nano - t3.micro - t3.small - t3.medium - t3a.nano - t3a.micro - t3a.small - t3a.medium - m5.large - m5.xlarge - m5.2xlarge - m5a.large - m5a.xlarge - m5a.2xlarge - c5.large - c5.xlarge - c5.2xlarge - r5.large - r5.xlarge - r5.2xlarge - r5a.large - r5a.xlarge - r5a.2xlarge ConstraintDescription: must be a valid EC2 instance type. 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 that can be used to SSH to the EC2 instances in CIDR format (e.g. 203.0.113.1/32) Type: String MinLength: 9 MaxLength: 18 Default: 0.0.0.0/0 AllowedPattern: '^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$' ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x. Resources: WebServerInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref LatestAmiId InstanceType: !Ref InstanceType KeyName: !Ref KeyName SecurityGroupIds: - !Ref WebServerSecurityGroup UserData: Fn::Base64: !Sub | #!/bin/bash -xe # Get the latest CloudFormation package dnf update -y aws-cfn-bootstrap # Run cfn-init /opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} || error_exit 'Failed to run cfn-init' # Start up the cfn-hup daemon to listen for changes to the EC2 instance metadata /opt/aws/bin/cfn-hup || error_exit 'Failed to start cfn-hup' # Signal success or failure /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource WebServerInstance --region ${AWS::Region} Metadata: AWS::CloudFormation::Init: config: packages: dnf: httpd: [] php: [] files: /var/www/html/index.php: content: | <?php echo "<h1>Hello World!</h1>"; echo "<p>This is an updated version of our application.</p>"; echo "<p>Running on Amazon Linux 2023!</p>"; ?> mode: '000644' owner: apache group: apache /etc/cfn/cfn-hup.conf: content: !Sub | [main] stack=${AWS::StackId} region=${AWS::Region} # The interval used to check for changes to the resource metadata in minutes. Default is 15 interval=2 mode: '000400' owner: root group: root /etc/cfn/hooks.d/cfn-auto-reloader.conf: content: !Sub | [cfn-auto-reloader-hook] triggers=post.update path=Resources.WebServerInstance.Metadata.AWS::CloudFormation::Init action=/opt/aws/bin/cfn-init -s ${AWS::StackId} -r WebServerInstance --region ${AWS::Region} runas=root services: systemd: 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 CreationPolicy: ResourceSignal: Timeout: PT5M WebServerSecurityGroup: Type: AWS::EC2::SecurityGroup Properties: GroupDescription: Enable HTTP access via port 80 and SSH access via port 22 SecurityGroupIngress: - IpProtocol: tcp FromPort: 80 ToPort: 80 CidrIp: 0.0.0.0/0 - IpProtocol: tcp FromPort: 22 ToPort: 22 CidrIp: !Ref SSHLocation Outputs: WebsiteURL: Value: !Sub 'http://${WebServerInstance.PublicDnsName}' Description: URL of the web application
使用與 中說明的相同步驟來更新堆疊步驟 2:更新應用程式。
新的執行個體開始運作後,CloudFormation 即會更新堆疊中的其他資源,進而指向新資源。系統會進行稱為 UPDATE_CLEANUP 的程序,藉此建立新資源、刪除舊資源。此時,堆疊中執行個體的執行個體 ID 與應用程式 URL,皆會因更新作業而有所變更。事件資料表中的事件包含描述「請求的更新已變更不可變屬性,因此建立新的實體資源」,以指出資源已取代。
或者:如果您將應用程式碼寫入您要更新的 AMI,您可以使用相同的堆疊更新機制來更新 AMI 以載入新的應用程式。
使用自訂應用程式碼更新 AMI
-
建立包含應用程式或作業系統變更的新 AMI。如需詳細資訊,請參閱《Amazon EC2 使用者指南》中的建立 Amazon EBS 後端 AMI。 Amazon EC2
-
更新您的範本以納入新的 AMI ID。
-
使用與 中說明的相同步驟來更新堆疊步驟 2:更新應用程式。
更新堆疊時,CloudFormation 即會偵測到 AMI ID 有所變更,然後啟動堆疊更新作業 (與上述更新的觸發方式相同)。
可用性與影響考量事項
不同屬性會對堆疊中的資源造成不同影響。您可以善用 CloudFormation 來更新任何屬性;但進行任何變更之前,應考量下列問題:
-
更新作業對資源本身有何影響? 舉例來說,更新警示閾值會導致警示在更新期間處於非作用中狀態。正如我們在本章所見,您需要停用並重新啟動執行個體,才能變更執行個體類型。CloudFormation 會透過基礎資源的更新或修改動作來更改資源。如需了解更新造成的影響,請查閱特定資源的文件。
-
更改內容屬於可變或不可變項目? 基礎服務並不支援部分資源屬性變更操作,例如:更改 Amazon EC2 執行個體上的 AMI。如果更改內容屬於可變項目,CloudFormation 將針對基礎資源使用 Update (更新) 或 Modify (修改) 類型的 API。如果屬性更改屬於不可變項目,則 CloudFormation 會使用更新後的屬性來建立新資源,並將這些資源連結至堆疊,接著刪除舊資源。雖然 CloudFormation 會嘗試縮短堆疊資源的停機時間,但替換資源屬於多步驟程序,需要一些時間才能完成。重新設定堆疊期間,應用程式將無法完全正常運作。例如,應用程式可能無法處理請求或存取資料庫;
相關資源
如需使用 CloudFormation 啟動應用程式以及與其他組態和部署服務整合的詳細資訊,例如 Puppet和 Opscode Chef,請參閱下列白皮書: