Docker에 Spring Boot 프로젝트 띄우기

develemon·2023년 9월 22일

Docker

목록 보기
1/1
post-thumbnail

Intro


해당 실습은 인프런 강의 <스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술>을 통해 구현한 회원 관리 애플리케이션을 Docker에 띄우는 것이다. 실습의 주요 내용은 Spring Boot가 아닌 Docker 연동이므로 여기서는 Docker에 대한 내용을 위주로 다룬다. 우선 구현 결과물 (Docker에 Spring Boot 프로젝트 띄우기)은 링크를 클릭하면 확인이 가능하다. 여기서 함께 알아볼 내용은 이미지 빌드를 위한 Dockerfile, 그리고 빌드된 이미지를 통해 도커를 실행할 docker-compose.yaml 파일이다.

Docker Image


도커 컨테이너를 띄우기 위해서는 그에 해당하는 이미지가 필요하다. 그리고 도커 이미지는 다른 이미지를 레이어 형식으로 불러와 원하는 형태를 구성할 수 있다. 아래 Dockerfile 내용을 보면 openjdk:11-jdk-slim과 openjdk:11-jre-slim이 레이어로 구성된 것이다.

# BUILD stage

FROM openjdk:17-jdk-slim AS builder

WORKDIR /workspace/app

COPY gradle gradle
COPY build.gradle settings.gradle gradlew ./
COPY src src

RUN ./gradlew bootJar
RUN mkdir -p build/libs/dependency && (cd build/libs/dependency; jar -xf ../*.jar)

# RUN stage

FROM openjdk:17-jdk-slim

VOLUME /tmp

ARG DEPENDENCY=/workspace/app/build/libs/dependency

COPY --from=builder ${DEPENDENCY}/BOOT-INF/lib /app/lib
COPY --from=builder ${DEPENDENCY}/META-INF /app/META-INF
COPY --from=builder ${DEPENDENCY}/BOOT-INF/classes /app

ENTRYPOINT ["java", "-cp", "app:app/lib/*", "hello.hellospring.HelloSpringApplication"]코드를 입력하세요

그리고 위 Dockerfile의 내용을 분석하자면, 우선 FROM 절을 기준으로 빌드 스테이지(Build-Stage)와 런 스테이지(Run-Stage)로 나뉘게 된다. 이렇게 여러 스테이지로 구성된 형식을 멀티 스테이지(Multi-Stage)라고 한다. 그리고 각 스테이지는 각각의 컨테이너를 구성하게 되며, 특히 빌드 스테이지의 경우에는 임시 컨테이너로 생성되었다가 이미지를 만들고서는 런 스테이지로 넘어갈 때 사라지게 된다. 그래서 빌드 스테이지의 내용으로 빌드된 이미지로 구현된 컨테이너에 스프링 프로젝트를 빌드하는 데에 필요한 파일들과 빌드하면서 생기는 파일들을 구분된 디렉토리에 저장해주고서 런 스테이지에서는 COPY 절을 통해 필요한 파일들이 있는 경로를 호출하여 지정 디렉토리에 복사하게 된다.

그리고 런 스테이지에서 VOLUME /tmp를 하는 이유는 애플리케이션이 동작하는 데 필요한 일을 /tmp 폴더에서 참조하기 위함이다.

> docker build -t <원하는 이미지 이름> <빌드할 디렉토리>

위 Dockerfile을 빌드하려면 Dockerfile이 위치한 곳에서 터미널을 열어 위 명령어를 실행시켜주면 된다. 빌드된 이미지는 도커허브(docker.io)에 ypwa121/hellospring으로 push하였다.

"docker-compose up"


빌드된 이미지를 컨테이너로 실행시키려면 터미널에 다음과 같은 명령어를 입력해야 한다.

> docker run -d -p <출입 포트>:<출구 포트> --name <지정할 컨테이너 이름> <이미지 이름>

그러나 매번 실행할 때마다 위와 같이 긴 명령어를 입력하는 것은 많이 불편할 수 있다. 따라서 docker-compose.yml이라는 파일을 별도로 구성하여 아래와 같은 명령어로 쉽게 실행시킬 수 있다.

> docker-compose up

그렇다면 docker-compose.yml에는 어떠한 내용이 들어갈까.

version: "3"
services:
  db:
    container_name: h2
    image: oscarfonts/h2:latest
    ports:
      - 1521:1521
      - 8081:81
    environment:
      H2_OPTIONS: -ifNotExists
    volumes:
      - ./h2/:/opt/h2-data
    restart: always
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: hellospring
    ports:
      - 5000:8080
    environment:
      SPRING_DATASOURCE_URL: jdbc:h2:tcp://h2:1521/demo
      SPRING_DATASOURCE_USERNAME: sa
      SPRING_DATASOURCE_PASSWORD:
      SPRING_JPA_HIBERNATE_DDL_AUTO: create
    depends_on:
      - db

version과 services를 적어주면 되는데, 이때 애플리케이션은 Spring Boot와 H2 Database 두 개의 컨테이너를 띄워야 한다. 각각의 컨테이너는 그 이름과 이미지 경로(또는 빌드할 파일 경로), 포트, 그리고 환경변수가 필요하다. 애플리케이션을 사용하고자 한다면 localhost:5000에 접속해주면 된다.

실행 화면


터미널 실행 화면

>docker-compose up
[+] Running 2/0
 ✔ Container h2           Created                                                                                  0.0s
 ✔ Container hellospring  Created                                                                                  0.0s
Attaching to h2, hellospring
h2           | TCP server running at tcp://172.19.0.2:1521 (others can connect)
h2           | Web Console server running at http://172.19.0.2:81 (others can connect)
hellospring  |
hellospring  |   .   ____          _            __ _ _
hellospring  |  /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
hellospring  | ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
hellospring  |  \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
hellospring  |   '  |____| .__|_| |_|_| |_\__, | / / / /
hellospring  |  =========|_|==============|___/=/_/_/_/
hellospring  |  :: Spring Boot ::               (v2.7.15)
hellospring  |
hellospring  | 2023-09-22 13:20:22.313  INFO 1 --- [           main] h.hellospring.HelloSpringApplication     : Starting HelloSpringApplication using Java 17.0.2 on d0fbdb1bf331 with PID 1 (/app started by root in /)
hellospring  | 2023-09-22 13:20:22.315  INFO 1 --- [           main] h.hellospring.HelloSpringApplication     : No active profile set, falling back to 1 default profile: "default"
hellospring  | 2023-09-22 13:20:22.746  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JPA repositories in DEFAULT mode.
hellospring  | 2023-09-22 13:20:22.757  INFO 1 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 4 ms. Found 0 JPA repository interfaces.
hellospring  | 2023-09-22 13:20:23.176  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8080 (http)
hellospring  | 2023-09-22 13:20:23.185  INFO 1 --- [           main] o.apache.catalina.core.StandardService   : Starting service [Tomcat]
hellospring  | 2023-09-22 13:20:23.185  INFO 1 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet engine: [Apache Tomcat/9.0.79]
hellospring  | 2023-09-22 13:20:23.260  INFO 1 --- [           main] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
hellospring  | 2023-09-22 13:20:23.260  INFO 1 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 906 ms
hellospring  | 2023-09-22 13:20:23.399  INFO 1 --- [           main] o.hibernate.jpa.internal.util.LogHelper  : HHH000204: Processing PersistenceUnitInfo [name: default]
hellospring  | 2023-09-22 13:20:23.442  INFO 1 --- [           main] org.hibernate.Version                    : HHH000412: Hibernate ORM core version 5.6.15.Final
hellospring  | 2023-09-22 13:20:23.580  INFO 1 --- [           main] o.hibernate.annotations.common.Version   : HCANN000001: Hibernate Commons Annotations {5.1.2.Final}
hellospring  | 2023-09-22 13:20:23.651  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
hellospring  | 2023-09-22 13:20:23.790  INFO 1 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
hellospring  | 2023-09-22 13:20:23.810  INFO 1 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.H2Dialect
hellospring  | Hibernate: drop table if exists member CASCADE
hellospring  | Hibernate: create table member (id bigint generated by default as identity, name varchar(255), primary key (id))
hellospring  | 2023-09-22 13:20:24.175  INFO 1 --- [           main] o.h.e.t.j.p.i.JtaPlatformInitiator       : HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
hellospring  | 2023-09-22 13:20:24.181  INFO 1 --- [           main] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
hellospring  | 2023-09-22 13:20:24.240  WARN 1 --- [           main] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
hellospring  | 2023-09-22 13:20:24.336  INFO 1 --- [           main] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page: class path resource [static/index.html]
hellospring  | 2023-09-22 13:20:24.480  INFO 1 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
hellospring  | 2023-09-22 13:20:24.487  INFO 1 --- [           main] h.hellospring.HelloSpringApplication     : Started HelloSpringApplication in 2.459 seconds (JVM running for 2.892)
hellospring  | 2023-09-22 13:20:35.862  INFO 1 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
hellospring  | 2023-09-22 13:20:35.863  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
hellospring  | 2023-09-22 13:20:35.863  INFO 1 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 0 ms
hellospring  | Hibernate: select member0_.id as id1_0_, member0_.name as name2_0_ from member member0_
hellospring  | Hibernate: select member0_.id as id1_0_, member0_.name as name2_0_ from member member0_ where member0_.name=?
hellospring  | Hibernate: insert into member (id, name) values (default, ?)
hellospring  | Hibernate: select member0_.id as id1_0_, member0_.name as name2_0_ from member member0_

홈(/)
홈 화면

회원 가입(/members/new)

회원 가입

회원 가입 페이지에서 이름(홍길동)을 등록한 후 회원 목록 페이지로 들어가면

회원 목록(/members)
회원 목록

위와 같이 정상적으로 작동한다.

profile
유랑하는 백엔드 개발자 새싹 블로그

0개의 댓글