[Docker] Spring Boot + MySQL Docker-compose 와 Volume을 이용해서 구동시키기

임성채·2024년 7월 18일

Docker

목록 보기
3/3
post-thumbnail

👨‍💻 Intro

DB랑 연동하는 과정에서 2개의 컨테이너가 동시에 구동되기 때문에 계속 에러가 발생하였습니다.
그 에러를 잡기 위해 wait-for-it.sh 또는 healthcheck를 사용하여서 설명이 좀 난잡하여도 이해해주기 바랍니다.
최하단 참고사이트에 자세하게 설명되어있으니 참고해주시기 바랍니다.

💡 도커 컴포즈 (Docker Compose)란?

여러 개의 컨테이너가 하나의 애플리케이션으로 동작할 때, 이를 테스트하려면 각 컨테이너를 하나씩 생성해야 한다. 여러 개의 컨테이너로 구성된 애플리케이션을 구축하기 위해서 run 명령어를 여러 번 사용할 수 있지만, 테스트 단계에서는 매번 run 명령어에 옵션을 설정해서 진행하기에 번거로움이 있다.
이를 위해 도커 컴포즈는 YAML 파일을 통해 여러 개의 컨테이너의 실행을 한 번에 관리하여 하나의 프로젝트처럼 다룰 수 있는 환경을 제공한다.

파일 위치 / 기본 구조

Docker Compose는 기본적으로 Docker-compose.yml 파일을 설정 파일로 사용하는데 일반적으로 프로젝트의 최상위 디렉토리에 위치시킵니다. 그래야 개발자들이 프로젝트에 디렉토리에 들어오자 마자 손쉽게 애플리케이션을 올릴 수 있기 때문입니다.

Docker-compose.yml 파일은 대략적으로 다음과 같은 구조를 갖습니다.

version: "3.7"
services:
  web:
    # 웹 애플리케이션 설정
  db:
    # 데이터베이스 설정
networks:
  # 네트워크 설정
volumes:
  # 볼륨 설정

💡 Volume이란?

볼륨이란 도커에 의해 관리되는 가상 하드 디스크입니다.
이미지로 컨테이너를 만들면 해당 컨테이너마다 독립적인 볼륨(하나의 파일시스템을 갖춘 접근 가능한 저장 공간)이 할당되고, 컨테이너가 삭제되면 해당 볼륨 또한 삭제됩니다.
문제는 컨테이너 내부에 저장된 데이터는 컨테이너가 삭제되면 같이 삭제됩니다

그래서 도커에서 데이터의 영속성을 보장하기 위하여 볼륨과 바인트 마운트를 이용합니다.
이는 파일 시스템과 컨테이너를 분리시켜서 관리하며
컨테이너를 지웠다가 다시 실행해도 도커 볼륨과 연결하면 데이터는 그대로 유지되는 데이터 영속성을 보장시켜줍니다.

Volume 명령어

  • 생성 : docker volume create [volume_name]
  • 조회 : docker volume ls
  • 상세조회 : docker volume inspect [volume_name]
  • 볼륨을 컨테이너에 마운트 : docker run -v [마운트할 볼륨명]:[컨테이너 내의 경로] ...
  • 삭제 : docker volume rm [volume_name]
  • 내가 쓴 Volume 명령어
    docker volume create mysql_db

💻 Dockerfile

이전 글과 거의 동일하지만 wait-for-it.sh 부분만 주석처리로 추가해놓았습니다.

# JDK 17 기반
FROM openjdk:17-jdk-slim

# build할 jar 파일 변수 선언
ARG JAR_FILE=build/libs/*.jar

# build/libs에 있는 JAR파일을 Docker 이미지의 app.jar로 복사
COPY ${JAR_FILE} app.jar

# wait-for-it.sh 사용시 하단의 ENTRYPOINT는 주석처리나 지워줘야함
#RUN apt-get update && apt-get install -y bash
#COPY wait-for-it.sh /wait-for-it.sh
#RUN chmod +x /wait-for-it.sh

# Docker 컨테이너가 실행되면 java -jar app.jar 명령어를 실행하여 Spring boot 실행
ENTRYPOINT ["java", "-jar", "app.jar"]

💻 Docker-compose.yml 작성

먼저 application.propertiesddl-auto
create -> update로 변경해주시기 바랍니다.

db-mysql

mysql 을 컨테이너로 구동시키기 위한 설정입니다.

  • image : 도커허브에서 가져올 이미지 (docker pull mysql 동일)
  • environment : mysql 구동시 필요한 환경변수 설정
  • ports : 포트매핑
  • volume : 마운트할 볼륨 설정 [마운트 할 볼륨명]:[컨테이너 내의 경로]
  • networks : 컨테이너가 구동될 네트워크 설정
  • healthcheck : db-mysql의 건강 상태를 체크 건강한 상태가 확인이 되고나서 springboot를 실행시키기 위함 자세한 설명은 주석 참고
  db-mysql:
    image: mysql
    environment:
      MYSQL_DATABASE: mydb
      MYSQL_USER: user
      MYSQL_PASSWORD: user
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    ports:
      - 3306:3306
    volumes:
      - mysql_db:/var/lib/mysql
    networks:
      - springboot-mysql-net
    healthcheck:
      test: ['CMD','mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
      interval: 5s # interval은 헬스 실시 간격을 의미
      timeout: 1s # timeout은 그때까지 응답을 받지 못하면 실패로 간주하는 제한 시간
      retries: 2 # retries는 컨테이너 상태를 이상으로 간주할 때까지 필요한 연속 실패 횟수를 의미
      start_period: 5s # start_period 는 컨테이너 실행 후 첫 헬스 체크를 실시하는 시간 간격을 의미 애플리케이션을 시작하는 데 시간이 오래 걸리는 경우

springboot-mysql

springboot 를 컨테이너로 구동시키기 위한 설정

  • build : 이미지 빌으데 필요한 정보를 설정
    - context : 로컬에서 프로젝트가 존재하는 경로 설정
    - dockerfile : 도커파일의 이름 지정
    여기서 이름을 굳이 지정한 이유는 개발환경과 운영환경에서 쓰이는 이름이 다를 수 있기 때문(Dockerfile-dev, Dockerfile-prod)
  • port : 이전과 동일
  • depends_on : db-mysql 컨테이너에 의존한다는 의미인데 db-mysql 컨테이너의 헬스 체크를 통해 '건강한' 상태가 되어야 함을 지정함
  • network : 이전과 동일
  springboot-mysql:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8080:8080
    depends_on:
        db-mysql:
          condition: service_healthy
    networks:
      - springboot-mysql-net
# wait-for-it.sh 사용시
#    command:
#      - bash
#      - -c
#      - |
#        ./wait-for-it.sh db-mysql:3306 -s -t 100
#        java -jar /app.jar

하단의 주석부분은 healthcheck 를 사용하기전에 wait-for-it.sh를 사용해서 db를 먼저 가동시킨 후 app을 가동시키는 순서로 지정할 때 썼었으나 healthcheck로 변경하였습니다.

wait-for-it.sh

https://velog.io/@heyday_7/6-How-was-your-day-docker-compose.yml%EC%9C%BC%EB%A1%9C-%EA%B5%AC%EC%84%B1%ED%95%98%EA%B8%B0

networks

이전 글과 동일하게 구성하였습니다.

volumes

데이터의 볼륨을 정의해줍니다.

external: true 로 설정해서 기존에 만든 볼륨을 쓰게 한다는 뜻입니다.

volumes:
  mysql_db:
    external: true

전체 Docker-compose.yml 코드

version: "3.7"

services:
  db-mysql:
    image: mysql
    environment:
      MYSQL_DATABASE: mydb
      MYSQL_USER: user
      MYSQL_PASSWORD: user
      MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
    ports:
      - 3306:3306
    volumes:
      - mysql_db:/var/lib/mysql
    networks:
      - springboot-mysql-net
    healthcheck:
      test: ['CMD','mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
      interval: 5s # interval은 헬스 실시 간격을 의미
      timeout: 1s # timeout은 그때까지 응답을 받지 못하면 실패로 간주하는 제한 시간
      retries: 2 # retries는 컨테이너 상태를 이상으로 간주할 때까지 필요한 연속 실패 횟수를 의미
      start_period: 5s # start_period 는 컨테이너 실행 후 첫 헬스 체크를 실시하는 시간 간격을 의미 애플리케이션을 시작하는 데 시간이 오래 걸리는 경우
  springboot-mysql:
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - 8080:8080
    depends_on:
        db-mysql:
          condition: service_healthy
    networks:
      - springboot-mysql-net
# wait-for-it.sh 사용시
#    command:
#      - bash
#      - -c
#      - |
#        ./wait-for-it.sh db-mysql:3306 -s -t 100
#        java -jar /app.jar

networks:
  springboot-mysql-net:
    driver: bridge

volumes:
  mysql_db:
    external: true

💻 Docker-compose.yml 구동

  • 코드가 변경 되었을시 (코드 변경 없으면 건너뛰기)
    ./gradlew clean build -x test

  • compose로 구성된 컨테이너 이미지 빌드
    docker-compose build

  • 컨테이너 구동
    docker-compose up or docker-compose up -d

-d 옵션을 사용하면 백그라운드로 띄워지게 되고
사용하지 않을 시에는 Ctrl + C 를 눌러서 탈출하는 순간 컨테이너가 모두 정지됨.

💡 결과


참고

https://velog.io/@dhk22/Springboot-MySQL-Docker-도커를-이용한-멀티-컨테이너-환경-구성-Docker-compose

https://0902.tistory.com/6

https://velog.io/@he0_077/도커-8장-헬스-체크와-디펜던시-체크로-애플리케이션의-신뢰성-확보하기

https://velog.io/@cabbage/문제해결-도커-컴포즈에서-DB-연결-지연-이슈

0개의 댓글