逐步解說:使用 Lambda 支援的自訂資源查詢 AMI IDs - AWS CloudFormation

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

逐步解說:使用 Lambda 支援的自訂資源查詢 AMI IDs

本逐步解說說明如何使用 Lambda 和自訂資源,在 CloudFormation 範本中動態查詢 Amazon Machine Image (AMI) IDs。這可協助您簡化 CloudFormation 範本中 AMI IDs的更新方式。

當您建立 CloudFormation 範本以啟動 Amazon EC2 執行個體時,您必須指定 AMI ID,這與將安裝在執行個體上的作業系統和軟體的範本類似。正確的 AMI ID 取決於執行個體類型,而 AWS 區域 您要在其中啟動執行個體。這些 IDs可能會定期變更,例如 AMI 更新軟體更新的時間。

您通常會在將 AMI ID 映射至特定執行個體類型和區域的Mappings區段中指定 AMI IDs。這表示若要更新 IDs,您必須在每個範本中手動變更 ID。不過,透過使用自訂資源和 Lambda,您可以建立一個函數,取得您正在使用的執行個體類型和區域的最新 AMIs IDs。如此一來,您就不必在堆疊範本中手動維護 AMI IDs、執行個體類型和區域之間的映射。

本演練會說明如何建立自訂資源,並將該資源與 Lambda 函數建立關聯,以便查詢 AMI ID。它假設您熟悉自訂資源和 Lambda 函數。如需自訂資源及其運作方式的簡介,請參閱使用自訂資源建立自訂佈建邏輯。如需 Lambda 的相關資訊,請參閱 AWS Lambda 開發人員指南

注意

CloudFormation 是一項免費服務;不過,您需要支付資源的費用,例如 Lambda 函數和 EC2 執行個體,這些 AWS 資源是以每個資源的目前費率包含在堆疊中。如需 AWS 定價的詳細資訊,請參閱 https://http://aws.amazon.com 中每個產品的詳細資訊頁面。

除了建立自訂資源和 Lambda 函數之外,您也可以使用 AWS Systems Manager 範本中的參數來擷取存放在 Systems Manager 參數中的最新 AMI ID 值。這可讓您的範本更可重複使用且更易於維護。如需詳細資訊,請參閱使用 CloudFormation 提供的參數類型在執行時間指定現有的資源

概觀

下列步驟提供此實作的概觀。

  1. 將包含 Lambda 函數程式碼的範例套件儲存至您要建立 EC2 執行個體 AWS 區域 的相同 Amazon S3 儲存貯體。

  2. 使用範例範本,透過自訂資源、Lambda 函數、EC2 執行個體和 IAM 角色建立堆疊,Lambda 會使用這些角色來呼叫 Amazon EC2。

  3. 堆疊會將 Lambda 函數與自訂資源建立關聯。建立堆疊時,CloudFormation 會叫用函數並傳送資訊,例如請求類型、輸入資料和預先簽章的 Amazon S3 URL。

  4. Lambda 函數會使用輸入資料來查詢最新的 AMI ID,並將 AMI ID 做為回應傳送至預先簽章的 URL。

  5. CloudFormation 在預先簽章的 URL 位置取得回應,並繼續建立堆疊。CloudFormation 建立執行個體時,會使用 Lambda 函數提供的 AMI ID 來建立具有最新 AMI 的 EC2 執行個體。

範本演練

如需檢視整個範例範本,請參閱:

以下程式碼片段將說明範例範本的相關部分,協助您了解如何建立 Lambda 函數與自訂資源間的關聯,亦可掌握函數回應的使用方法。

AWS::Lambda::Function 資源 AMIInfoFunction

AWS::Lambda::Function 資源會指定函數的原始程式碼、處理常式名稱、執行時間環境和執行角色 Amazon Resource Name (ARN)。

  • Code 屬性會指定儲存範例套件的 Amazon S3 位置 (儲存貯體名稱和檔案名稱)。為了讓您可以在建立堆疊時指定名稱,範例範本會使用 "Ref": "S3Bucket""Ref": "S3Key" 這兩個輸入參數來設定儲存貯體及檔案的名稱。同樣地,與 .zip 套件中來源檔案 (JavaScript 檔案) 名稱相對應的處理常式名稱亦會採用 "Ref": "ModuleName" 輸入參數。來源檔案是由 JavaScript 程式碼編寫而成,因此系統會將執行時間指定為 nodejs18.x

  • 對於此演練中使用的程式碼,函數的執行時間超過預設值 3 秒,因此逾時設定為 30 秒。若您指定的逾時期間不夠長,則 Lambda 可能會在函數完成前發生逾時,導致堆疊建立失敗。

  • Role 屬性會使用 Fn::GetAtt函數來取得範本中其他位置宣告之LambdaExecutionRole執行角色的 ARN。

JSON

"AMIInfoFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Ref": "S3Bucket" }, "S3Key": { "Ref": "S3Key" } }, "Handler": { "Fn::Join" : [ "", [{ "Ref": "ModuleName" },".handler"] ] }, "Runtime": "nodejs18.x", "Timeout": "30", "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] } } }

YAML

AMIInfoFunction: Type: AWS::Lambda::Function Properties: Code: S3Bucket: !Ref S3Bucket S3Key: !Ref S3Key Handler: !Sub "${ModuleName}.handler" Runtime: nodejs18.x Timeout: 30 Role: !GetAtt LambdaExecutionRole.Arn

AWS::IAM::Role 資源 LambdaExecutionRole

執行角色會授予 Lambda 函數許可,以將日誌傳送至 AWS 和呼叫 EC2 DescribeImages API。

JSON

"LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["lambda.amazonaws.com"]}, "Action": ["sts:AssumeRole"] }] }, "Path": "/", "Policies": [{ "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"], "Resource": "arn:aws:logs:*:*:*" }, { "Effect": "Allow", "Action": ["ec2:DescribeImages"], "Resource": "*" }] } }] } }

YAML

LambdaExecutionRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - sts:AssumeRole Path: "/" Policies: - PolicyName: root PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: arn:aws:logs:*:*:* - Effect: Allow Action: - ec2:DescribeImages Resource: "*"

自訂::AMIInfo 資源 AMIInfo

對於 Linux 和 Windows 範本,自訂資源會叫用與其相關聯的 Lambda 函數。若要將函數與自訂資源建立關聯,您可以使用Fn::GetAtt內部函數為 ServiceToken 屬性指定函數的 ARN。CloudFormation 會將自訂資源宣告中包含的其他屬性,例如 RegionArchitecture,以輸入形式傳送至 Lambda 函數。Lambda 函數則負責判斷這些輸入屬性的正確名稱與數值。

JSON

"AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "ServiceToken": { "Fn::GetAtt" : ["AMIInfoFunction", "Arn"] }, "Region": { "Ref": "AWS::Region" }, "Architecture": { "Fn::FindInMap" : [ "AWSInstanceType2Arch", { "Ref" : "InstanceType" }, "Arch" ] } } }

YAML

AMIInfo: Type: Custom::AMIInfo Properties: ServiceToken: !GetAtt AMIInfoFunction.Arn Region: !Ref "AWS::Region" Architecture: Fn::FindInMap: - AWSInstanceType2Arch - !Ref InstanceType - Arch

在 Windows 作業系統中,自訂資源會提供 Windows 版本給 Lambda 函數,而非執行個體的架構。

JSON

"AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "ServiceToken": { "Fn::GetAtt": ["AMIInfoFunction", "Arn"] }, "Region": { "Ref": "AWS::Region" }, "OSName": { "Ref": "WindowsVersion" } } }

YAML

AMIInfo: Type: Custom::AMIInfo Properties: ServiceToken: !GetAtt AMIInfoFunction.Arn Region: !Ref "AWS::Region" OSName: !Ref "WindowsVersion"

當 CloudFormation 調用 Lambda 函數時,該函數會使用 AWS 區域 和 執行個體架構或作業系統名稱來篩選映像清單,以呼叫 EC2 DescribeImages API。接著,函數將按日期排序該影像清單,並傳回最新的 AMI ID。

在回傳最新的 AMI ID 期間,該函數會在回應物件Data 屬性中,將 ID 傳送至預先簽章的 URL。資料的結構為名稱/值組,如以下範例所示:

"Data": { "Id": "ami-02354e95b3example" }

AWS::EC2::Instance 資源 SampleInstance

以下程式碼片段會說明從 Lambda 函數取得資料的方法,其會透過 Fn::GetAtt 內部函數,進而提供欲獲取的自訂資源名稱與數值屬性名稱。在本演練中,自訂資源名稱為 AMIInfo,屬性名稱則為 Id

JSON

"SampleInstance": { "Type": "AWS::EC2::Instance", "Properties": { "InstanceType" : { "Ref": "InstanceType" }, "ImageId": { "Fn::GetAtt": [ "AMIInfo", "Id" ] } } }

YAML

SampleInstance: Type: AWS::EC2::Instance Properties: InstanceType: !Ref InstanceType ImageId: !GetAtt AMIInfo.Id

先決條件

您必須先擁有 Amazon S3 儲存貯體,才能完成建立堆疊的步驟。當您使用 Lambda 函數建立堆疊時,必須指定包含函數原始程式碼的 Amazon S3 儲存貯體位置。儲存貯體必須 AWS 區域 與您建立堆疊所在的儲存貯體相同。如需有關建立儲存貯體的詳細資訊,請參閱《Amazon Simple Storage Service 使用者指南》中的建立儲存貯體

您還必須擁有 IAM 許可才能使用所有對應的服務,例如 Lambda、Amazon EC2 和 CloudFormation。

步驟 1:將範例 Lambda 套件儲存至 Amazon S3

在此步驟中,您將範例 Lambda 套件 (.zip檔案) 上傳至 Amazon S3 儲存貯體。

此套件包含 Lambda 函數的原始碼和必要的程式庫。在本演練中,函數並不需使用額外的程式庫。

在 Amazon S3 中儲存範例套件
  1. 從 Amazon S3 下載範例套件。儲存檔案時,請務必使用與範例相同的檔案名稱,例如 amilookup.zipamilookup-win.zip

  2. 前往 https://console.aws.amazon.com/s3/home,開啟 Amazon S3 主控台。

  3. 在畫面頂端的導覽列上,選擇您在 AWS 區域 其中建立 Amazon S3 儲存貯體的 。

  4. 儲存貯體清單中,選擇儲存貯體的名稱。請記下儲存貯體名稱,因為您在建立堆疊時使用它。

  5. 選擇上傳

  6. 上傳下,對於檔案和資料夾 ,將範例套件上傳到儲存貯體。如需詳細資訊,請參閱 Amazon Simple Storage Service 使用者指南中的上傳物件

步驟 2:啟動堆疊

在此步驟中,您會從範例範本啟動堆疊。堆疊包含 Lambda 函數、IAM 角色 (執行角色)、叫用函數的自訂資源,以及使用函數結果的 EC2 執行個體。

堆疊建立期間,自訂資源會呼叫 Lambda 函數,並等候該函數將回應傳送至預先簽章的 Amazon S3 URL。在回應中, 函數會傳回對應至 EC2 執行個體類型的最新 AMI ID,而 AWS 區域 您要在其中建立執行個體。系統會將該函數回應中的資料存放為自訂資源的屬性,藉此指定 EC2 執行個體的 AMI ID。

建立堆疊
  1. 開啟位在 https://console.aws.amazon.com/cloudformation/ 的 CloudFormation​ 主控台。

  2. 堆疊頁面,選擇右上角的建立堆疊,然後選擇使用新資源 (標準)

  3. 針對先決條件 - 準備範本,選擇選擇現有範本

  4. 針對指定範本,選擇 Amazon S3 URL,然後在 Amazon S3 URL 欄位中複製並貼上下列 URL

    Linux 範本

    https://s3.amazonaws.com/cloudformation-examples/lambda/LambdaAMILookupSample.template

    Windows 範本

    https://s3.amazonaws.com/cloudformation-examples/lambda/LambdaAMILookupSample-win.template

  5. 選擇 Next (下一步)

  6. Stack Name (堆疊名稱) 中輸入 SampleEC2Instance

  7. 針對 參數,指定您建立的 Amazon S3 儲存貯體名稱,然後選擇下一步

    其他參數的預設值會與範例 .zip 套件所使用的名稱相同。

  8. 在此逐步解說中,您不需要新增標籤或指定進階設定,因此請選擇 Next (下一步)

  9. 確認堆疊名稱和範本 URL 無誤,接著選擇 Create (建立)

CloudFormation 可能需要幾分鐘的時間來建立您的堆疊。若要監控進度,請檢視堆疊事件。如需詳細資訊,請參閱從 CloudFormation 主控台檢視堆疊資訊

若堆疊建立成功,則系統會一併建立堆疊中所有資源 (如 Lambda 函數、自訂資源與 EC2 執行個體)。您已成功透過 Lambda 函數及自訂資源指定 EC2 執行個體的 AMI ID,所以無需在此範本中建立並維護 AMI ID 的映射。

若要查看用於建立 EC2 執行個體的 AMI ID CloudFormation,請檢視堆疊輸出。

如果 Lambda 函數傳回錯誤,請在 CloudWatch Logs 主控台中檢視函數的日誌。日誌串流名稱即為自訂資源的實體 ID,您能夠檢視堆疊資源以查詢該名稱。如需詳細資訊,請參閱《Amazon CloudWatch 使用者指南》中的檢視日誌資料

步驟 3:清除資源

您可以刪除堆疊以清除建立的所有堆疊資源,便無需為不必要的資源支付費用。

刪除堆疊
  1. 從 CloudFormation 主控台中,選擇 SampleEC2Instance 堆疊。

  2. 選擇 Actions (動作),然後選擇 Delete Stack (刪除堆疊)

  3. 在確認訊息中,選擇 Yes, Delete (是,刪除)

系統將刪除您建立的所有資源。

現在您已了解如何透過 CloudFormation 建立和使用 Lambda 函數,您可以使用此逐步解說中的範例範本和程式碼來建置其他堆疊和函數。

相關資訊