개요
개인 프로젝트에서 serverless에 배포를 고민하고 있다. 대표적인 클라우드 serverless 서비스인 AWS Lambda를 통해 프로젝트를 배포하는 것을 고려하고 있기 때문에 현재 프로젝트에 사용 중인 Spring과 AWS Lambda를 어떻게 연동하는지 알아보았다.
대표적으로 Spring Boot에 직접 연동하여 배포하는 방법과 Spring Clound Function을 사용해 연동하는 방법이 있다. 이 글에서는 먼저 Spring Boot에서 직접 연동하여 배포하는 방법을 적어본다.
1. 프로젝트 설정
Pre-requisites
build.gradle 설정
의존성 추가
dependencies {
implementation ('org.springframework.boot:spring-boot-starter-web') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
implementation 'com.amazonaws.serverless:aws-serverless-java-container-springboot3:2.0.1'
implementation 'com.amazonaws:aws-lambda-java-core:1.2.2'
implementation 'com.amazonaws:aws-lambda-java-events:3.11.1'
runtimeOnly 'com.amazonaws:aws-lambda-java-log4j2:1.5.1'
// 생략
}
프로젝트 패키지 빌드
zip 파일 아카이브를 사용하여 직접 함수를 배포할 때 사용한다.
task buildZip(type: Zip) {
from compileJava
from processResources
dependencies {
exclude(group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat')
}
into('lib') {
from(configurations.compileClasspath) {
exclude 'tomcat-embed-*'
}
}
}
build.dependsOn buildZip
참고사항
의존성 추가와 빌드 설정에 내장 Tomcat을 제외했다. AWS Lambda에 배포 시, 내장 Tomcat은 필요하지 않기 때문에 제외했다.
내장 Tomcat을 제외하지 않아도 잘 작동하는 것을 확인했다. 따라서, 제외하는 것이 필수는 아닌 듯하다.
2. 예제 코드 작성
RequestStreamHandler 구현
implementation 'com.amazonaws.serverless:aws-serverless-java-container-springboot3:2.0.1'
build.gradle에 이 의존성을 추가하면 RequestStreamHandler라는 인터페이스를 제공받는다.
public interface RequestStreamHandler {
void handleRequest(InputStream input, OutputStream output, Context context) throws IOException;
}
RequestStreamHandler는 handleRequest라는 추상 메서드를 갖고 있다. Spring Boot에서 AWS Lambda를 통해 들어오는 요청을 받기 위해서는 해당 인터페이스를 구현한 클래스를 따로 만들어야 한다.
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringBootLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringBootLambdaContainerHandler.getAwsProxyHandler(SpringLambdaApplication.class);
} catch (ContainerInitializationException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override
public void handleRequest(InputStream input, OutputStream output, Context context) throws IOException {
handler.proxyStream(input, output, context);
}
}
Controller
API 요청을 받는 역할은 보통 Spring 프로젝트에 사용하는 controller가 그대로 진행한다.
@RestController
public class ApiController {
@GetMapping("/hello")
public String hello() {
return "Hello! This is Spring Boot + AWS Lambda demo project.";
}
}
여기서는 간단하게 "/hello"라는 경로로 요청이 들어오면 문자열을 응답으로 반환하는 간단한 API controller를 생성했다.
3. 빌드 및 배포
template.yml 생성
AWS SAM CLI을 통해 빌드 및 배포를 위해 template.yml
을 작성해야 한다.
- 참고: SAM template
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Spring Boot + AWS Lambda demo project
Globals:
Api:
# API Gateway regional endpoints
EndpointConfiguration: REGIONAL
Resources:
DemoFunction:
Type: AWS::Serverless::Function
Properties:
Handler: demo.springlambda.handler.StreamLambdaHandler::handleRequest
Runtime: java17
CodeUri: .
Architectures:
- x86_64
MemorySize: 2048
Policies: AWSLambdaBasicExecutionRole
Timeout: 60
SnapStart:
ApplyOn: PublishedVersions
AutoPublishAlias: prod
Events:
HelloWorld:
Type: Api
Properties:
Path: /{proxy+}
Method: ANY
Outputs:
DemoApplicationApi:
Description: URL for application
Value: !Sub 'https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com'
Export:
Name: DemoApplicationApi
빌드 및 배포
빌드
sam build
Local에 함수 호출 테스트
sam local start-api
- Local 사용 시, Docker 설치 및 실행 필수
- Docker를 실행했는데도 오류가 생긴다면? --> 해결 방법
AWS Lambda에 배포
sam deploy --guided
References
'Spring' 카테고리의 다른 글
[Spring] RestClient에 대하여 (0) | 2024.07.01 |
---|---|
[Spring] @Scheduled를 사용한 메서드 스케줄링 (0) | 2024.06.17 |
[Spring] Pagination 기본값 설정하기 (0) | 2024.04.03 |
[Spring] MultipartFile Bean Validation (0) | 2024.01.26 |
[Spring] MultipartFile 테스트 시 405 Error가 생기는 이유 (0) | 2024.01.18 |