[문제해결] 도커 컴포즈에서 DB 연결 지연 이슈

cabbage·2023년 10월 25일
1

문제해결

목록 보기
2/3
post-thumbnail

팀과제를 진행하면서 프로젝트 초기설정을 진행하던 중, 도커 컴포즈에서 DB 연결 지연 이슈가 발생했다. 같은 팀원분이 해결 방법을 알려주셨고, 구글링을 통해 어떻게 해결되었는지를 정리한다.

도커 컴포즈에서 DB 연결 지연 이슈

문제 상황

  • 도커 컴포즈로 구성한 서버 컨테이너의 서버와 DB 컨테이너의 MySQL 서버 연결 시 데이터베이스 연결이 지연되는 문제가 발생하였음
  • 서버에서 약 3번의 연결 시도를 통해 데이터베이스와 연결됨

문제 원인

  • 도커 컴포즈의 서비스 실행 순서 문제
  • 서버는 빠르게 시작되어 데이터베이스와 연결을 계속 시도하지만, 데이터베이스는 서버보다 비교적 늦게 실행이 완료되어 정상적으로 서버와 연결할 수 있는 상태가 아니어서 서버가 계속 데이터베이스에 연결을 시도하였음
  • depends_on 은 서비스의 시작과 종료를 제어할 수 있는 설정 옵션
  • depends_on 으로 서비스의 의존성을 명시하더라도, 의존받는 서비스의 ‘준비’ 상태를 보장하지는 않음
    • 즉 의존받는 서비스가 실행되면 곧바로 의존하는 서비스도 실행되기 때문에 의존받는 서비스가 완전히 ‘준비’ 상태가 되지 않더라도 의존하는 서비스가 실행된다는 의미
  • 이를 우리 상황에 대입했을 때
    • dev_db 서비스에 api 서비스가 의존하는 상황에서 dev_db 서비스가 시작되면 dev_db 서비스가 완전히 준비 상태가 아닌 상황에서도 곧바로 api 서비스도 실행됨
    • 따라서 데이터베이스 연결 문제가 발생함
    • 결과적으로 dev_db 서비스가 완전한 준비 상태가 되었을 때 api 서비스를 실행하면 문제를 해결

문제 해결

services:
    api:
        build:
            context: .
            dockerfile: DockerFile
        volumes:
            - ./src:/api/src
        restart: always
        ports:
            - ${SERVER_PORT}:${SERVER_PORT}
        depends_on:
            dev_db:
                condition: service_healthy
        networks:
            - container-network

    dev_db:
        image: mysql:latest
        container_name: db
        environment:
            MYSQL_ROOT_USER: ${MYSQL_ROOT_USER}
            MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
            MYSQL_DATABASE: ${MYSQL_DATABASE}
        restart: always
        ports:
            - ${MYSQL_PORT}:${MYSQL_PORT}
        networks:
            - container-network
        healthcheck:
            test: ['CMD', 'mysqladmin', 'ping', '-h', 'localhost', '-u', 'root', '-p$$MYSQL_ROOT_PASSWORD']
            timeout: 20s
            retries: 10
networks:
    container-network:
        driver: bridge
  • 도커 컴포즈의 depends_on, healthcheck 관련 옵션을 통해 해결하였음
  • 도커 컴포즈 공식 문서에 따르면 서비스의 준비 상태를 확인하는 방법은 depends_oncondition 속성에 다음 값들을 사용하는 것
    • service_started
    • service_healthy
    • service_completed_successfully
  • 이중에서 사용한 service_healthy 값은 의존하는 서비스가 시작되기 전 의존받는 서비스의 healthcheck 에 정의된 대로 의존받는 서비스가 ‘건강한’ 상태가 되어야 함을 지정함
    • 즉 dev_db 서비스의 healthcheck 에서 정의한 대로 dev_db가 ‘건강한’ 상태가 되면 dev_db 서비스를 의존하는 api 서비스가 실행된다는 의미
  • healthcheck 은 서비스 컨테이너가 ‘건강한’ 상태인지를 결정하기 위한 진단을 선언함
    • test 도커 컴포즈가 컨테이너의 건강을 확인하기 위해 실행하는 커맨드를 정의함
      • test 에 정의한 커맨드
        CMD mysqladmin ping -h localhost -u root -p$$MYSQL_ROOT_PASSWORD
      • mysqladmin: MySQL 서버 관리 프로그램
      • ping: 서버가 사용 가능한지를 체크함
        • 서버가 실행 중이면 0을, 그렇지 않다면 1을 반환
      • -h: MySQL 서버에 연결할 때 사용하는 호스트명
      • -u: 서버에 연결하기 위해 사용할 MySQL 계정의 유저 이름
        • root 명시
      • -p: MySQL 계정의 유저 패스워드
        • -p의 경우 -p 바로 뒤에 패스워드를 작성해야 함(-p와 패스워드 사이에 공백이 없다는 의미)
      • MYSQL_ROOT_PASSWORD
        • 도커 컴포즈 실행 시 명시한 환경 변수 파일에서 읽은 환경 변수 값
    • timeout 한 번의 건강 진단이 명시한 시간보다 오래 걸리면 해당 건강 진단은 실패로 간주됨
    • retries 컨테이너에 대한 건강 진단 진행 횟수

참고 링크

profile
캐비지 개발 블로그입니다. :)

0개의 댓글