- 컨테이너 이미지(Container Images)
- 12.1. 효율적인 컨테이너 이미지(Efficient Container Images)
- 12.1.1. 도커 이미지 계층(Layering Docker Images)
- 12.2. 도커파일(Dockerfiles)
- 12.3. 클라우드 네이티브 빌드팩(Cloud Native Buildpacks)
- 12.4. 다음에 읽을 내용(What to Read Next)
- 12.1. 효율적인 컨테이너 이미지(Efficient Container Images)
12. 컨테이너 이미지(Container Images)
스프링 부트 애플리케이션은 도커파일(Dockerfile)
을 사용하거나 Cloud Native Buildpack
을 사용하여 어디서나 실행할 수 있는 최적화된 도커 컨테이너 이미지를 생성하여 컨테이너화할 수 있다.
12.1. 효율적인 컨테이너 이미지(Efficient Container Images)
스프링 부트 fat jar를 도커 이미지로 패키징하는 것은 쉽다. 그러나 도커 이미지에서와 같이 fat jar를 복사하고 실행하는 데 여러 단점이 있다. 언패킹(unpacking)을 없이 Fat Jar를 실행하는 경우 항상 일정량의 오버헤드가 발생하며, 컨테이너화된 환경에서는 이것이 눈에 띄게 나타날 수 있다. 또 다른 문제는 애플리케이션의 코드와 모든 의존성을 도커 이미지의 한 레이어에 배치하는 것이다. 사용하는 스프링 부트 버전을 업그레이드하는 것보다 코드를 더 자주 재컴파일할 수 있으므로 항목을 좀 더 분리하는 것이 더 나은 경우가 많다. 애플리케이션 클래스 이전 계층에 jar 파일을 배치하는 경우 도커는 맨 아래 계층만 변경하면 되고 캐시에서 다른 계층을 선택할 수 있는 경우가 많다.
12.1.1. 도커 이미지 계층화(Layering Docker Images)
최적화된 도커 이미지를 더 쉽게 생성할 수 있도록 스프링 부트는 jar에 계층 인덱스 파일 추가를 지원한다. 이는 계층 목록과 그 안에 포함되어야 하는 jar를 제공한다. 인덱스의 계층 목록은 계층이 Docker/OCI 이미지에 추가되어야 하는 순서에 따라 정렬된다. 기본적으로 다음 계층이 지원된다.
- 의존성(dependencies) (정기적으로 릴리스된 의존성의 경우)
- spring-boot-loader (org/springframework/boot/loader 아래의 모든 항목에 대해)
- snapshot-dependencies (스냅샷 의존성)
- application (애플리케이션 클래스 및 리소스)
다음은layer.idx 파일의 예를 보여준다.
- "dependencies":
- BOOT-INF/lib/library1.jar
- BOOT-INF/lib/library2.jar
- "spring-boot-loader":
- org/springframework/boot/loader/JarLauncher.class
- org/springframework/boot/loader/jar/JarEntry.class
- "snapshot-dependencies":
- BOOT-INF/lib/library3-SNAPSHOT.jar
- "application":
- META-INF/MANIFEST.MF
- BOOT-INF/classes/a/b/C.class
이 계층화는 애플리케이션 빌드 간 변경 가능성에 따라 코드를 분리하도록 설계됐다. 라이브러리 코드는 빌드 간 변경될 가능성이 적으므로, 라이브러리가 캐시의 계층을 재사용할 수 있도록 자체 계층에 배치된다. 애플리케이션 코드는 빌드 간 변경될 가능성이 높으므로 별도의 계층에 격리된다.
스프링 부트는 또한 layers.idx의 도움으로 war 파일에 대한 계층화를 지원한다.
메이븐의 경우 압축파일에 계층 인덱스를 추가하는 방법에 대한 자세한 내용은 패키징 계층 jar 또는 war 장을 참고하자. 그레이들의 경우 그레이들 플러그인 문서의 패키징 계층 jar 또는 war 장을 참고하자.
12.2. 도커파일(Dockerfiles)
도커파일에서 단 몇 줄만으로 스프링 부트 fat jar를 도커 이미지로 변환할 수 있지만, 레이어링 기능을 사용하여 최적화된 도커 이미지를 생성할 수 있다. 레이어 인덱스 파일을 포함하는 jar를 생성하면 spring-boot-jarmode-layertools
jar가 jar에 의존성으로 추가된다. 클래스패스에 있는 이 jar를 사용하면 부트스트랩 코드가 애플리케이션과 완전히 다른 작업(예: 레이어를 추출하는 작업)을 실행할 수 있도록 하는 특수 모드에서 애플리케이션을 시작할 수 있다.
layertools
모드는 시작 스크립트(launch script)를 포함하는 실행 가능한 스프링 부트 압축파일과 함께 사용할 수 없다. layertools
와 함께 사용하기 위한 jar 파일을 빌드할 때 시작 스크립트 구성을 비활성화해야 한다.
layertools
jar 모드를 사용하여 jar를 실행하는 방법은 다음과 같다.
$ java -Djarmode=layertools -jar my-app.jar
그러면 다음과 같이 출력된다.
Usage:
java -Djarmode=layertools -jar my-app.jar
Available commands:
list List layers from the jar that can be extracted
extract Extracts layers from the jar for image creation
help Help about any command
extract
명령을 사용하면 애플리케이션을 도커파일
에 추가할 계층으로 쉽게 분할할 수 있다. 다음은 jarmode
를 사용하는 도커파일 예제다.
FROM eclipse-temurin:17-jre as builder
WORKDIR application
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} application.jar
RUN java -Djarmode=layertools -jar application.jar extract
FROM eclipse-temurin:17-jre
WORKDIR application
COPY --from=builder application/dependencies/ ./
COPY --from=builder application/spring-boot-loader/ ./
COPY --from=builder application/snapshot-dependencies/ ./
COPY --from=builder application/application/ ./
ENTRYPOINT ["java", "org.springframework.boot.loader.JarLauncher"]
위의 도커파일(Dockerfile)이 현재 디렉토리에 있다고 가정하면 다음 예제와 같이 docker build .
를 사용하거나 선택적으로 애플리케이션 jar의 패스를 지정하여 도커 이미지를 빌드할 수 있다.
$ docker build --build-arg JAR_FILE=path/to/myapp.jar .
이것은 다단계 도커파일이다. 빌더 단계에서는 나중에 필요한 디렉토리를 추출한다. 각 COPY 명령은 jarmode
로 추출된 계층과 관련된다.
물론, jarmode
를 사용하지 않고도 도커파일을 작성할 수 있다. unzip
과 mv
의 조합을 사용하여 항목을 올바른 계층으로 이동할 수 있지만 jarmode
는 이를 단순화한다.
12.3. 클라우드 네이티브 빌드팩(Cloud Native Buildpacks)
도커파일은 도커 이미지를 빌드하는 한 가지 방법일 뿐이다. 도커 이미지를 빌드하는 또 다른 방법은 빌드팩을 사용하여 메이븐 또는 그레이들 플러그인에서 직접 만드는 것이다. Cloud Foundry
또는 Heroku
와 같은 애플리케이션 플랫폼을 사용해 본 적이 있다면 아마도 빌드팩을 사용해 본 적이 있을 것이다. 빌드팩은 애플리케이션을 가져와서 플랫폼이 실제로 실행할 수 있는 것으로 변환하는 플랫폼의 일부다. 예를 들어 Cloud Foundry
의 자바 빌드팩은 .jar
파일을 푸시하고 있음을 인식하고 관련 JRE를 자동으로 추가한다.
클라우드 네이티브 빌드팩을 사용하면 어디에서나 실행할 수 있는 도커 호환 이미지를 생성할 수 있다. 스프링 부트에는 메이븐과 그레이들 모두에 대한 빌드팩 지원이 직접 포함되어 있다. 즉, 명령 하나만 입력하면 로컬로 실행되는 도커 데몬에 적절한 이미지를 빠르게 가져올 수 있다.
메이븐 및 그레이들에서 빌드팩을 사용하는 방법에 대한 개별 플러그인 문서를 참고하자.
Paketo 스프링 부트 빌드팩도 layers.idx
파일을 지원하도록 업데이트되었으므로 여기에 적용되는 모든 커스텀이 빌드팩에서 생성된 이미지에 반영된다.
빌드 및 컨테이너 이미지 캐싱을 위해 빌드팩은 애플리케이션 리소스 메타데이터(예: 파일 “마지막 수정” 정보)를 조작할 수 있다. 애플리케이션이 런타임 시 해당 메타데이터에 의존하지 않는지 확인해야 한다. 스프링 부트는 정적 리소스를 제공할 때 해당 정보를 사용할 수 있지만 spring.web.resources.cache.use-last-modified
를 사용하여 비활성화할 수 있다.
12.4. 다음에 읽을 내용(What to Read Next)
효율적인 컨테이너 이미지를 구축하는 방법을 배운 후에는 쿠버네티스 같은 클라우드 플랫폼에 애플리케이션을 배포하는 방법을 읽을 수 있다.