今回は、AWS Lambda上にSpringBoot実装の簡単なAPIをデプロイする方法のメモです。
日時を返却するだけのAPIです。
おおまかに以下のような形で、デプロイします。
目次
バージョン
- SpringBoot:3.5.5
- Java:21
- SAM CLI:1.143.0
SpringBootプロジェクト
現在時刻を返却するだけの処理を実装しています。
また、AWS Lambdaで処理するためのハンドラクラスも実装します。
加えてSAMテンプレート等の定義ファイルもプロジェクト内に配置しておきます。
・SpringBootApplicationクラス
ProjectRoot/src/main/java/com/example/springboottimeronlambda/SpringBootTimerOnLambdaApplication.java
package com.example.springboottimeronlambda;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringBootTimerOnLambdaApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootTimerOnLambdaApplication.class, args);
}
}
・コントローラクラス
ProjectRoot/src/main/java/com/example/springboottimeronlambda/NowController.java
package com.example.springboottimeronlambda;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
@RestController
public class NowController {
@GetMapping("/now")
public Map<String, String> getCurrentTime() {
Map<String, String> response = new HashMap<>();
response.put("now", ZonedDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME));
return response;
}
}
・LambdaHanderクラス
ProjectRoot/src/main/java/com/example/springboottimeronlambda/StreamLambdaHandler.java
package com.example.springboottimeronlambda;
// AWS LambdaとAPI Gatewayのリクエスト/レスポンスモデルをインポート
import com.amazonaws.serverless.proxy.model.AwsProxyRequest;
import com.amazonaws.serverless.proxy.model.AwsProxyResponse;
// Spring BootアプリをLambdaで動かすためのハンドラ
import com.amazonaws.serverless.proxy.spring.SpringBootLambdaContainerHandler;
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestStreamHandler;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.IOException;
// Lambdaのリクエストストリームハンドラを実装
public class StreamLambdaHandler implements RequestStreamHandler {
// Spring Bootアプリ用のLambdaコンテナハンドラ(シングルトン)
private static final SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
// staticイニシャライザでハンドラを初期化
static {
try {
// Spring Bootアプリケーションのエントリポイントを指定してハンドラ生成
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(SpringBootTimerOnLambdaApplication.class);
} catch (Exception e) {
// 初期化失敗時はランタイム例外をスロー
throw new RuntimeException("Could not initialize Spring Boot application", e);
}
}
// Lambda関数のエントリポイント
@Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
// API GatewayからのリクエストをSpring Bootアプリにプロキシし、レスポンスを返す
handler.proxyStream(input, output, context);
}
}
・プロパティファイル
ProjectRoot/src/main/resources/application.properties
spring.application.name=SpringBootTimerOnLambda
・Gradleファイル
ProjectRoot/build.gradle
plugins {
id 'java'
id 'org.springframework.boot' version '3.5.5'
id 'io.spring.dependency-management' version '1.1.7'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
description = 'SpringBootTimerOnLambda'
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'com.amazonaws.serverless:aws-serverless-java-container-springboot3:2.0.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.named('test') {
useJUnitPlatform()
}
・AWS SAM テンプレート
ProjectRoot/template.yaml
AWSTemplateFormatVersion: '2010-09-09' # CloudFormation テンプレートのバージョン
Transform: AWS::Serverless-2016-10-31 # AWS SAM テンプレートであることを示す
Resources:
MyApi:
Type: AWS::Serverless::Api # API Gateway (REST API) をSAMで定義
Properties:
StageName: SpringBoot_Timer_Lambda_Dev # デプロイされるAPI Gatewayのステージ名
SpringBootFunction:
Type: AWS::Serverless::Function # Lambda関数をSAMで定義
Properties:
Handler: com.example.springboottimeronlambda.StreamLambdaHandler # Javaのエントリポイント(ハンドラクラス)
Runtime: java21 # Lambdaの実行ランタイム(Java 21)
CodeUri: . # デプロイするコードのパス(カレントディレクトリ)
MemorySize: 512 # Lambda関数のメモリ(MB)
Timeout: 60 # タイムアウト(秒)
Policies: AWSLambdaBasicExecutionRole # 最低限のLambda実行ロールを付与
Events:
ApiEvent:
Type: Api # API Gatewayイベントでトリガー
Properties:
RestApiId: !Ref MyApi # 上記で定義したAPI Gatewayリソースを参照
Path: /{proxy+} # 任意のパスで受け付ける(プロキシ統合)
Method: ANY # 全HTTPメソッドで受け付ける
・AWS SAM 設定ファイル
ProjectRoot/samconfig.toml
version = 0.1
[default.deploy.parameters]
stack_name = "spring-boot-timer-lambda" # CloudFormationスタック名
region = "us-east-1" # バージニア北部リージョン
capabilities = "CAPABILITY_IAM" # CloudFormationのIAM権限を許可
confirm_changeset = true # デプロイ前に変更セットを確認
デプロイ準備
・aws-sam-cli インストール
brew install aws-sam-cli
・jar作成
gradleでjarを作成します。
./gradlew build
ProjectRoot/build/libs/プロジェクト名-バージョン番号-SNAPSHOT.jarのような形式で生成されます。
デプロイ実施
・sam build
sam build
ProjectRoot/.aws-samディレクトリにLambdaデプロイ用にビルドされたプロジェクトファイルが生成されます。
・sam deploy
sam deploy --resolve-s3
実行されるたびに、S3にファイルが増えていきます。
(不要な場合手動等で削除してください)
尚、–resolve-s3ではなく–guidedを付与して実行すると、
対話形式で設定しながらデプロイされます。こちらで実施頂いても良いと思います。
(samconfig.tomlが不要になります)
aws sam deploy --guided
デプロイが完了するとを確認できます。
- S3バケット 資材ファイル
- CloudFormation スタック
- Lambda 関数
- API Gateway
- IAM ロール
・sam delete
sam delete
これらのデプロイした内容は、以下を除きそれぞれのリソースが破棄されます。
- 保護が有効になっているもの
- SAMテンプレート(CloudFormation)外で作成したもの
- 依存関係にある外部リソースなど
画面からもスタックを削除することができ、ほぼ同じ挙動になります。
調整などを行なっていると、意図せず削除されていないリソースが出てくることもありますので、
念の為、コマンドや画面で確認することをオススメします。
挙動確認
API Gatewayの画面より作成したAPIの詳細を確認します。
ステージのところで、今回作成したステージが確認できます。
※今回のyamlの内容だとAPI Gatewayのステージがデフォルト(Stage)も作成されます。
ステージのところに記載されているURLにcurlやブラウザなどでリクエストすることが出来ます。
今回のメモは以上です。
Github等でソース管理している場合は、cicdでそのままデプロイすると思いますが、
簡単な内容を試しでデプロイして動作させるだけであれば、
S3に資材を配置してデプロイすれば十分だと思います。