AWS SAM を使用して、Lambda ベースのカスタムリソースを Java で CloudFormation 用に構築する方法を教えてください。
Java を使用して AWS Lambda ベースのカスタムリソースを構築し、AWS CloudFormation に実装したいと考えています。
簡単な説明
Lambda for CloudFormation で Java ベースのカスタムリソースを構築することは、特にこのプロセスを手動で行う場合では複雑なプロセスとなります。環境を手動で設定するには、リソースをビルドする前に Java 開発キットとランタイムをセットアップする必要があります。次に、最終的に Lambda 関数を作成する前に、コードをパッケージ化して Amazon Simple Storage Service (Amazon S3) にアップロードする必要があります。
このプロセスを簡略化するには、AWS Serverless Application Model (AWS SAM)を使用できます。AWS SAM は、AWS でサーバーレスアプリケーションを構築するために使用できるオープンソースのフレームワークです。このサービスは、Java カスタムリソースの構築、コードのアップロード、カスタムリソースと Lambda 関数のデプロイに役立てることができます。
解決方法
開発用インスタンスを作成する
1. Amazon Elastic Compute Cloud (Amazon EC2) インスタンスを作成してリソースを開発してください。インスタンスにはどのような環境でも使用できますが、このユースケースでは Amazon Linux 2 でインスタンスを作成するのがベストプラクティスです。
2. Amazon EC2 SSH キーペアを作成して EC2 インスタンスに割り当てます。
3. スタックとリソースをデプロイする権限を持つインスタンスプロファイル を設定します。具体的には、次のアクションを実行する権限を付与してください。
- Lambda 関数を作成する
- 機能コードを更新する
- 関数を呼び出す
- Lambda のログを格納するロググループを作成する
4. インスタンスを起動したら、SSH でログインします。次のセクションでは、このインスタンスを開発環境として使用します。
開発環境のセットアップ
重要: 始める前に、AWS コマンドラインインターフェイス (AWS CLI) を インストールして、設定します。AWS CLI コマンドの実行中にエラーが発生した場合は、最新バージョンの AWS CLI を使用していることを確認してください。
java-corretto11 をインストールする
corretto11 をインストールするには、次のコマンドを実行します。
sudo rpm --import https://yum.corretto.aws/corretto.key sudo curl -L -o /etc/yum.repos.d/corretto.repo https://yum.corretto.aws/corretto.repo sudo yum install -y java-11-amazon-corretto-devel
以下のコマンドでインストールを確認します。
java -version
詳細については、RPM ベースの Linux に Amazon Corretto 11 をインストールするを参照してください。
AWS SAM をインストールする
AWS SAM をインストールするには、次のコマンドを実行します。
wget https://github.com/aws/aws-sam-cli/releases/latest/download/aws-sam-cli-linux-x86_64.zip unzip aws-sam-cli-linux-x86_64.zip -d sam-installation sudo ./sam-installation/install sam --version
詳細については、AWS SAM CLI のインストールを参照してください。
Gradle をインストールする
Gradle をインストールするには、次のコマンドを実行します。
wget https://services.gradle.org/distributions/gradle-7.6-bin.zip sudo mkdir /opt/gradle sudo unzip -d /opt/gradle gradle-7.6-bin.zip export PATH=$PATH:/opt/gradle/gradle-7.6/bin gradle -v
詳細については、Gradle Web サイトのパッケージマネージャーによるインストールを参照してください。
注記:再起動後に PATH を再度エクスポートする必要がある場合があります。この手順を回避するには、~/.bashrc ファイルに次の行を追加してください。
export PATH=$PATH:/opt/gradle/gradle-7.6/bin
プロジェクトとファイルを作成する
SAM プロジェクトのルートフォルダを作成するには、以下のコマンドを実行します。
mkdir javaBasedCustomResource cd javaBasedCustomResource/
プロジェクトに必要なフォルダを作成するには、以下のコマンドを実行します。
mkdir -p src/Function/src/main/java/
Vim のテキストエディタでプロジェクトファイルを作成します。詳細については、Vim の Web サイトを参照してください。次の内容をコピーして Vim で実行します。
vim template.yaml vim ./src/Function/build.gradle vim ./src/Function/src/main/java/Handler.java
プロジェクトの構造は次の構造ツリーに似ています。
. └── javaBasedCustomResource ├── src │ └── Function │ ├── build.gradle │ └── src │ └── main │ └── java │ └── Handler.java └── template.yaml
プロジェクトを構築するためのファイルテンプレートについては、以下のセクションを参照してください。
template.yaml
スタックには次のテンプレートを使用してください。これにより、Lambda 関数、ロググループ、CustomResourceが定義されます。
Transform: AWS::Serverless-2016-10-31 Resources: CustomResourceJavaBased: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !Join ["", [ !Sub "arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:", !Ref CustomResourceLambdaInJava]] DummyKey: DummyValue CustomResourceLambdaInJava: Type: AWS::Serverless::Function Properties: Description: !Sub - Stack ${AWS::StackName} Function ${ResourceName} - ResourceName: CustomResourceLambdaInJava CodeUri: src/Function Handler: Handler::handleRequest Runtime: java11 MemorySize: 3008 Timeout: 30 Tracing: Active CustomResourceLambdaInJavaLogGroup: Type: AWS::Logs::LogGroup DeletionPolicy: Retain Properties: LogGroupName: !Sub /aws/lambda/${CustomResourceLambdaInJava}
build.gradle
Java のビルドを容易にするために、次のファイルテンプレートを使用してください。
apply plugin: 'java' repositories { mavenCentral() } dependencies { implementation 'com.amazonaws:aws-lambda-java-core:1.2.2' implementation 'com.amazonaws:aws-lambda-java-events:3.11.0' implementation 'com.google.code.gson:gson:2.10' } task buildZip(type: Zip) { from compileJava from processResources into('lib') { from configurations.compileClasspath } } build.dependsOn buildZip
Handler.java
Lambda は次のコードを実行します。これにより、入力イベントが Map に設定され、そこからレスポンスを送り返すために必要なエンドポイント URL を取得できます。必要なパラメータをすべて JSON 文字列に入力し、エンドポイントに HTTP リクエストを送信します。
import com.google.gson.Gson; import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.*; import java.io.*; public class Handler { public String handleRequest(Object event) { /* Customer workload */ System.out.println("Dummy CustomResource Job"); /* sending signal back to CFN stack */ try { sendResponse(event); } catch (Exception e){ System.out.println("Got Exception!!"); e.printStackTrace(System.out); } return "JobFinished"; } public void sendResponse(Object event) throws IOException, InterruptedException { System.out.println("start sending signal"); Gson gson = new Gson(); String eventJson = gson.toJson(event); Map map = gson.fromJson(eventJson, Map.class); System.out.println("Request event: " + eventJson); /* Generate response parameters */ String putEndpoint = (String)map.get("ResponseURL"); String Status = "SUCCESS"; // "SUCCESS" or "FAILED" String Reason = "Dummy reason for Java based Custom Resource"; String PhysicalResourceId = "CustomResourcePhysicalID"; String StackId = (String)map.get("StackId"); String RequestId = (String)map.get("RequestId"); String LogicalResourceId = (String)map.get("LogicalResourceId"); /* Building response */ String responseJson = "{\"Status\":\"" + Status + "\",\"Reason\":\"" + Reason + "\",\"PhysicalResourceId\":\"" + PhysicalResourceId + "\",\"StackId\":\"" + StackId + "\",\"RequestId\":\"" + RequestId + "\",\"LogicalResourceId\":\"" + LogicalResourceId + "\",\"NoEcho\":false,\"Data\":{\"Key\":\"Value\"}}"; System.out.println("Response event: " + responseJson); var request = HttpRequest.newBuilder() .uri(URI.create(putEndpoint)) .header("Content-Type", "application/json") .PUT(HttpRequest.BodyPublishers.ofString(responseJson)) .build(); var client = HttpClient.newHttpClient(); /* Sending Response */ System.out.println("Sending Response to stack, response code: "); var response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.statusCode()); System.out.println(response.body()); System.out.println("Finish sending signal"); } }
プロジェクトをデプロイする
1. AWS SAM プロジェクトを作成したら、ルートプロジェクトフォルダ JavaBasedCustomResourceで次のコマンドを実行します。
sam build
2. プロジェクトをデプロイするには、次のコマンドを実行します。すると、リソースを作成するスタック名と AWS リージョンの指定を求めるガイドが表示されます。
sam deploy --guided
これにより、指定した名前の CloudFormation スタックがアカウントにデプロイされます。スタックには、前のステップのコードを実行する Lambda 関数が含まれています。また、CloudFormation は同じスタックにカスタムリソースタイプ AWS:: CloudFormation:: CustomResource を作成します。
CloudFormation が AWS:: CloudFormation:: CustomResource を作成すると、CloudFormation は上記の Lambda 関数も呼び出します。これに応答して、Lambda 関数は SYCEESS シグナルを CloudFormation に送り返します。この SUCCESS シグナルは、リソースを CreateCompleteに送信します。
スタック内のカスタムリソースが正常に作成されると、Lambda も正常に実行されていることになります。Lambda はシグナルをスタックに返し、Java ベースのカスタムリソースは正常に起動します。
リクエストイベントやレスポンスイベントなどのメトリクスの詳細については、Lambda ログで確認できます。関数コードを変更して独自のタスクを指定したり、独自のリソースを作成したりできます。
関連するコンテンツ
- 質問済み 3ヶ月前lg...
- AWS公式更新しました 3年前