[Gradle] bootBuildImage를 사용한 스프링부트 컨테이너 이미지 빌드
이멀젼씨
·2021. 11. 24. 20:27
목적
멀티 프로젝트 환경에서 간단하게 docker 이미지를 만들고 docker hub에 푸시하기 위함
목차
- Dockerfile을 이용하는 방법
- bootBuildImage를 사용하는 방법
- 사용 예시
1. Dockerfile을 이용하는 방법
기존에 컨테이너 이미지를 만들기 위해선 Dockerfile을 생성하고 필요한 속성들을 정의해야 했다.
FROM openjdk:11
EXPOSE 8080
ADD ./build/libs/*.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]
도커 이미지는 여러 레이어를 갖고 있어서 변경되지 않는 부분은 그대로 사용하고 변경되는 부분만 바꾸어 효율적인 사용이 가능했다.
하지만 별다른 설정 없이 Dockfile을 사용하는 방법은 이미지를 단일 레이어로 만들어버렸다.
이는 단 한 줄의 코드만 바꾸더라도 동일한 레이어로 취급되지 않아 코드부터 의존성 등 전체를 모두 새롭게 빌드해야 했다.
애플리케이션의 시작 시간을 늦추게 되는 원인이었다.
현재는 layered jar을 지원하여 Dockerfile을 사용하더라도 추가적인 설정을 통해 레이어별로 빌드가 가능하다.
2. bootBuildImage를 사용하는 방법
스프링부트 2.3부터 가능한 방법이다
Cloud Native Buildpack을 사용하여 명령어 한 번으로 알아서 이미지를 생성해준다.
Cloud Native Buildpack이란?
작성한 코드를 OCI 호환 컨테이너 이미지로 변환하는 도구로 소스 코드를 빌드하고 애플리케이션을 실행하는데 필요한 모든 의존성을 포함하는 컨테이너 이미지로 만들어준다.
bootBuildImage 명령어는 애플리케이션에 맞는 설정을 바탕으로 레이어별로 나누어 이미지를 생성하게 되고, 수정된 부분만 다시 빌드하게 된다.
그래서 빌드가 굉장히 빠르게 진행된다.
https://spring.io/blog/2020/01/27/creating-docker-images-with-spring-boot-2-3-0-m1
3. 사용 예시
bootBuildImage의 추가 설정을 통해 이미지 빌드 후 도커 허브에 push까지 가능하다.
kubernetes와 연동한다면 도커 허브의 webhook을 사용하여 현재 Pod내부에서 실행중인 컨테이너들을 업데이트 할 수 있다.
bootBuildImage명령어를 사용하기 위해선 도커 데몬에 접근이 필요하다.
도커 데몬이 local과 remote 둘 다 가능하나 필자는 local에서 테스트를 진행해보겠다.
local은 도커 데몬 연결에 별다른 설정이 필요하지 않다.
우선 이미지 빌드는 bootBuildImage명령어만 사용하면 된다.
./gradlw bootBuildImage
명령어 하나로 간단하게 빌드가 진행되며 레이어를 재사용 하는 것을 볼 수 있다.
이미지 빌드 후 도커 허브에 push를 하고 싶다면 아래의 내용을 추가해주면 된다.
bootBuildImage {
imageName = docker_id + "/${project.name}"
publish = true
docker {
publishRegistry {
username = docker_id
password = docker_pw
}
}
}
publish옵션을 true로 설정해주고 도커 허브에 접근할 수 있도록 아이디와 비밀번호를 정의해준다.
하드코딩으로 하려면 usename과 password에 큰따옴표를 넣은 문자열을 넣어주면 되겠고, 아이디와 비밀번호 노출이 안되려면 gradle 변수로 넘겨주면 된다.
위와같이 username와 password부분에 gradle 명령줄로 넘겨줄 변수 명을 정의해준다.
bootBuildImage를 할때 아래와 같이 넘겨주면 알아서 push가 된다.
./gradlew bootBuildImage -Pdocker_id=myid -Pdocker_pw=mypw
push할때 주의할 점은 imageName과 도커 허브 repository이름이 일치해야 한다.
보통 도커 허브에서 repository를 만들면 "id / repository이름" 과 같은 형식으로 생성된다.
따라서 imageName에는 gradle 명령줄 변수로 입력받는 docker_id와 settings.gradle의 rootProjectname에 해당하는 proejct.name을 도커 허브 repository네임과 일치시켜 주어야 정상적으로 push가 된다.