Spring Cloud Function을 이용해 Spring Application을 AWS Lambda에 배포하기

kshired·2022년 10월 6일
1
post-thumbnail

시작하며

현재 몬스테라 팀의 CS Broker 프로젝트는 AI 서버의 모델이 업데이트 되거나 채점 기준이 변경 되었을 경우, 많은 양의 채점 기록을 전부 재채점해야합니다.

이 상황에서 유용하게 사용할 수 있는 것이 Spring Batch 였습니다.

그러던 도중 하나의 문제에 봉착하게 됩니다.

배포를 어디에 할까?

이 프로젝트에서, 재채점 작업은 그렇게 자주 일어나는 작업이 아닙니다.

특정한 시점에, 요청이 있을 때만 재채점 작업을 진행하면 됩니다. 그렇기에, 이를 위해 서버를 하나 더 올리는 것은 비용 낭비라고 생각했습니다.

이런 비용 낭비를 줄이기 위해, AWS Lambda 서비스를 사용하기로 마음 먹었습니다.

Spring Cloud Function

운이 좋게도, Spring 프로젝트 중에 AWS Lambda나 Azure Functions과 같이 서버리스 서비스에 사용하기 쉽도록 해주는 Spring Cloud Function 이라는 것이 있다는 것을 알게 되었습니다.

이제 이것을 적용해보겠습니다.

주의! 이 프로젝트는 Kotlin 으로 개발되었습니다.

build.gradle.kts

아래와 같은 값들을 build.gradle.kts 에 추가합니다.


plugins {
    id("com.github.johnrengelman.shadow") version "7.1.2"
}

depenencies {
    implementation("org.springframework.cloud:spring-cloud-starter-function-web:3.2.5")
    implementation("org.springframework.cloud:spring-cloud-function-kotlin:3.2.5")
    implementation("org.springframework.cloud:spring-cloud-function-adapter-aws:3.2.5")
    implementation("com.amazonaws:aws-lambda-java-events:3.11.0")
    implementation("com.amazonaws:aws-lambda-java-core:1.2.1")
    runtimeOnly("com.amazonaws:aws-lambda-java-log4j2:1.5.1")
}

tasks.withType<Jar> {
	// Spring Application 시작점
    manifest {
        attributes["Start-Class"] = "io.csbroker.batchserver.BatchServerApplication" 
    }
}

tasks.assemble {
    dependsOn("shadowJar")
}

tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {
    archiveFileName.set("batch.jar")
    dependencies {
        exclude("org.springframework.cloud:spring-cloud-function-web")
    }
    mergeServiceFiles()
    append("META-INF/spring.handlers")
    append("META-INF/spring.schemas")
    append("META-INF/spring.tooling")
    transform(com.github.jengelman.gradle.plugins.shadow.transformers.PropertiesFileTransformer::class.java) {
        paths.add("META-INF/spring.factories")
        mergeStrategy = "append"
    }
}
  1. spring-cloud-function-web 은 로컬에서, 테스트 용도로 사용하기 위함입니다.
  2. Start-Class 의 값은 적절하게 변경해야합니다.
  3. shadowjar 는 모든 라이브러리를 포함한 fat-jar를 생성하기 위함입니다.
  4. 실제로 gradle 을 통해 jar 파일을 생성할 때는, spring-cloud-function-web 을 제외하게됩니다.

application.yml

아래와 같은 값들을 application.yml 에 추가합니다.

spring:
  cloud:
    function:
      definition: regradingProblem # 함수 이름
    main:
      banner-mode: off
logging:
  level:
    root: info

함수 작성

package io.csbroker.batchserver.function

import io.csbroker.batchserver.service.RegradingJobLauncherService
import io.csbroker.batchserver.util.log
import org.slf4j.MDC
import org.springframework.context.annotation.Bean
import org.springframework.stereotype.Component
import java.time.LocalDateTime
import java.time.ZoneId
import java.util.UUID

@Component
class RegradingFunction(
    private val regradingJobLauncherService: RegradingJobLauncherService
) {
    @Bean
    fun regradingProblem(): (Long) -> (String) {
        return {
            MDC.put("traceId", UUID.randomUUID().toString())
            log.info("==> re-grading request coming with problem id : $it")
            regradingJobLauncherService.regradingProblem(it, LocalDateTime.now(ZoneId.of("Asia/Seoul")))
            MDC.get("traceId")
        }
    }

}

위 예시는 실제로 CSBroker의 Batch 서버에서 사용하고 있는 코드입니다.

위 함수는 실제로 실행된다면, POST 요청을 통해 text/plain 의 Long 값을 받아 text/plain 의 String을 return하게 됩니다.

함수 테스트

이 어플리케이션을 local에서 실행하게 된다면, http://localhost:8080/함수이름 에 POST 요청을 함으로써 테스트를 할 수 있습니다.

spring-cloud-function-web 이 이를 가능하게 해줍니다.

실제 요청 및 응답 결과입니다.

AWS Lambda에 배포하기

함수 생성

함수 이름은 적절히 적어줍니다.

런타임은 Java 11 을 선택하면 됩니다.

런타임 설정 편집

함수가 생성되었다면, 런타임 설정을 편집해야합니다.

코드 -> 런타임 설정 -> 런타임 설정 편집을 누르고,

org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest 을 설정해줍니다.

환경 변수

구성 -> 환경 변수를 누르고,

키는 FUNCTION_NAME, 값은 아까 yml에서 정의한 함수이름과 같게 맞춰줍니다.

코드 소스 업로드

S3 bucket은 이미 있다고 가정하겠습니다.

  1. 아래 명령어를 통해, jar 파일을 생성해줍니다.
./gradlew shadowJar
  1. build/libs 에 생성된 jar 파일을 S3 bucket에 업로드합니다.

  2. S3에 업로드한 jar 파일을 url을 복사합니다.

  3. 위에서 복사한 url을, lambda 코드 소스 -> 업로드 -> Amazon S3 에 붙여넣기합니다.

제한 시간 및 메모리 값 변경

기본적으로 lambda의 제한 시간은 15초, 메모리는 512mb 입니다.

이 시간과 메모리로 Spring을 띄우기에는 조금 부족합니다.

시간과 메모리를 변경해줍니다.

구성 -> 일반 구성 -> 편집을 눌러줍니다.

저는 대략 1GB의 메모리와, 10분의 제한 시간을 설정했습니다.

필요한만큼 변경해주면 됩니다.

테스트

생성된 lambda를 테스트해보겠습니다.

Lambda 콘솔에서 테스트

Postman으로 테스트

AWS Lambda의 함수 url을 복사하여 Postman으로 요청해봅니다.

잘 됩니다.

profile
글 쓰는 개발자

0개의 댓글