MLOps/Docker

[Docker#16] Docker Compose 여러 개의 컨테이너 동시에 띄우기(2)

j.d 2025. 5. 13. 00:38

Docker Compose를 사용하면 여러 개의 컨테이너를 동시에 띄워 다양한 환경을 쉽게 구축할 수 있습니다. 예를 들어, Python(Flask) 백엔드와 MySQL 데이터베이스를 각각 컨테이너로 구성해 한 번에 실행할 수 있죠.

하지만 종종 아래와 같은 MySQL 연결 오류를 마주하게 됩니다.

 Can't connect to MySQL server on 'my-db' ([Errno 111] Connection refused)

 

이번 글에서는 왜 이런 에러가 발생하는지, 그리고 어떻게 해결해야 하는지를 설명하도록 하겠습니다.

 

 

에러 원인: 컨테이너는 서로 다른 'localhost'를 가진다

보통 우리는 MySQL 주소를 이렇게 작성합니다.

conn = pymysql.connect(
    host="localhost",
    user="root",
    password="pwd1234",
    database="test_db"
)

 

하지만 이 방식은 컨테이너 환경에서는 잘못된 접근입니다. 이유는 다음과 같습니다:

  • 각 컨테이너는 독립된 네트워크 공간을 갖습니다.
  • Flask 컨테이너에서 localhost는 자기 자신을 가리킵니다.
  • 즉, 위 코드는 Flask 컨테이너 내부에 존재하지 않는 MySQL을 찾고 있는 셈입니다.

 

해결 방법: host에 서비스 이름을 써야 한다

conn = pymysql.connect(
    host="my-db",      # Compose의 MySQL 서비스 이름
    user="root",
    password="pwd1234",
    database="test_db"
)

 

이전 글에서 my-db는 docker-compose.yml에서 MySQL 서비스를 다음과 같이 정의했기 때문입니다.

services:
  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: pwd1234
      MYSQL_DATABASE: test_db

※ 이때 my-db는 네트워크 상에서 해당 MySQL 컨테이너의 호스트 이름처럼 작동합니다.

 

 

추가 참고사항: depends_on으로 실행 순서 보장하기

 

MySQL이 완전히 실행되기 전에 Python 앱이 연결을 시도하면 여전히 실패할 수 있습니다.
이럴 땐 depends_on 설정을 활용해 Flask 컨테이너가 MySQL 컨테이너를 기다린 후 실행되도록 할 수 있습니다.

services:
  my-db:
    image: mysql
    environment:
      MYSQL_ROOT_PASSWORD: pwd1234
      MYSQL_DATABASE: test_db
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "localhost" ]
      interval: 5s
      retries: 10

  my-app:
    build: ./app
    depends_on:
      my-db:
        condition: service_healthy

 

 

위 수정사항을 반영해서 다시 실행하면 아래와 같이 정상 페이지가 보이는 것을 알 수 있습니다.