0.1 멀티 모듈이란?
자바에서 모듈(Module)은 독립적으로 배포될 수 있는 코드의 단위를 말합니다.
멀티 모듈(Multi-Module)이란 이러한 코드 뭉치를 하나의 프로젝트 안에서 관리하는 것을 의미합니다.
멀티 모듈 안에서 각각의 모듈은 서로를 향한 의존성을 가질 수 있습니다.
여러개의 모듈을 생성할 때 반드시 멀티 모듈 프로젝트를 생성해야 하진 않지만 코드 중복 제거, 모듈 간 의존성을 위해 저장소에 배포하지 않아도 되는 점 등 장점이 있고 이를 각각 다른 컴포넌트로 구성해야 하는 경우에 하나의 프로젝트에서 어떻게 빌드를 수행해야 하는지 확인해 보겠습니다.
예시를 들자면 다음과 같이 스프링 프로젝트를 멀티모듈로 하나의 프로젝트에서 구성했습니다. 그 후에 컨테이너화 하여 서버에 각각의 컴포넌트로 띄우고자 합니다. 이제 다음으로 CI/CD과정을 통해서 Build를 수행하고자 한다면, 다른 github를 사용하는 대신 GithubAction의 Path전략을 사용할 수 있습니다.
# 공통 베이스 이미지 설정
FROM amd64/amazoncorretto:21 AS base
WORKDIR /app
# 공통 빌드 인스트럭션
FROM base AS builder
ARG SERVICE_NAME
COPY ${SERVICE_NAME}/build/libs/*.jar app.jar
# 최종 이미지 설정
FROM amd64/amazoncorretto:21
COPY --from=builder /app/app.jar app.jar
ENTRYPOINT ["java", "-Duser.timezone=Asia/Seoul", "-jar", "-Dspring.profiles.active=docker", "app.jar"]
다음과 같이 최상위 폴더에 DockerFile을 생성해 줍니다. DockerFile의 키워드에 관련해서는 알고 계시다고 생각하고 간단하게만 설명하고 넘어가겠습니다.
다음 코드는 이미지를 가져와서 공통으로 빌드를 수행할 수 있는 DockerFile입니다.
각 서비스 이름을 통해서 build를 수행할 수 있고, 그 후 이미지를 생성하는 코드입니다.
gradle을 사용한다면 다음과 같은 예시를 들 수 있겠습니다.
./gradlew :user-service:build -x test
docker build --build-arg SERVICE_NAME=user-service -t ${image Repository} .
다음과 같이 수행을 하게 된다면 멀티모듈로 구성된 서비스 이름으로 build가 이루어지게 됩니다.
해당하는 모듈 이름을 통해 해당 모듈만 빌드를 수행할 수 있습니다.
해당 프로젝트들을 여러 사람들이 작업하고 있고 각각의 작업물을 수행한 뒤 병합하는 과정에서 전체 application전체를 하나하나 다 build를 수행해야 한다면 모든 컴포넌트 build, 서버에 올리는 작업까지 너무 많은 시간이 걸리게 됩니다. 따라서 github에서는 path별로 수행할 수 있는 방법을 적용할 수 있습니다.
name: User Service CICD
on:
push:
branches: ["dev"]
paths:
- 'user-service/**'
다음은 github action의 yml파일입니다. github action을 수행하는 방법은 따로 설명드리지 않겠습니다.
다음과 같이 paths: 키워드를 작성하면 해당 path에 있는 파일이 변경되었을 때만 action파일을 수행할 수 있습니다.
예시로 다음과 같이 작성할 수 있습니다.
jobs:
build_and_deploy:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set up JDK 21
uses: actions/setup-java@v3
with:
distribution: 'corretto'
java-version: '21'
- name: Create application.yml
run: |
mkdir -p user-service/src/main/resources
touch user-service/src/main/resources/application.yml
echo "${{ secrets.USER_APPLICATION }}" > user-service/src/main/resources/application.yml
cat user-service/src/main/resources/application.yml
- name: Build User Service
run: |
./gradlew :user-service:build -x test
- name: Docker Login
uses: docker/login-action@v2.2.0
with:
username: ${{ secrets.DOCKER_LOGIN_USERNAME }}
password: ${{ secrets.DOCKER_LOGIN_ACCESSTOKEN }}
- name: Docker Image Build and Push
run: |
docker build --build-arg SERVICE_NAME=user-service -t ${{ secrets.DOCKER_REPOSITORY }}/user-service-image .
docker push ${{ secrets.DOCKER_REPOSITORY }}/user-service-image
- name: Deploy User Service via SSH
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.SERVER_IP }}
username: ${{ secrets.SERVER_USER }}
key: ${{ secrets.SERVER_KEY }}
script: |
cd ~
./deploy_user_service.sh
docker image prune -f
여기서 주의 깊게 봐야 할 부분은
1. CI/CD를 수행할 때 1차적으로 path를 통해서 action을 수행하는가?
2. 그때 action 수행과정에서 해당 모듈만 build를 하는가?
입니다.
따라서 해당내용을 확인하고 필요한 부분에만 따라서 build를 수행하고 배포하는 과정을 진행할 수 있습니다.
'Spring' 카테고리의 다른 글
Spring Boot 서비스 환경 스트레스 테스트 [Spring/Java] (1) | 2025.01.04 |
---|---|
Spring Boot 프로파일링 및 Stress Test [Spring] (0) | 2024.12.21 |
가상 스레드 vs 반응형 프로그래밍 [Spring/Java] (2) | 2024.11.22 |
[Spring] 응? 이게 왜 롤백이 안되지? - 비동기와 @Transaction (4) | 2024.10.21 |
[Spring] Redis기반의 EventStreamListener가 동작하지 않는 문제 (2) | 2024.10.15 |