SpringBoot AWS Lambda デプロイ SAM テンプレート

今回は、AWS Lambda上にSpringBoot実装の簡単なAPIをデプロイする方法のメモです。
日時を返却するだけのAPIです。
SpringBoot AWS Lambda sam deploy sample
おおまかに以下のような形で、デプロイします。

SpringBoot AWS Lambda sam deploy sample PlantUML

バージョン

  • 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のような形式で生成されます。

SpringBoot AWS Lambda gradle build


デプロイ実施

・sam build

sam build

ProjectRoot/.aws-samディレクトリにLambdaデプロイ用にビルドされたプロジェクトファイルが生成されます。

SpringBoot AWS Lambda sam deploy sample

・sam deploy

sam deploy --resolve-s3

実行されるたびに、S3にファイルが増えていきます。
(不要な場合手動等で削除してください)

SpringBoot AWS Lambda sam deploy S3

尚、–resolve-s3ではなく–guidedを付与して実行すると、
対話形式で設定しながらデプロイされます。こちらで実施頂いても良いと思います。
(samconfig.tomlが不要になります)

aws sam deploy --guided

デプロイが完了するとを確認できます。

  • S3バケット 資材ファイル
  • CloudFormation スタック
  • Lambda 関数
  • API Gateway
  • IAM ロール

SpringBoot AWS Lambda sam deploy sample S3

SpringBoot AWS Lambda sam deploy sample CloudFormation stack

SpringBoot AWS Lambda sam deploy sample Lambda Function

SpringBoot AWS Lambda sam deploy sample API Gateway

SpringBoot AWS Lambda sam deploy sample IAM Role

・sam delete

sam delete

これらのデプロイした内容は、以下を除きそれぞれのリソースが破棄されます。

  • 保護が有効になっているもの
  • SAMテンプレート(CloudFormation)外で作成したもの
  • 依存関係にある外部リソースなど

画面からもスタックを削除することができ、ほぼ同じ挙動になります。

SpringBoot AWS Lambda sam delete

調整などを行なっていると、意図せず削除されていないリソースが出てくることもありますので、
念の為、コマンドや画面で確認することをオススメします。


挙動確認

API Gatewayの画面より作成したAPIの詳細を確認します。

SpringBoot AWS Lambda API

ステージのところで、今回作成したステージが確認できます。
※今回のyamlの内容だとAPI Gatewayのステージがデフォルト(Stage)も作成されます。

SpringBoot AWS Lambda API stage ステージのところに記載されているURLにcurlやブラウザなどでリクエストすることが出来ます。

SpringBoot AWS Lambda sam deploy sample API Request


今回のメモは以上です。

Github等でソース管理している場合は、cicdでそのままデプロイすると思いますが、
簡単な内容を試しでデプロイして動作させるだけであれば、
S3に資材を配置してデプロイすれば十分だと思います。

都内でエンジニアをやっています。 2017年に脱サラ(法人設立)しました。 仕事で調べたことや、気になったことをメモしています。
投稿を作成しました 182

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA


関連投稿

検索語を上に入力し、 Enter キーを押して検索します。キャンセルするには ESC を押してください。

トップに戻る