안녕세계

[SpringBoot] Docker 컨테이너 배포 (with. Gradle) 본문

Infra/Docker

[SpringBoot] Docker 컨테이너 배포 (with. Gradle)

Junhong Kim 2020. 1. 5. 22:58
728x90
반응형

SpringBoot 앱을 개발환경(Development/Production)을 나누어 배포하는 방법에 대해 알아봅니다 🤩

(본 포스팅에서는 SpringBoot + Gradle + Docker를 사용합니다.)

 

1. Spring Initializr에서 dependency로 Spring Web만 추가하여 Gradle Project를 생성합니다.

Project Structure

 

2. application.properties를 application.yaml 파일로 변경후 application-{profile}.yaml 형식의 파일을 생성합니다.

(properties 파일을 선호하는 경우 변경하지 않아도 됩니다.)

개발환경별 yaml 파일 생성

 

3. application-dev.yaml과 application-prod.yaml 파일은 개발환경과 운영환경의 셋팅을 달리하기 위함입니다.

각 파일에 spring.profiles.active에 활성화할 profile명을 다음과 같이 설정합니다.

# application-dev.yaml
spring:
  profiles:
    active: dev
# application-prod.yaml
spring:
  profiles:
    active: prod

 

 

여기까지 진행하셨다면 SpringBoot에서 할 일은 끝났습니다. 😎

자! 그럼 Docker 컨테이너를 개발환경별로 배포하기 위해 프로젝트 최상위 디렉토리에 Dockerfile을 생성합시다.

프로젝트 최상위에 Dockerfile 생성

 

4. Dockerfile에 Multi-Stage Build를 사용하는 다음 코드를 작성합니다.

FROM adoptopenjdk:8-jdk-hotspot AS builder # 베이스 이미지 + 이미지 별칭
COPY gradlew . # gradlew 복사
COPY gradle gradle # gradle 복사
COPY build.gradle . # build.gradle 복사
COPY settings.gradle . # settings.gradle 복사
COPY src src # 웹 어플리케이션 소스 복사
RUN chmod +x ./gradlew # gradlew 실행권한 부여
RUN ./gradlew bootJar # gradlew를 사용하여 실행 가능한 jar 파일 생성

FROM adoptopenjdk:8-jdk-hotspot # 베이스 이미지
COPY --from=builder build/libs/*.jar app.jar # builder 이미지에서 build/libs/*.jar 파일을 app.jar로 복사

EXPOSE 8080 # 컨테이너 Port 노출
ENTRYPOINT ["java","-jar","/app.jar"] # jar 파일 실행

 

5. 작성한 도커파일을 빌드하고 실행해봅시다.

# Dockerfile 이미지 빌드
$ docker build -t deploy-test:0.0.1 .

 

# Docker 컨테이너 실행
$ docker run -d -p 8080:8080 deploy-test:0.0.1

 

6. http://localhost:8080으로 접속하여 다음 페이지가 출력되면 정상입니다.

(profiles를 명시하지 않았기 때문에 기본적으로 application.yaml 설정 파일을 읽습니다.)

정상적으로 컨테이너가 실행되었을 때 보이는 페이지

 

7. SampleController개발환경별 변수(sample.value)를 다르게하여 로컬에서 실행해봅니다.

// SampleController.java
@RestController
@RequestMapping("/sample")
public class SampleController {

    @Value("${sample.value}")
    private String sample;

    @GetMapping
    private String getSample() {
        return sample;
    }
}
# application.yaml
sample:
  value: default
# application-dev.yaml
spring:
  profiles:
    active: dev

sample:
  value: dev
# application-prod.yaml
spring:
  profiles:
    active: prod

sample:
  value: prod

 

>> 다음 명령어를 사용하면 환경변수에 따라 application-{profile}.yaml 파일이 읽히는 것을 확인할 수 있습니다.

(http://localhost:8080/sample 페이지에서 default가 찍히는 것을 확인합니다.)

# 실행가능한 jar 파일 빌드
$ ./gradlew bootJar

# jar 파일 실행시 application-dev.yaml 파일을 읽도록 한다.
$ java -Dspring.profiles.active=dev -jar build/libs/*.jar

 

[2021.03.21 updated]

2.4.x 이후부터 기존 spring.profiles.active가 deprecated 되었습니다.

기존 spring.profiles.active 를 사용하여 jar 파일 실행시 다음에러가 발생하는 것을 확인했습니다. 

Property 'spring.profiles.active' imported from location 'class path resource [application-dev.yml]' is invalid in a profile specific resource ...

 

spring.config.active.on-profile로 변경하면 정상동작하니, SpringBoot 2.4.x 버전은 다음과 같이 변경해주세요.

(config 파일 관련해서 한 번 정리해야겠네요 ㅠ)

# application-dev.yaml
spring:
  config:
    activate:
      on-profile: dev
sample:
  value: dev

---

# application-prod.yaml
spring:
  profiles:
    active: prod

sample:
  value: prod

 

8. 위와 같은 작업을 Dockerfile에서는 --build-arg 옵션을 사용하여 가능합니다.

>> 우선 Dockerfile이 argument를 받아서 profile을 설정할 수 있도록 다음과 같이 변경합니다.

FROM adoptopenjdk:8-jdk-hotspot AS builder
COPY gradlew .
COPY gradle gradle
COPY build.gradle .
COPY settings.gradle .
COPY src src
RUN chmod +x ./gradlew
RUN ./gradlew bootJar

FROM adoptopenjdk:8-jdk-hotspot
COPY --from=builder build/libs/*.jar app.jar


# ENVIRONMENT라는 이름의 argument를 받을 수 있도록 설정
ARG ENVIRONMENT
# argument로 받은 ENVIRONMENT 값을 SPRING_PROFILES_ACTIVE에 적용
ENV SPRING_PROFILES_ACTIVE=${ENVIRONMENT}

EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]

 

>> argument를 받을 설정이 완료되었으면 이미지를 다시 빌드하고 컨테이너를 실행합니다.

(http://localhost:8080/sample 페이지에서 dev가 찍히는 것을 확인합니다.)

# ENVIRONMENT argument를 넘겨서 이미지 빌드
$ docker build --build-arg ENVIRONMENT=dev -t deploy-dev:0.0.1 .

# 컨테이너 실행
$ docker run -d -p 8080:8080 deploy-dev:0.0.1

 

이로써 SpringBoot에서 Profiles를 활용하여 개발환경을 구분하고,

Dockerfile에서 원하는 환경으로 이미지를 빌드하는 방법에 대해 알아보았습니다. 🥰

 

참고

https://wfreud.tistory.com/277

https://blusky10.tistory.com/404

https://docs.docker.com/develop/develop-images/multistage-build/

반응형
0 Comments
댓글쓰기 폼