チュートリアル: Amazon マシンイメージ ID を参照する - AWS CloudFormation

チュートリアル: Amazon マシンイメージ ID を参照する

Amazon Elastic Compute Cloud (Amazon EC2) インスタンスを宣言する AWS CloudFormation テンプレートでは、インスタンスの起動に使用される、オペレーティングシステムまたはその他のソフトウェアと構成情報が含まれた Amazon マシンイメージ (AMI) の ID も指定する必要があります。適切な AMI ID は、スタックを起動するインスタンスタイプおよびリージョンによって異なる場合があります。ID は定期的に変更される可能性があります (AMI が更新されてソフトウェアアップデートが追加されたときなど)。

通常は、特定のインスタンスタイプとリージョンに AMI ID をマップできます。ID を更新するには、各テンプレートで手動で更新します。カスタムリソースと AWS Lambda (Lambda) を使用すると、使用するリージョンとインスタンスタイプの最新 AMI の ID を取得する関数を作成でき、マッピングを維持する必要がなくなります。

このチュートリアルでは、カスタムリソースを作成して Lambda 関数を関連付け、AMI ID を参照する方法を示します。また、カスタムリソースと Lambda の使用方法を理解していることが前提です。詳細については、「カスタムリソース」または「AWS Lambda デベロッパーガイド」を参照してください。

チュートリアルの概要

このチュートリアルでは、カスタム リソース、Lambda 関数、および EC2 インスタンスを伴うスタックを作成します。チュートリアルでは、スタックの作成に使用するサンプルコードとサンプルテンプレートを提供します。

サンプルテンプレートは、カスタムリソースタイプを使用し、Lambda 関数を呼び出して入力値を渡します。テンプレートを使用すると、AWS CloudFormation によってこの関数が呼び出され、リクエストタイプ、入力データ、署名付き Amazon Simple Storage Service (Amazon S3) URL などの情報が渡されます。この関数は、その情報を使用して AMI ID を参照し、署名付き URL に応答を送信します。

AWS CloudFormation は、署名付き URL の場所で応答を取得した後、スタックの作成処理に進みます。AWS CloudFormation はインスタンスを作成すると、Lambda 関数の応答を使用してインスタンスの AMI ID を指定します。

次のリストは、プロセスをまとめたものです。対応するサービス (Lambda、Amazon EC2、AWS CloudFormation など) をすべて使用するには、AWS Identity and Access Management (IAM) 権限が必要です。

注記

AWS CloudFormation は無料サービスです。ただし、スタックに追加する AWS リソース (Lambda 関数や EC2 インスタンスなど) にはそれぞれ、現在の料金が課金されます。AWS 料金に関する詳細については、http://aws.amazon.com で各製品の詳細ページを参照してください。

  1. Amazon Simple Storage Service (Amazon S3) バケットに、サンプルの Lambda パッケージを保存します。

    サンプル パッケージには、Lambda 関数を作成するために必要なものがすべてが含まれています。パッケージは、スタックを作成するリージョンと同じリージョンにあるバケットに保存する必要があります。

  2. サンプルテンプレートを使用してスタックを作成します。

    スタックは、Lambda 関数とカスタムリソースを関連付ける方法と、関数からの結果を使用して AMI ID を指定する方法を示しています。また、スタックによって IAM ロール (実行ロール) が作成されます。このロールは、Lambda が Amazon EC2 を呼び出すために使用されます。

  3. スタックを削除します。

    不要なリソースに対して課金されないよう、作成したすべてのスタックリソースをクリーンアップするために、スタックを削除します。

ステップ 1: サンプルパッケージをダウンロードして Amazon S3 に保存する

Lambda 関数を使用してスタックを作成する際は、関数のソースコードが格納されている Amazon S3 バケットの場所を指定する必要があります。バケットは、スタックを作成するリージョンと同じリージョンに存在する必要があります。

このチュートリアルでは、Lambda 関数を作成するために必要なサンプルパッケージ (.zip ファイル) が提供されます。Lambda パッケージには、関数のソースコードおよび必要なライブラリが含まれています。このチュートリアルでは、関数に追加のライブラリは必要ありません。

この関数は、AWS CloudFormation カスタムリソースリクエストからインスタンスのアーキテクチャおよびリージョンを入力として取得し、最新の AMI ID を署名済みの Amazon S3 URL に返します。

パッケージをダウンロードして Amazon S3 に保存するには
  1. サンプルパッケージを Amazon S3 からダウンロードします。ファイルを保存する際には、サンプルと同じファイル名の amilookup.zip もしくは amilookup-win.zip を使用してください。

  2. https://console.aws.amazon.com/s3/home にある Amazon S3 コンソールを開きます。

  3. AWS CloudFormation スタックを作成するリージョンと同じリージョンにあるバケットを選択するか、新しく作成します。バケット名をメモしておきます。

    このバケットにサンプルパッケージを保存します。バケットの作成の詳細については、「Amazon Simple Storage Service ユーザーガイド」の「Creating a bucket」(バケットの作成) を参照してください。

  4. 選択または作成したバケットに、サンプルパッケージをアップロードします。

    オブジェクトのアップロードの詳細については、「Amazon Simple Storage Service ユーザーガイド」の「Uploading objects」(オブジェクトのアップロード) を参照してください。

パッケージを Amazon S3 に保存したら、AWS CloudFormation テンプレートの Lambda リソース宣言で、場所を指定できます。次のステップでは、関数を宣言し、カスタムリソースを使用して呼び出す方法を示します。関数の結果を使用して、EC2 インスタンスの AMI ID を指定する方法についても説明します。

ステップ 2: スタックを作成する

Amazon EC2 のサンプルスタックを作成するには、Lambda 関数が含まれるサンプルテンプレート、IAM 実行ロール、関数を呼び出すカスタムリソース、関数からの結果を使用する EC2 インスタンスを使用します。

スタックの作成時、カスタムリソースは Lambda 関数を呼び出し、この関数によって応答が署名済み Amazon S3 の URL に送信されるまで待ちます。応答では、EC2 インスタンスタイプと、インスタンスを作成するリージョンに対応する最新の AMI ID が返されます。関数の応答からのデータは、カスタムリソースの属性として保存されます。この属性は、EC2 インスタンスの AMI ID を指定するために使用されます。

次のスニペットは、Lambda 関数をカスタムリソースと関連付ける方法や、その関数の応答を使用する方法について理解するのに役立つサンプルテンプレートの関連する部分について説明しています。

サンプルテンプレート全体を確認するには、以下を参照してください。

スタックテンプレートのスニペット

Lambda 関数を作成するには、AWS::Lambda::Function リソースを宣言します。これには、関数のソースコード、ハンドラー名、ランタイム環境、実行ロールの 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

Code プロパティでは、サンプルパッケージをアップロードした Amazon S3 の場所 (バケット名とファイル名) を指定します。サンプルテンプレートでは、スタックの作成時に名前を指定できるように、バケット名とファイル名の設定には入力パラメーター ("Ref": "S3Bucket" および "Ref": "S3Key") が使用されます。同様に、.zip パッケージに含まれているソースファイル (JavaScript ファイル) の名前に対応するハンドラー名にも、入力パラメーター ("Ref": "ModuleName") が使用されます。ソースファイルは JavaScript であるため、ランタイムは nodejs18.x として指定されます。

このチュートリアルでは、関数の実行時間がデフォルト値の 3 秒を超えるため、タイムアウトは 30 秒に設定されています。十分な長さのタイムアウトを指定しなかった場合、関数が完了する前に Lambda でタイムアウトが発生し、スタックの作成に失敗することがあります。

テンプレートの他の箇所で宣言される実行ロールは、Fn::GetAtt 組み込み関数を使用して Role プロパティで指定されます。実行ロールは 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: "*"

Linux および Windows のテンプレートのどちらも、カスタムリソースは関連付けられた Lambda 関数を起動します。関数をカスタムリソースと関連付けるには、Fn::GetAtt 組み込み関数を使用して、ServiceToken プロパティ用に関数の Amazon リソースネーム (ARN) を指定します。AWS 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"

AWS CloudFormation によって Lambda 関数が呼び出されると、この関数はリージョンとインスタンスのアーキテクチャまたは OS 名を使用してイメージのリストをフィルタし、EC2 DescribeImages API を呼び出します。さらに、日付によってイメージのリストをソートし、最新 AMI の ID を返します。

関数では、最新 AMI の ID を返す際に、この ID を応答オブジェクトData プロパティで署名付き URL に送信します。データは、次の例に示すように、名前と値のペアとして構造化されます。

"Data": { "Id": "ami-43795473" }

次のスニペットは、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

テンプレートの機能を理解できたところで、サンプルテンプレートを使用してスタックを作成しましょう。

スタックを作成するには
  1. https://console.aws.amazon.com/cloudformation/ で AWS CloudFormation コンソール を開きます。

  2. [Create Stack] (スタックの作成) を選択します。

  3. [テンプレート] セクションで、[Amazon S3 テンプレート URL の指定)] を選択し、次の URL をコピーしてテキストボックスに貼り付けます。

  4. [Next] (次へ) をクリックします。

  5. [スタックの名前] フィールドに SampleEC2Instance と入力します。

  6. [パラメータ] セクションで、作成した Amazon S3 バケットの名前を指定し、[次へ] を選択します。

    他のパラメーターのデフォルト値は、サンプルの .zip パッケージで使用されている名前と同じです。

  7. このチュートリアルでは、タグの追加も詳細設定の指定も不要です。[次へ] を選択します。

  8. スタック名とテンプレート URL が正しいことを確認し、[作成] を選択します。

AWS CloudFormation によってスタックが作成されるまでに数分かかることもあります。進捗状況を監視するには、スタックイベントを確認します。詳細については、「AWS Management Console での AWS CloudFormation スタックデータとリソースの表示」を参照してください。

スタックの作成に成功した場合は、スタック内のすべてのリソース (Lambda 関数、カスタムリソース、EC2 インスタンスなど) も作成されています。Lambda 関数とカスタムリソースを正常に使用して EC2 インスタンスの AMI ID を指定できています。このテンプレートで AMI ID のマッピングを作成および維持する必要はありません。

どの AMI ID を使用して AWS CloudFormation で EC2 インスタンスが作成されたか確認するには、スタック出力を確認します。

Lambda 関数からエラーが返される場合は、Amazon CloudWatch Logs コンソールで関数のログを確認します。ログストリームの名前は、カスタムリソースの物理 ID です。これは、スタックのリソースを表示して確認できます。詳細については、「Amazon CloudWatch ユーザーガイド」の「Viewing log data」(ログデータの表示) を参照してください。

ステップ 3: リソースをクリーンアップする

不要なサービスに対して課金されないように、スタックを削除します。

スタックを削除するには
  1. AWS CloudFormation コンソールから、[SampleEC2Instance] スタックを選択します。

  2. [アクション] を選択し、[スタックの削除] を選択します。

  3. 確認メッセージで、[はい、削除する] を選択します。

作成したすべてのリソースが削除されます。

これで、AWS CloudFormation によって Lambda 関数を作成して使用する方法を理解できました。このチュートリアルのサンプルテンプレートおよびコードを使用して、他のスタックおよび関数を作成することができます。

関連情報