MSA
최저 리소스와 최고 성능으로 스프링부트 애플리케이션을 구동
ipxy
2025. 3. 18. 14:25
728x90
최적의 Dockerfile 구성
# 1단계: 빌더 - 정적 링크로 네이티브 이미지 컴파일
FROM ghcr.io/graalvm/graalvm-ce:latest AS builder
WORKDIR /app
# 프로젝트 파일 복사
COPY . .
RUN chmod +x ./gradlew
# 네이티브 이미지 빌드 (완전 정적 링크)
RUN ./gradlew nativeCompile \
-Dorg.graalvm.nativeimage.imagecode=static \
--no-daemon \
-Pnative
# 2단계: UPX로 바이너리 압축
FROM alpine:latest AS compressor
RUN apk add --no-cache upx
WORKDIR /app
COPY --from=builder /app/build/native/nativeCompile/application .
# 최대 압축률로 바이너리 압축 (시간이 걸릴 수 있음)
RUN upx --ultra-brute --best application
# 3단계: 최종 이미지 - scratch 베이스 (가장 작은 크기)
FROM scratch
WORKDIR /
# 필요한 최소 시스템 라이브러리만 복사 (필요한 경우)
# COPY --from=builder /lib/x86_64-linux-gnu/libz.so.1 /lib/x86_64-linux-gnu/libz.so.1
# 압축된 바이너리 복사
COPY --from=compressor /app/application /application
# 실행 명령
ENTRYPOINT ["/application"]
최적화 추가 설정
1. GraalVM 네이티브 이미지 최적화 옵션
build.gradle 또는 스크립트에 다음 GraalVM 옵션 추가:
graalvmNative {
binaries {
main {
imageName = 'application'
buildArgs.add('-O3') // 최대 최적화
buildArgs.add('--static')
buildArgs.add('-H:+RemoveSaturatedTypeFlows')
buildArgs.add('-H:+ReportExceptionStackTraces')
buildArgs.add('-H:+StackTrace')
buildArgs.add('--initialize-at-build-time')
buildArgs.add('-H:+UnlockExperimentalVMOptions')
buildArgs.add('-H:+EnableAllSecurityServices')
buildArgs.add('-march=native') // 대상 CPU 아키텍처에 최적화
buildArgs.add('-R:MaxHeapSize=32m') // 힙 크기 제한
}
}
}
2. 스프링부트 애플리케이션 최적화
application.properties에 다음 설정 추가:
# 서버 최적화
server.tomcat.threads.max=50
server.tomcat.max-connections=200
server.tomcat.accept-count=100
# 메모리 최적화
spring.jpa.properties.hibernate.jdbc.batch_size=30
spring.jpa.properties.hibernate.order_inserts=true
spring.jpa.properties.hibernate.order_updates=true
# 로깅 최소화
logging.level.root=WARN
logging.level.org.springframework=WARN
logging.pattern.console=%d{HH:mm:ss} %-5level %logger{36} - %msg%n
# JVM 옵션 (JVM 모드로 실행 시)
# -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Xmx128m -XX:+UseStringDeduplication
3. 컨테이너 런타임 설정
Kubernetes 또는 Docker 실행 시 리소스 제한:
resources:
limits:
memory: "128Mi"
cpu: "500m"
requests:
memory: "64Mi"
cpu: "250m"
4. 운영 권장사항
- 워밍업: 정적 리소스 사전 로드
- 애플리케이션 모니터링:
- management.endpoints.web.exposure.include=health,prometheus management.metrics.export.prometheus.enabled=true
- JIT 최적화 회피: AOT 컴파일로 예측 가능한 성능 확보
- Kubernetes에서 실행 시 설정:
- securityContext: allowPrivilegeEscalation: false runAsNonRoot: true runAsUser: 1000 capabilities: drop: ["ALL"]
이 구성은 다음과 같은 이점을 제공합니다:
- 극소형 이미지 크기: 약 10-50MB (애플리케이션 복잡도에 따라 다름)
- 빠른 시작 시간: 100ms 미만
- 낮은 메모리 사용량: 20-50MB (단순한 애플리케이션의 경우)
- 보안 강화: 최소한의 공격 표면
- 높은 처리량: 네이티브 코드 실행으로 최적화된 성능
이 방식은 리소스가 제한된 환경(예: 엣지 컴퓨팅, IoT, 서버리스)에서 특히 효과적입니다.
상세 주석 포함 Dockerfile
# 1단계: GraalVM을 사용하여 네이티브 이미지 빌드
# GraalVM CE (Community Edition) 최신 버전의 컨테이너 이미지를 사용
FROM ghcr.io/graalvm/graalvm-ce:latest AS builder
WORKDIR /app # 작업 디렉토리 설정
# --- 캐시 활용 최적화 ---
# 프로젝트의 필수 파일을 먼저 복사 (의존성 캐싱을 위해)
COPY build.gradle settings.gradle gradle.properties gradlew gradle/ ./
# Gradle 실행 권한 부여
RUN chmod +x gradlew
# 의존성 다운로드 (캐시 활용)
RUN ./gradlew dependencies --no-daemon
# 나머지 소스 코드 복사 (의존성 변경이 없으면 캐시가 유지됨)
COPY src ./src
# --- 네이티브 이미지 빌드 ---
# GraalVM을 사용하여 정적 링크된 네이티브 바이너리 생성
RUN ./gradlew nativeCompile \
-Dorg.graalvm.nativeimage.imagecode=static \ # 완전 정적 링크 설정
--no-daemon \ # Gradle 데몬 비활성화 (컨테이너 환경에서 권장)
-Pnative # 네이티브 이미지 빌드 옵션 적용
# 2단계 (UPX 압축 단계) 제거됨
# 3단계: 최종 최소 컨테이너 이미지 생성
# scratch는 가장 작은 베이스 이미지 (필요한 파일만 포함)
FROM scratch
WORKDIR /
# 빌드된 네이티브 실행 파일을 최종 이미지로 복사
COPY --from=builder /app/build/native/nativeCompile/application /application
# 실행 명령어 설정 (별도의 셸 없이 실행)
ENTRYPOINT ["/application"]
728x90