BOOT-INF/lib/ 안에 의존성 jar를 중첩으로 품음 → 중첩 jar에서 클래스 로딩하는 약간의 startup 비용 발생-Djarmode=tools 시스템 프로퍼티로 jar를 도구 모드로 실행하면 내용물을 풀거나 레이어 정보를 조회java -Djarmode=tools -jar app.jar list-layers # 추출 가능한 레이어 목록
java -Djarmode=tools -jar app.jar extract # 기본 layout으로 압축 해제
java -Djarmode=tools -jar app.jar extract --layers --destination extracted # 레이어별로 분리 추출
tools jarmode는 구버전 layertools를 대체 (Spring Boot 3.3+) — 옛 튜토리얼의 -Djarmode=layertools를 봤다면 지금은 toolslib/로, app jar에는 클래스 + lib/를 참조하는 manifest만 남음java -jar app/app.jar # 추출된 디렉터리 구조에서 실행
extract --layers가 만드는 4개 기본 레이어 (먼저 COPY되는 것 = 변경 빈도 낮은 것부터)| 순서 | 레이어 | 내용 | 변경 빈도 |
|---|---|---|---|
| 1 | dependencies |
정식 릴리스 의존성 | 가장 낮음 → 최하단(캐시 재사용 극대화) |
| 2 | spring-boot-loader |
org/springframework/boot/loader 로더 클래스 |
거의 안 바뀜 |
| 3 | snapshot-dependencies |
SNAPSHOT 의존성 | 릴리스보다 자주 바뀜(분리해 릴리스 레이어 보호) |
| 4 | application |
앱 클래스·리소스(BOOT-INF/classes, manifest) |
가장 높음 → 최상단 |
layers.idx 파일이 “어떤 파일이 어느 레이어에 속하는지” 매핑을 정의 → 추출·이미지 빌드가 이 인덱스를 따름<!-- Maven: spring-boot-maven-plugin -->
<configuration><layers><enabled>true</enabled></layers></configuration>
// Gradle
bootJar { layered() }
extract --layers로 풀고, runtime 스테이지에서 레이어 디렉터리를 각각 COPY → COPY 한 줄당 Docker 레이어 1개FROM bellsoft/liberica-openjre-debian:25-cds AS builder
WORKDIR /builder
COPY target/*.jar application.jar
RUN java -Djarmode=tools -jar application.jar extract --layers --destination extracted
FROM bellsoft/liberica-openjre-debian:25-cds
WORKDIR /application
# 변경 빈도 낮은 레이어부터 COPY → 의존성 레이어는 캐시 재사용, 앱 코드만 바뀌면 마지막 레이어만 무효화
COPY --from=builder /builder/extracted/dependencies/ ./
COPY --from=builder /builder/extracted/spring-boot-loader/ ./
COPY --from=builder /builder/extracted/snapshot-dependencies/ ./
COPY --from=builder /builder/extracted/application/ ./
ENTRYPOINT ["java", "-jar", "application.jar"]
dependencies는 거의 안 바뀌므로 push/pull 시 변경된 레이어만 전송, 이미지 빌드도 빨라짐-XX:AOTCacheOutput/-XX:AOTCache), 이전은 CDS(-XX:ArchiveClassesAtExit/-XX:SharedArchiveFile)./gradlew bootBuildImage # Gradle
mvn spring-boot:build-image # Maven
layers.idx를 반영 → 위 레이어드 JAR 커스터마이징이 빌드팩 이미지에도 그대로 적용spring.web.resources.cache.use-last-modified=false # 정적 리소스가 last-modified에 의존하지 않도록
| 기준 | Dockerfile + layered jar | Cloud Native Buildpacks |
|---|---|---|
| Dockerfile 관리 | 직접 작성·유지 | 불필요(빌드 명령만) |
| 베이스 이미지·JRE 제어 | 완전 제어(원하는 base 지정) | buildpack이 자동 선택 |
| 빌드 진입점 | docker build |
bootBuildImage / build-image |
| 적합 | 세밀한 커스터마이징·기존 Docker 파이프라인 | 표준화·빠른 시작·Dockerfile 보일러플레이트 제거 |