更新 CloudFormation 堆疊 - AWS CloudFormation

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

更新 CloudFormation 堆疊

注意

本教學課程以在 Amazon EC2 上部署應用程式教學課程中的概念為基礎。如果您尚未完成該教學課程,我們建議您先這麼做,以了解使用 CloudFormation 的 EC2 引導。

本主題示範對執行中堆疊的簡單更新進度。我們將逐步解說以下步驟:

  1. 建立初始堆疊 – 使用基本 Amazon Linux 2 AMI 建立堆疊,並使用 CloudFormation 協助程式指令碼安裝 Apache Web Server和簡單的 PHP 應用程式。

  2. 更新應用程式 – 更新應用程式中的其中一個檔案,並使用 CloudFormation 部署軟體。

  3. 新增金鑰對 – 將 Amazon EC2 金鑰對新增至執行個體,然後更新安全群組以允許 SSH 存取執行個體。

  4. 更新執行個體類型 – 變更基礎 Amazon EC2 執行個體的執行個體類型。

  5. 更新 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
從此範本啟動堆疊
  1. 複製範本,並將其儲存為文字檔案於本機系統。請記下檔案位置,因為後續步驟仍需使用到該檔案。

  2. 登入 AWS 管理主控台 ,並在 https://https://console.aws.amazon.com/cloudformation 開啟 CloudFormation 主控台。

  3. 選擇使用新資源建立堆疊 (標準)

  4. 選擇選擇現有的範本

  5. 指定範本下,選擇上傳範本檔案,瀏覽至您在第一個步驟中建立的檔案,然後選擇下一步

  6. 指定堆疊詳細資訊頁面上,輸入 UpdateTutorial做為堆疊名稱。

  7. 參數下,保持所有參數相同,然後選擇下一步兩次。

  8. 檢閱和建立畫面上,選擇提交

堆疊的狀態為 之後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

透過文字編輯器,即可手動編輯儲存在本機上的範本檔案。

現在,請更新堆疊。

使用已更新的範本更新堆疊
  1. 在 CloudFormation 主控台中,選取您的UpdateTutorial堆疊。

  2. 選擇更新,直接更新

  3. 選擇取代現有範本

  4. 指定範本下,選擇上傳範本檔案並上傳修改後的範本檔案,然後選擇下一步

  5. 指定堆疊詳細資訊頁面上,保持所有參數相同,然後選擇下一步兩次。

  6. 檢閱頁面上,檢閱變更。在變更下,您應該會看到 CloudFormation 會更新WebServerInstance資源。

  7. 選擇提交

當您的堆疊處於 UPDATE_COMPLETE 狀態時,您可以再次選擇WebsiteURL輸出值,以確認應用程式的變更已生效。根據預設,cfn-hup協助程式每 2 分鐘執行一次,因此更新堆疊後,應用程式最多可能需要 2 分鐘才能變更。

前往 CloudFormation 主控台,即可查看更新後的資源集。您可以在 Events (事件) 標籤上檢視堆疊事件。在此特定情況下,Amazon EC2 執行個體的中繼資料WebServerInstance已更新,這會導致 CloudFormation 也重新評估其他資源 (WebServerSecurityGroup),以確保沒有其他變更。系統並不會修改其他堆疊資源。唯有堆疊中的資源受到任何堆疊變更影響時,CloudFormation 才會更新這些資源。這類變更可以是直接的,例如屬性或中繼資料變更,也可能是由於相依性或透過 RefGetAtt或其他內部範本函數的資料流程所造成。如需詳細資訊,請參閱內建函數參考

這個簡單的更新說明了程序。不過,您可以對部署到 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.conf mysqld: enabled: true ensureRunning: 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 存取
  1. 將兩個額外參數新增至範本,藉此傳遞現有的 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.
  2. KeyName 屬性新增至 Amazon EC2 執行個體。

    WebServerInstance: Type: AWS::EC2::Instance Properties: ImageId: !Ref LatestAmiId InstanceType: !Ref InstanceType KeyName: !Ref KeyName SecurityGroupIds: - !Ref WebServerSecurityGroup
  3. 將連接埠 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
  4. 使用與 中說明的相同步驟來更新堆疊步驟 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 是範本的輸入參數,因此我們不需要修改範本;我們可以在指定堆疊詳細資訊頁面上變更 參數的值。

使用新的參數值更新堆疊
  1. 在 CloudFormation 主控台中,選取您的UpdateTutorial堆疊。

  2. 選擇更新、直接更新

  3. 選擇使用現有範本,然後選擇下一步

  4. 指定堆疊詳細資訊頁面上,將 InstanceType 文字方塊的值從 t3.micro變更為 m5.large。然後,選擇下一步兩次。

  5. 檢閱頁面上,檢閱變更。在變更下,您應該會看到 CloudFormation 會更新WebServerInstance資源。

  6. 選擇提交

透過啟動和停用執行個體,即可動態變更 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
  1. 建立包含應用程式或作業系統變更的新 AMI。如需詳細資訊,請參閱《Amazon EC2 使用者指南》中的建立 Amazon EBS 後端 AMIAmazon EC2

  2. 更新您的範本以納入新的 AMI ID。

  3. 使用與 中說明的相同步驟來更新堆疊步驟 2:更新應用程式

更新堆疊時,CloudFormation 即會偵測到 AMI ID 有所變更,然後啟動堆疊更新作業 (與上述更新的觸發方式相同)。

可用性與影響考量事項

不同屬性會對堆疊中的資源造成不同影響。您可以善用 CloudFormation 來更新任何屬性;但進行任何變更之前,應考量下列問題:

  1. 更新作業對資源本身有何影響? 舉例來說,更新警示閾值會導致警示在更新期間處於非作用中狀態。正如我們在本章所見,您需要停用並重新啟動執行個體,才能變更執行個體類型。CloudFormation 會透過基礎資源的更新或修改動作來更改資源。如需了解更新造成的影響,請查閱特定資源的文件。

  2. 更改內容屬於可變或不可變項目? 基礎服務並不支援部分資源屬性變更操作,例如:更改 Amazon EC2 執行個體上的 AMI。如果更改內容屬於可變項目,CloudFormation 將針對基礎資源使用 Update (更新) 或 Modify (修改) 類型的 API。如果屬性更改屬於不可變項目,則 CloudFormation 會使用更新後的屬性來建立新資源,並將這些資源連結至堆疊,接著刪除舊資源。雖然 CloudFormation 會嘗試縮短堆疊資源的停機時間,但替換資源屬於多步驟程序,需要一些時間才能完成。重新設定堆疊期間,應用程式將無法完全正常運作。例如,應用程式可能無法處理請求或存取資料庫;

相關資源

如需使用 CloudFormation 啟動應用程式以及與其他組態和部署服務整合的詳細資訊,例如 Puppet和 Opscode Chef,請參閱下列白皮書: