Kotlin과 Spring Boot MSA 프로젝트 구조 설계 및 세팅

Kotlin과 Spring Boot로 MSA를 구축할 때 첫 번째 고민은 프로젝트 구조다.
서비스가 여러 개로 나뉘다 보니 디렉토리 구성부터 빌드 환경까지 고려해야 할 요소가 많다.
각 서비스가 독립적으로 작동할 수 있어야 하고, 동시에 하나의 시스템처럼 잘 연결되어야 한다.
이 글에서는 MSA를 위한 기본 프로젝트 구조를 설계하고, Kotlin + Spring Boot 기반의 세팅 과정을 기록한다.

1. 전체 아키텍처 개요

msa-project/
├── config-server
├── discovery-server
├── gateway-service
├── auth-service
├── user-service
├── public-service
└── common-lib
  • config-server: 설정 중앙 관리
  • discovery-server: 서비스 디스커버리 (Eureka)
  • gateway-service: API 게이트웨이 (Spring Cloud Gateway)
  • auth-service: 인증 서비스 (OAuth2, JWT)
  • user-service: 인증된 사용자 전용 도메인 서비스
  • public-service: 누구나 접근 가능한 공개 서비스
  • common-lib: 공통 코드 (DTO, 유틸 등)

2. 빌드 시스템 선택

Kotlin과 Spring Boot기반 MSA 멀티 모듈 프로젝트에는 Gradle이 적합하다.
Kotlin DSL을 사용하는 build.gradle.kts로 관리한다.

루트 프로젝트의 settings.gradle.kts

rootProject.name = "msa-project"
include("config-server", "discovery-server", "gateway-service", "auth-service", "user-service", "public-service", "common-lib")

루트 프로젝트의 build.gradle.kts

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
        classpath("org.jetbrains.kotlin:kotlin-allopen:1.9.22")
        classpath("org.springframework.boot:spring-boot-gradle-plugin:3.2.5")
        classpath("io.spring.gradle:dependency-management-plugin:1.1.4")
    }
}


allprojects {
    repositories {
        mavenCentral()
    }
}

subprojects {
    apply(plugin = "org.jetbrains.kotlin.jvm")
    apply(plugin = "org.jetbrains.kotlin.plugin.spring")

    if (gradle.startParameter.isOffline) {
        tasks.register("build") {
            doLast {
                println("Offline mode - skipping build for ${'$'}project.path")
            }
        }
    }
}

3. 공통 모듈 구성

common-lib 모듈은 DTO, JWT 유틸, 공통 예외 처리 등을 포함한다.
서비스 간 중복 코드를 줄이고 유지보수를 쉽게 한다.

import java.util.Base64
import javax.crypto.Mac
import javax.crypto.spec.SecretKeySpec

object JwtUtil {
    fun createToken(subject: String, secret: String): String {
        val headerJson = "{" + "\"alg\":\"HS256\",\"typ\":\"JWT\"}"
        val payloadJson = "{" + "\"sub\":\"$subject\"}"
        val header = Base64.getUrlEncoder().withoutPadding().encodeToString(headerJson.toByteArray())
        val payload = Base64.getUrlEncoder().withoutPadding().encodeToString(payloadJson.toByteArray())
        val signature = hmacSha256("$header.$payload", secret)
        val sigEncoded = Base64.getUrlEncoder().withoutPadding().encodeToString(signature)
        return "$header.$payload.$sigEncoded"
    }

    fun verifyToken(token: String, secret: String): Boolean {
        val parts = token.split('.')
        if (parts.size != 3) return false
        val expected = Base64.getUrlEncoder().withoutPadding()
            .encodeToString(hmacSha256("${parts[0]}.${parts[1]}", secret))
        return expected == parts[2]
    }

    private fun hmacSha256(data: String, secret: String): ByteArray {
        val mac = Mac.getInstance("HmacSHA256")
        mac.init(SecretKeySpec(secret.toByteArray(), "HmacSHA256"))
        return mac.doFinal(data.toByteArray())
    }
}

4. 서비스 모듈 템플릿

각 서비스는 독립적인 Spring Boot 애플리케이션이다. 모듈별로 다음 구조를 갖는다:

user-service/
├── src/
│   └── main/
│       ├── kotlin/com/example/user/
│       ├── resources/
│       │   └── application.yml

각 서비스는 필요한 의존성만 갖고 독립적으로 실행 가능해야 한다.
공통 설정은 Config Server에서 관리하고, 서비스는 Eureka에 등록된다.

5. Kotlin + Spring Boot 초기 세팅

서비스 모듈의 build.gradle.kts 예시는 다음과 같다:

plugins {
    kotlin("jvm")
    kotlin("plugin.spring")
    id("org.springframework.boot")
    id("io.spring.dependency-management")
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-actuator")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation(project(":common-lib"))
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

6. 프로젝트 빌드

전체 프로젝트 빌드하고 특정 프로젝트를 빌드한 결과 지정된 8080 포트로 서비스가 잘 뜨는것을 확인 할 수 있었다

명확한 구조가 유지보수를 좌우한다

Kotlin과 Spring Boot로 만든 MSA는 복잡하지만,
프로젝트 초기 구조를 잘 설계하면 이후의 개발과 운영이 훨씬 수월해진다.
Kotlin과 Spring Boot는 간결한 문법과 강력한 생태계 덕분에 MSA 환경에서도 유용하다.
다음 글에서는 인증 서비스를 어떻게 구축할지 다뤄볼 예정이다.
JWT와 OAuth2를 활용한 인증 로직이 중심이 될 것이다.

이전편 보기
왜 인증 중심으로 MSA 설계를 하는가?

참고

Building web applications with Spring Boot and Kotlin

자세한 코드는 아래 저장소에서 확인 가능하다.
Github – 저장소

댓글 남기기