본문 바로가기

Docker

[Docker Compose] Spring Boot + MySQL + Redis

728x90

https://bestdevelop-lab.tistory.com/154

 

Docker compose 설정 및 각종 테스트

Docker compose란?여러 개의 Docker Container를 정의하고 이들을 하나의 애플리케이션으로 관리할 수 있게 해주는 것 여기서는 두 개의 컨테이너를 동일 네트워크에 포함시킬 예정네트워크는 별도로

bestdevelop-lab.tistory.com

 

이전 Docker compose 글에서 추가, 변경이 된 내용

1. Redis (application.yml)

  • 이메일 인증 코드를 저장하기 위해 Redis가 추가
  • 추후 JWT 토큰의 Refresh Token을 저장할 때도 Redis가 필요
spring:
  # 레디스
  data:
    redis:
      host: localhost
      port: 6379

 

2. docker-compose.yml

  • 이전 글의 Docker compose 방식
  1. docker build -t test-image(이미지명) . → 명령어를 사용하여 이미지 생성
  2. docker-compose.yml에서 services.myapp.image : test-image(이미지명) 으로 Spring에 사용할 image 지정
services:
  myapp:
    image: 이미지명
    container_name: playheaven-container
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      db :
        condition: service_healthy
    ports:
      - "8080:8080"

 

 

하지만, 생각해보니 아래 두 줄의 명령어에 의해서 '현재 디렉토리에 있는 Dockerfile을 실행시켜서 image를 build 하겠다'라는 의미로 작동 됨

services.myapp.build.context : .
services.myapp.build.dockerfile : Dockfile

 

따라서, 'docker build -t 이미지명 .' 명령어를 할 필요 없이 아래 처럼 docker-compose.yml 파일 하나로 가능

services:
  myapp:
    container_name: playheaven-container
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      db :
        condition: service_healthy
    ports:
      - "8080:8080"

 

3. docker-compose.yml만 실행 vs build 기준

  • docker-compose.yml 파일만 변경이 되었다면 새로 빌드할 필요 없이 컨테이너 삭제 후 docker-compose.yml만 실행하면 됨
  • 하지만 그 외에 자바 코드 추가, 삭제 변경 / application.yml / Dockerfile 변경 시에는 컨테이너 뿐만 아니라 Spring image(myapp)까지 삭제한 뒤 build → docker-compose.yml 실행 순서로 해야 함

docker-compose.yml 설정 추가
services:
  redis:
    image: redis:latest
    container_name: redis_test
    ports:
      - 6379:6379
    volumes:
      - ./redis/data:/data
      - ./redis/conf/redis.conf:/usr/local/conf/redis.conf
    labels:
      - "name=redis"
      - "mode=standalone"
    restart: always
    command: redis-server /usr/local/conf/redis.conf

 

  • service.redis.image
    • 가장 최신 버전 redis 사용
  • service.redis.container_name
    • 컨테이너로 사용할 이름
    • 설정하지 않을 경우 Docker가 자동 할당
  • service.redis.ports
    • 접근 포트 설정 (호스트포트:컨테이너포트)
  • service.redis.volumes
    • 로컬 디렉토리와 컨테이너 내부 디렉토리를 마운트
    • ./redis/data:/data컨테이너의 /data 디렉토리에 데이터를 저장하면서, 로컬 디렉토리(./redis/data)에도 이를 유지
      컨테이너가 삭제되더라도 데이터는 로컬에 남아있어, 컨테이너 재시작 시 데이터 복구 가능
    • ./redis/conf/redis.conf:/usr/local/conf/redis.conf는 Redis 설정 파일을 외부에서 관리할 수 있도록 마운트
  • service.redis.labels
    • 컨테이너에 메타 데이터 추가
    • name=redis, mode=standalone이라는 라벨을 부여해 컨테이너를 식별하거나 필터링 가능
    • Docker 명령어나 UI 도구에서 컨테이너를 관리할 때 유용
  • service.redis.restart
    • 컨테이너 종료 시 재시작 여부 설정
    • always : 컨테이너가 중지되거나 충돌 시 무조건 재시작
  • service.redis.command
    • 컨테이너가 시작될 때 실행할 명령어 설정
    • 특정 설정 파일(/usr/local/conf/redis.conf)을 사용해 실행

 

docker-compose.yml 실행 → Docker Container 확인

  • 3개 Container 모두 정상 실행 확인
  • Postman을 이용하여 이메일 인증 코드 발송 → 에러 발생

  • Docker의 Spring Boot 확인 → ConnectionException : Connection refused

 

원인
  • 이전 Docker compose 글에서 DB Connection을 docker 설정에 맞춰야하는 문제와 동일
  • Local에서는 localhost이지만, Docker에서는 host.docker.internal로 설정을 해야한다고 함
  • host.docker.internal 설정은 docker-compose.yml 파일의 services 이름을 넣으면 됨

application.yml 파일이 변경 되었기 때문에 아래 순서로 진행

1. Container 삭제

2. Image 삭제

3. Build

4. docker-compose.yml 실행(터미널 명령 : docker compose up)

5. 3개 컨테이너 정상 작동 확인

 

 

6. Postman 정상 작동 확인

 

7. Docker의 Redis에 저장 되었는 지 확인

  • Docker Redis 접근 명령
  • docker exec -it 레디스컨테이너명 redis-cli
docker exec -it redis_test redis-cli

 

최종 설정

application.yml

spring:
  # 레디스
  data:
    redis:
      host: redis
      port: 6379
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://db:3306/playheaven
    username: root
    password: 1234
  #Email 인증
  mail:
    host: smtp.gmail.com
    port: 587
    username: 아이디
    password: 비밀번호
    properties:
      mail:
        smtp:
          auth: true
          starttls:
            enable: true
            required: true
          connectiontimeout: 5000
          timeout: 5000
          writetimeout: 5000
      auth-code-expiration-millis: 300000  # 5 * 60 * 1000(밀리초) == 5분

  jpa:
    open-in-view: true
    hibernate:
      ddl-auto: update
    show-sql: true
    properties:
      hibernate.format_sql: true
      dialect: org.hibernate.dialect.MySQL8InnoDBDialect

logging:
  level:
    org.hibernate.SQL: debug

 

docker-compose.yml

version: '3.8'
services:
  redis:
    image: redis:latest
    container_name: redis_test
    ports:
      - 6379:6379
    volumes:
      - ./redis/data:/data
      - ./redis/conf/redis.conf:/usr/local/conf/redis.conf
    labels:
      - "name=redis"
      - "mode=standalone"
    restart: always
    command: redis-server /usr/local/conf/redis.conf

  db:
    image: mysql:8.0
    container_name: mysql-container
    environment:
      MYSQL_ROOT_PASSWORD : 1234
      MYSQL_DATABASE: playheaven
    ports:
      - "3307:3306"
    restart: always
    healthcheck:
      test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p1234 && sleep 5"]
      interval: 5s
      retries: 10

  myapp:
    container_name: playheaven-container
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      db :
        condition: service_healthy
    ports:
      - "8080:8080"


 

Health Check

 

설정 도중 myapp의 depends_on에 redis를 추가하려 하니 아래의 두 설정 파일처럼 db와 redis 둘 다 health_check를 하거나 둘 다 하지 않아야했음

 

  • 아래 설정 파일을 사용하기 위해서는 redis에도 health check를 하는 설정을 해주어야 함
services:
  myapp:
    container_name: playheaven-container
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
            db :
              condition: service_healthy
            redis:
              condition: service_healthy
    ports:
      - "8080:8080"

 

  • 아래 설정 파일은 MySQL이 실행되는 동안 Spring에서 DB Connection에 실패하여 Spring Container가 종료 되기 때문에 MySQL이 켜진 뒤 수동으로 시작해줘야하는 번거로움이 있었음
services:
  myapp:
    container_name: playheaven-container
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - db
      - redis
    ports:
      - "8080:8080"

 

  • ChatGPT에 의하면 depends_on의 condition : service_health 옵션은 더 이상 Docker compose에서 권장하지 않으며, 최신 버전에서는 지원하지 않는다고 함
  • 따라서, healcheck 대신 restart : on-failure 설정을 통해, 실패할 때마다 자동으로 재시작 되도록 하는 것이 일반적인 접근이라고 함
services:
  myapp:
    container_name: playheaven-container
    restart: on-failure
    build:
      context: .
      dockerfile: Dockerfile
    depends_on:
      - db
      - redis
    ports:
      - "8080:8080"

 

  • 또는 헬스 체크 대신 대기 스크립트를 사용한다고 함
  • 예를 들어, wait-for-it.sh 같은 도구를 사용하여 MySQL과 Redis가 준비될 때까지 대기한 후 애플리케이션 기동 가능
728x90

'Docker' 카테고리의 다른 글

Docker compose 설정 및 각종 테스트  (0) 2024.08.09
Docker 설치 및 환경 설정  (0) 2024.08.09
Docker란?  (0) 2024.08.08
컨테이너 vs 가상머신(VM)  (0) 2024.08.08