Spring Boot Application 을 Dockerize 하기

#springboot#DOCKER

2022-11-20 13:19

대표 이미지

SpringBoot 앱을 도커로 만드는 다양한 방법을 알아봅니다. 프로젝트에 즉시 적용할 수 있는 예시도 함께 제공합니다. 쉽고 빠르게 적용해보세요.

Spring Boot 를 Dockerize 하려면


개발을 하다 보면, 내가 만든 애플리케이션을 Docker 이미지로 빌드해야 할 일이 한 번씩 찾아오게 된다. 이유는 다양하다.

  • 회사 내의 환경이 컨테이너 기반 환경이거나
  • 여러 환경에서 동일한 조건으로 실행하고 싶거나
  • 그냥 편해서 😂
  • 기타 등등

전통적인 도커 빌드 방법은 Dockerfile을 이용하는 방법인데, 여러가지 커스터마이징이 가능하지만 많은 단점이 있으며 실제 Dockerfile을 작성해보면 한번에 끝나는 일이 드물 것이다. 한마디로 쉽지 않다. 그래서, 비교적 손쉽게 Docker 이미지를 빌드할 수 있는 방법 두 가지를 소개하고자 한다. 여기서는 Spring Boot Application의 이미지 빌드만을 다룬다.

bootBuildImage 를 이용한 dockerize


Spring boot 2.3 버전 이상부터 가능. 빌드가 수행되는 곳에 Docker가 설치되어 있어야 한다.

2020년 5월, Spring Boot 2.3의 New feature로써 추가되어 릴리즈되었다. Cloud Native Buildpack을 이용하여 Docker 이미지를 빌드하며, Spring Boot 플러그인에는 Maven과 Gradle 모두에 대한 직접적인 빌드팩 지원이 포함되어 있다.

// build.gradle
...
plugins {
    ...
    id 'org.springframework.boot' version '2.7.2'
    ...    
}
...

Buildpack을 이용한 Docker 이미지 빌드와 다른 방법과의 비교

image-20221013-101106.png

  • 도커 이미지는 Layer 구조로 되어 있고, 애플리케이션의 코드가 수정됐을 경우 Buildpack을 통해 이미지를 빌드하면 수정된 부분(application)의 Layer만 빌드하여 빠른 생성이 가능하다.
  • Dockerfile의 경우 Layer 구조를 활용하려면 애플리케이션의 각 디펜던시를 나누는 복잡한 설정을 거쳐야 하나, Buildpack이 jar를 분석하여 layer를 자동으로 나누어 준다.
  • 이미지 생성을 위해 간단한 API를 가진 Spring Boot 프로젝트를 하나 만들어보자.
  • 코드는 다음 Github에 있다 샘플 코드
...

@RestController
@RequestMapping("/hello")
public class HelloController {
    @GetMapping
    public String hello() {
        return "hello";
    }
}

Gradle에 docker 설정하기

  • Plugin을 통해 Gradle Task에 bootBuildImage가 추가되어 있을 것이다.

image-20221014-065532.png

./gradlew <모듈명>:bootBuildImage --imageName=<이미지명>:<이미지버전>
  • 컨테이너 실행 시 JAVA_OPTS 형태로 옵션을 지정할 수 있다.

docker run으로 실행하기

docker run --name simple_server -d -p 9091:9091 \
--env JAVA_OPTS="-Dspring.profiles.active=local" \
simple_server:0.0

docker-compose 로 한번에 실행하기

version: '2'
services:
  simpleAPIServer:
    image: simple_server:0.0
    environment:
      - JAVA_OPTS=-Dspring.profiles.active=local
    ports:
      - 9091:9091

Maven 으로 docker 설정

  • 이미지 빌드
./mvnw spring-boot:build-image -DskipTests -Dspring-boot.build-image.imageName=<이미지명>:<이미지버전>
  • 컨테이너 실행 시 JAVA_OPTS 형태로 옵션을 지정할 수 있다.
  • 예시 (docker-compose)
version: '3.9'
services:
  simpleAPIServer:
    image: simple_server-web:1.0
    environment:
      - JAVA_OPTS=-Dspring.profiles.active=dev
    restart: unless-stopped
    ports:
      - 8080:8080

Jib 라이브러리로 dockerize 하기


로컬에 Docker 데몬이 없어도 이미지 빌드가 가능하다. Gradle 플러그인의 경우 Gradle 버전 5.1 이상 필요

  • 도커 데몬 없이 자바 애플리케이션을 도커 이미지로 빌드하기 위한 플러그인. 자바만 가능!
  • bootBuildImage와 비슷하게 Layer 구조인 도커 이미지 빌드에 변경사항만 빌드하기 때문에 속도는 빠르다.
  • creationTime 옵션을 줄 경우 Created 시간이 제대로 표시됨.

Gradle 에 Jib 설정 추가하기

  • build.gradle에 플러그인 설정. 2022년 8월 30일 기준 Latest는 3.2.1
plugins {
    ...
    id 'com.google.cloud.tools.jib' version '3.2.1'
    ...
}
...
subprojects {
    ...
    apply plugin: 'com.google.cloud.tools.jib'
    ...
}
  • build.gradle에 jib 관련 config 추가
jib {
    from {
        image = "adoptopenjdk/openjdk11:x86_64-alpine-jdk-11.0.11_9"
    }
    to {
        image = "my_docker_registry/simple_server"
        tags = ["latest"]
    }
    container {
        creationTime = "USE_CURRENT_TIMESTAMP"
        jvmFlags = ['-Dspring.profiles.active=local', '-XX:+UseContainerSupport', '-Dfile.encoding=UTF-8']
        ports = ['9091']
        labels = [maintainer: "simple<simple@gmail.com>"]
    }
}
  • from{}에 설정될 base 컨테이너 이미지는 가급적 가벼워야 하니 alpine 버전이 좋고, 컨테이너 내부에서 빌드를 할 게 아니면 jdk까지 필요없다.
  • 빌드 with 로컬 도커 데몬
./gradlew jibDockerBuild
  • 로컬 도커 데몬 없이 빌드
./gradlew jib
  • 빌드와 동시에 도커 허브 / 도커 레지스트리에 이미지가 Push된다.
  • 따라서 빌드 전에 docker login을 통해 ~/.docker/config.json에 credential을 저장해 두어야 한다.

Maven 에 Jib 설정 추가하기

  • pom.xml 플러그인 설정.
<plugins>
  ...
  <plugin>
    <groupId>com.google.cloud.tools</groupId>
    <artifactId>jib-maven-plugin</artifactId>
    <version>3.2.1</version>
    <configuration>
      <to>
        <image>myimage</image>
      </to>
    </configuration>
  </plugin>
  ...
</plugins>
  • gradle과 마찬가지로 xml 문법을 통해 config 할 수 있다.
  • 빌드 with 로컬 도커 데몬
    • ./mvnw compile jib:dockerBuild
    • 로컬에 docker image 추가
  • 로컬 도커 데몬 없이 빌드
    • ./mvnw compile jib:build
    • gradle과 동일하게, 빌드와 동시에 도커 허브 / 도커 레지스트리에 이미지가 Push

Ref


bootBuildImage

Jib