스프링 부트 도커에 올리기(Dockerizing Spring Boot App)
이전 포스트 도커(Docker) 설치하기에서 도커가 무엇인지 간략하게 알아보고 도커를 설치했다. 이번 포스트에서는 실제 프로젝트를 이용해 도커 이미지를 만들고 도커 위에 컨테이너를 실행시켜 보도록 한다. 도커 이미지를 만들 프로젝트는 스프링부트 웹 어플리케이션 프로젝트이다.
목차
- Dockerfile
- Docker build
- Docker run
Dockerfile
첫번째로 도커가 이해 할 수 있는 Dockerfile이라는 것을 만들어 줘야 한다. 이 파일에 필요한 디펜던시 예를들어 우리와 같은 경우 어떤 자바를 사용 할 것인지, 어떤 어플리케이션(.jar)를 사용 할 것인지, 어떤 명령어로 이 도커 컨테이너를 실행시켜야 되는지에 대해 명시해야 한다.
일단 프로젝트 root 디렉토리에 Dockerfile을 만들자.
Dockerfile의 내부는 다음과 같다.
# Start with a base image containing Java runtime
FROM java:8
# Add Author info
LABEL maintainer="f.softwareengineer@gmail.com"
# Add a volume to /tmp
VOLUME /tmp
# Make port 8080 available to the world outside this container
EXPOSE 8080
# The application's jar file
ARG JAR_FILE=build/libs/MySpringApp-0.0.1-SNAPSHOT.jar
# Add the application's jar to the container
ADD ${JAR_FILE} to-do-springboot.jar
# Run the jar file
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/to-do-springboot.jar"]
Dockerfile은 명령어들로 구성되어있다. 예를들어서, 아래는 이 스프링 부트 앱이 java 8위에서 실행된다는 뜻이다.
FROM java:8
Label은 말 그대로 라벨이다. maintainer를 추가해 이 이미지를 관리하는 사람이 누구인지 명시했다.
LABEL maintainer="f.softwareengineer@gmail.com"
이제 VOLUMN이라는 디렉토리를 지정 해 준다. 이 디렉토리 /tmp아래에 이 컨테이너가 필요한 여러가지 데이터를 저장하는 곳이다.
VOLUME /tmp
이 웹 어플리케이션은 도커 컨테이너 내부에서는 8080의 포트를 가지고 돌 것이다. 따라서 이 포트를 외부로 노출시킨다.
EXPOSE 8080
ARG JAR_FILE을 이용해 어떤 어플리케이션을 실행시켜야 하는지, 즉 어플리케이션의 실행파일을 연결 해 주어야한다. 우리가 gradle build를 하면 .jar파일이 생성된다. 내 환경에서는 build/libs/아래에 생성되었다. 프로젝트의 환경에 따라 tartget아래에 생성되기도 하도 build아래에 생성되기도 한다. 어쨌든 프로젝트를 빌드 후 .jar파일을 찾아 그 경로를 확인하는게 중요하다. 경로를 확인했으면 경로를 적어주자. 주의 할 점은 상대경로를 적어주어야 한다는 것이다. 안그러면 다른 팀원의 개발환경에서는 실행되지 않을 수 있다.
ARG JAR_FILE=build/libs/MySpringApp-0.0.1-SNAPSHOT.jar
이제 이 JAR_FILE에 이름을 붙여준다. 이름은 to-do-springboot.jar이다.
ADD ${JAR_FILE} to-do-springboot.jar
여기까지 완료되었다면 어플리케이션을 실행시키기 위한 초석을 마련한 것이다. 이제 어플리케이션을 실행시키기 위한 명령어를 쓰자.
ENTRYPOINT ["java","-Djava.security.egd=file:/dev/./urandom","-jar","/to-do-springboot.jar"]
ENTRYPOINT가 바로 자바를 실행시키는 것이다. 이 부분에 들어가는 명령어들은 실제 명령어를 스페이스로 나눠놓은 것과 같다. 즉, 우리가 직접 실행 시킬 때는 아래처럼 실행 시킬 것을 그냥 따로따로 리스트로 하나씩 주는 것이다.
➜ java -Djava.security.edg=file:/dev/./urandom -jar /to-do-springboot.jar
Docker build
이제 작성한 도커파일로 도커 이미지를 만들어야 한다. 도커 이미지를 만드는 명령어는 간단하다. Dockerfile이 존재하는 디렉토리 아래에서 실행시켜야 한다는 것을 명심하라.
<Dockerfile이 있는 프로젝트의 ROOT 디렉토리>
➜ docker build -t to-do-springboot .
Sending build context to Docker daemon 47.33MB
Step 1/7 : FROM java:8
8: Pulling from library/java
5040bd298390: Downloading 13.59MB/51.36MB
fce5728aad85: Downloading 4.865MB/18.54MB
76610ec20bf5: Downloading 5.549MB/42.5MB
60170fec2151: Waiting
e98f73de8f0d: Waiting ... Successfully built 9e5f29ac40ed Successfully tagged to-do-springboot:latest
위와같은 메시지로 Successfully tagged...로 끝나면 완료 된 것이다.
Docker run
이제 도커 이미지가 제대로 만들어 졌는지 확인 해 보자. docker images로 현재 이미지를 확인 해 보면 to-do-springboot와 스프링 부트가 사용할 java이미지가 생긴 것을 확인 할 수 있다.
➜ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
to-do-springboot latest 9e5f29ac40ed 2 minutes ago 672MB
java 8 d23bdf5b1b1b 2 years ago 643MB
이제 도커이미지를 이용해 도커 컨테이너를 실행 해 보자.
➜ docker run -p 5000:8080 to-do-springboot
이렇게 하면 gradle bootRun을 실행시켰던 것과 같은 로그화면이 뜨기 시작 할 것이다. 여기서 5000:8080에 대해 잠깐 보자. 아까 우리는 도커파일에서 8080을 노출시켰다. 만약에 내가 to-do-springboot말고 다른 웹 앱을 실행시키고 싶다면 그 앱도 로컬환경에서 8080을 사용 할 수 있다. 이 때 같은 포트를 사용하는 앱을 한 서버에서 실행시키면 port가 중복되어 에러가 난다. 그렇다면 내 환경에서는 8080에 실행시키고, 도커에서는 다른 포트에서 실행 시킬 수 있을까? 그럴 때 사용하는게 바로 5000:8080 Porter이다. 이 뜻은 내부적으로는 이 어플리케이션이 8080을 사용하고 있으니 5000으로 날아오는 포트는 전부 이 어플리케이션의 8080포트에 맵핑시켜라 라는 뜻이다. 이렇게 하면 개발 당시에는 8080을 사용하고, 개발 후 도커에 올리고 나서는 5000포트를 이용 할 수 있다는 장점이 있다.
브라우저를 켜서 http://localhost:5000/todo/ (이거는 사용한 프로젝트마다 다를 것이므로 프로젝트가 제공하는 API로 테스팅을 해보면 된다.)에 들어간다. 네트워크탭(F12)를 열어 보면 웹 앱이 제대로 실행 된 것을 확인 할 수 있다.
끝
이번 포스트를 통해 스프링 부트를 도커에 올리는 법을 알아보았다. 계획은 스프링 부트랑 몽고디비를 함께 올리는 것이므로 이후의 포스트에서는 몽고디비를 도커에 올리고 스프링부트를 연결하는 방법에 대해서 포스팅 해 보겠다.