SW 개발/Spring
Spring Boot, Docker 이미지 빌드하기
지단로보트
2020. 11. 10. 10:16
개요
- 이번 글에서는 Spring Boot 기반 애플리케이션을 Docker 이미지로 빌드하는 방법을 소개하고자 한다.
사전 참고할만한 글
Docker 이미지 빌드 및 실행
- 아래는 가장 일반적인 방법의 Docker 이미지 빌드 및 실행 방법이다.
### 애플리케이션 빌드
$ ./gradlew build
# Dockerfile 생성
$ nano Dockerfile
FROM amazoncorretto:17 # FROM public.ecr.aws/bitnami/java:17-prod
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
ENV JAVA_OPTS=""
CMD java $JAVA_OPTS -server -jar app.jar
# Docker 이미지 빌드
$ docker build -t foo/bar .
# 빌드된 이미지 확인
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
foo/bar latest 422fb2d589f3 2 minutes ago 734MB
# Docker 컨테이너 실행
$ docker run -d -p 8080:80 foo/bar
9442d550adb3
# Docker 컨테이너 로그 확인
$ docker logs -f 9442d550adb3
# 실행 중인 Docker 컨테이너 목록 확인
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9442d550adb3 foo/bar "java -jar /app.jar" About a minute ago Up About a minute 0.0.0.0:8080->80/tcp elated_jackson
# 실행 중인 Docker 컨테이너 쉘 접속
$ docker exec -it 9442d550adb3 /bin/bash
bash-4.2#
# Docker 컨테이너 종료
$ docker stop 9442d550adb3
Spring Boot 2.3.x 플러그인으로 Docker 이미지 빌드
- Spring Boot 2.3부터 Gradle 플러그인으로 Docker 이미지 빌드를 지원한다. 로컬에 Docker 데몬 설치를 요구하며, Dockerfile 파일을 이용하지 않고 빌드한다.
# docker.io/foo/bar/latest 이름의 이미지를 빌드
$ gradlew bootBuildImage --imageName=foo/bar
# 멀티 프로젝트일 경우 특정 프로젝트의 이미지를 빌드
$ gradlew {project_name}:bootBuildImage --imageName=foo/bar
- 생성한 이미지에 대해 Docker 컨테이너 실행시 JAVA_OPTS 환경 변수를 아래와 같이 전달하여 실행할 수 있다.
# 컨테이너 실행
$ docker run -m 8g -d -p 8080:8080 --env JAVA_OPTS="-Xms512m -Xmx512m -Dspring.profiles.active=prod" foo/bar
{container_id}
# 실행 중인 컨테이너 쉘 접속
$ docker exec -it {container_id} sh
# 현재 uid
> id
uid=1000(cnb) gid=1000(cnb) groups=1000(cnb)
# 실행 중인 프로세스
> ps -ef
UID PID PPID C STIME TTY TIME CMD
cnb 1 0 8 06:53 ? 00:00:11 java org.springframework.boot.loader.JarLauncher
- 플러그인으로 빌드된 컨테이너를 실행하면 별도의 CMD를 정의하지 않아도 Spring Boot 애플리케이션이 자동으로 실행된다.
트러블슈팅: 컨테이너 파일 생성시 한글 파일명 깨짐 문제
- 애플리케이션에서 빌드된 컨테이너 런타임에서 파일 저장시 파일명에 한글을 포함한 CJK 계열 문자열이 포함될 경우 ???와 같이 문자열이 깨지는 이슈를 있어 유의해야 한다.
- 원인은 도커 컨테이너 이미지의 기본 로케일이
POSIX
로 설정되어 있기 때문인데 이를C.UTF-8
로 수정하면 해결된다. 수정 방법은 도커 컨테이너 실행시 전달되는 환경 변수에 아래 항목을 추가하면 된다. [관련 링크]
LC_ALL=C.UTF-8
AWS에서의 Docker 이미지 배포 전략
- 생성한 Docker 이미지를 AWS 생태계에 배포하여 서비스를 운영하는 방법에는 2가지가 있다. 2가지 경우 모두, 사전 조건으로
Amazon ECR
에 리파지터리를 생성하고 빌드한 이미지를 푸시해야 한다. - 첫째, EC2 인스턴스를 생성하고 Docker 컨테이너를 직접 운영하는 것이다. 오토 스케일링은 EC2의 기능을 이용하게 되며 인스턴스 관리를 직접 해야 하는 부담이 있다.
- 둘째,
AWS Fargate
에서 푸시한 이미지를 기반으로 태스크를 생성하는 것이다. 완전한 매니지드 서비스로 관리할 수 있는 장점을 가진다. 이 경우AWS CloudFormation
또는Terraform
도구를 이용하여 완전한 코드에 의한 인프라 관리(IaS)가 가능하다.
Amazon ECR에 이미지 푸시
Amazon ECR
은 AWS가 제공하는 프라이빗 도커 레지스트리 상품이다. 개인적으로 또는 상업적인 목적으로 생성한 이미지를 자유롭게 push/pull할 수 있다.- Docker 이미지를 푸시하려면 먼저 리파지터리가 생성되어야 한다. 생성된 리파지터리에는 태그 단위로 여러 버전의 이미지를 푸시할 수 있다. 리파지터리 생성 방법은 아래와 같다.
Amazon ECR 콘솔 접속 → [리포지토리 생성] 클릭
→ 리포지토리 이름: foo/bar
→ [리포지토리 생성] 클릭
- 생성된 리파지터리에 Docker 이미지를 푸시하는 방법은 아래와 같다.
# Amazon ECR 로그인 비밀번호 획득
$ aws ecr get-login-password --region ap-northeast-2
{login-password}
# 앞서 획득한 비밀번호를 이용하여 Docker 리파지터리 로그인
$ docker login -u AWS -p {login-password} xxxxx.dkr.ecr.ap-northeast-2.amazonaws.com
Login Succeeded
# ECR에 푸시할 이미지 태그를 지정하고, 생성한 리파지터리를 연결
$ docker tag foo/bar:latest xxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/foo/bar
# ECR에 생성한 리파지터리에 이미지를 푸시
$ docker push xxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/foo/bar
AWS Fargate로 Docker 이미지 기동
- 앞서 푸시한 Docker 이미지는 다양한 방식으로 온전한 애플리케이션의 형태로 기동이 가능하다. 최근 AWS 생태계에서 가장 선호되는 방식은
AWS Fargate
를 이용하여 완전한 매니지드 형태로 애플리케이션을 서비스하고 관리하는 것이다. 자세한 내용은 이 글을 참고한다.