서론
SpringBoot Framwork 기반의 Application을 build하는 방법은 많이 있습니다. 그 중 Docker를 활용하여 빌드 및 이미지화 하는 방법을 포스팅하려 합니다. 본 포스팅에서는 gradle build tool을 활용합니다.
본론
1. JDK , Spring Boot 버전 및 빌드 툴 확인하기
Application에서 사용하는 java 및 springboot 버전을 확인하려면 build.gradle 파일에서 확인할 수 있습니다.
2. docker hub에서 jdk 이미지 찾기
어플리케이션을 컨테이너 이미지로 만들때에 중요한건 아무래도 경량화라고 생각합니다. 때문에 저는 jdk 버전에 맞는 slim(경량화된 버전) 이미지를 활용하여 빌드를 시켜줄 예정입니다. Docker Hub에 접속하여 본인이 사용하는 jdk를 검색하면 그에 맞는 이미지를 확인할 수 있습니다.
https://hub.docker.com/layers/library/openjdk/17-slim/images/sha256-779635c0c3d23cc8dbab2d8c1ee4cf2a9202e198dfc8f4c0b279824d9b8e0f22
hub.docker.com
저는 openjdk를 사용할 예정이고, 그에 맞게 openjdk:17-slim 이미지를 빌드 및 런타임 이미지로 활용할 예정입니다.
3.Dockerfile 작성하기
저는 도커파일을 작성할 때 보통 Build Stage와 Runtime Stage를 나눠서 작성하는데, 그 이유는 아래와 같습니다.
장점
최소화된 이미지 크기:
빌드 단계에서 필요한 도구(예: Gradle, 소스 코드, 빌드 스크립트 등)는 최종 런타임 이미지에 포함되지 않으므로, 불필요한 파일과 라이브러리가 제거되어 이미지 크기를 크게 줄일 수 있습니다.
보안 강화:
빌드 도구나 디버깅에 사용되는 툴들이 런타임 이미지에 포함되지 않으므로, 공격 표면이 줄어들어 보안 측면에서 이점이 있습니다.
환경 분리:
빌드 환경과 실행 환경을 명확히 구분함으로써, 빌드에 필요한 의존성은 빌드 스테이지에서만 관리되고, 런타임 스테이지는 오로지 실행에 필요한 요소들만 포함하게 됩니다. 이를 통해 유지보수가 용이해집니다.
캐싱 활용:
변경되지 않는 빌드 단계의 캐시를 효과적으로 활용할 수 있어, 이후 빌드 시 전체 프로세스의 속도를 개선할 수 있습니다.
단점
Dockerfile 복잡도 증가:
멀티 스테이지 빌드는 Dockerfile 작성 시 각 단계의 역할과 파일 복사, 경로 관리 등을 신경써야 하므로 단일 스테이지에 비해 복잡해질 수 있습니다.
빌드 시간 및 리소스:
모든 스테이지를 거치기 때문에 빌드 시간이 다소 늘어날 수 있으며, 특히 복잡한 빌드 프로세스의 경우 빌드 서버 리소스 사용이 증가할 수 있습니다.
디버깅 어려움:
빌드 단계와 런타임 단계가 분리되어 있기 때문에, 빌드 시 발생하는 문제를 런타임 이미지에서 직접 확인하기 어려울 수 있습니다. 문제 발생 시 어느 단계에서 오류가 발생했는지 파악하는 데 추가적인 노력이 필요할 수 있습니다.
멀티 스테이지 빌드는 최종 이미지의 경량화, 보안 강화 및 환경 분리를 통한 유지보수 용이성 등의 큰 장점을 제공하지만, Dockerfile의 복잡도 증가와 빌드 과정에서의 리소스 사용, 디버깅의 어려움 등 단점도 존재합니다. 따라서, 프로젝트의 요구사항과 개발/운영 환경에 맞춰 적절히 선택하여 작성하시면 됩니다.
# --- Build Stage ---
FROM openjdk:17 AS build
WORKDIR /app/api.mingyu.co.kr
COPY . .
RUN chmod +x ./gradlew
# Gradle 빌드 시 병렬 워커 최소화
RUN ./gradlew clean build -x test --no-daemon
# --- Runtime Stage ---
FROM openjdk:17 AS runtime
WORKDIR /app/api.mingyu.co.kr
RUN mkdir -p logs
RUN mkdir -p config
COPY --from=build /app/api.mingyu.co.kr/build/libs/*.jar app.jar
COPY --from=build /app/api.mingyu.co.kr/src/main/resources/application-dev.yml config/application-dev.yml
EXPOSE 8080
제가 작성한 Dockerfile은 멀티스테이지 빌드로서, 빌드 환경(build stage)과 실행 환경(runtime stage)을 분리하여 최종 이미지의 크기를 줄이고, 불필요한 빌드 도구나 소스 코드를 런타임 이미지에서 제외합니다.
빌드 단계에서는 OpenJDK 17 기반의 빌드 환경 설정, 소스 코드 복사 및 Gradle 빌드 실행, 테스트는 제외하여 빠른 빌드 진행
런타임 단계에서는 OpenJDK 17 기반의 경량 실행 환경 설정, 로그 및 설정 파일 저장을 위한 디렉터리 생성, 빌드 단계에서 생성된 JAR 파일과 설정 파일 복사, 애플리케이션이 8080 포트에서 실행됨을 지정합니다.
저의 경우, spring boot 2.7버전을 사용하고, plain.jar 생성을 방지했기 때문에 *.jar를 app.jar로 변경해도 오류가 발생하진 않지만, 보통 plain.jar도 함께 생성되기 때문에 사전에 본인 버전에 맞는 방법으로 plain.jar 생성을 방지하거나, .jar 파일의 이름을 설정하여 COPY하도록 합니다.
4. Docker 빌드하기
Docker 명령어를 사용하여 Dockerfile을 기준으로 mingyu-api 라는 이름의 0.1 버전의 이미지를 생성합니다.
$ docker build -t mingyu-api:0.1 -f Dockerfile .
빌드가 정상적으로 완료되는것을 확인할 수 있습니다.
5. Docker 이미지 확인하기
docker 명령어를 사용하여 이미지가 잘 생성됬는지 확인합니다.
$ docker images
아래와 같이 0.1버전의 mingyu-api 이미지가 정상적으로 생성된 것을 확인할 수 있습니다.
결론
각자의 java 버전 및 spring boot에 따라 취향껏 커스텀하며 도커파일을 작성할 수 있습니다. 도커의 확장성은 무궁무진합니다. 너무 어려워 하지 말고 많이 작성해보고 빌드해보면서 사용해보도록 합시다.
'Docker' 카테고리의 다른 글
[Chat GPT] GPT가 만든 PHP, Nginx, Mysql, Mongo, Redis 웹 환경 도커 셋팅 (2) | 2023.02.20 |
---|---|
Docker를 사용하여 Laravel 환경 구축하기 (6) | 2022.02.24 |