[Docker] docker-compose로 MySQL 띄우기

코딩은 돈이 된다·2024년 7월 1일

Django 프로젝트 초기 설정을 하면서 프론트와의 협업을 위해 Django와 MySQL을 모두 Docker에 띄워주기로 하였다. Docker는 물론 Docker-compose도 안써봐서 공부하면서 생겼던 문제들이나, 코드들을 적어보고자 한다.

1. Django Dockerfile 작성

장고의 도커파일 작성 자체는 어렵지 않았다.

FROM python:3.10

WORKDIR /app

COPY . /app

RUN pip install --upgrade pip
RUN pip install -r requirements.txt
RUN pip install cryptography

EXPOSE 8000

이정도로만 작성해줘도 동작했는데,

cryptography가 뭐냐?
나도 저 코드 없이 돌려봤는데, 데이터베이스에 비밀번호로 접근할 때에 저걸 사용해서 없으면 오류가 난다.
추가하니까 잘 해결됐다.

requirements.txt파일은 그냥 버전 정보가 적혀있는 파일이다.
이걸 왜쓰냐면, 이렇게 명시해주고 instal을 해주면 설치가 된다.
즉, 도커 파일 내부가 좀 더 간단해진다. 이게 아니었다면 도커 파일 내부에 전부 RUN으로 추가해주어야한다.

Django==5.1a1
python-dotenv==1.0.0
djangorestframework==3.14.0
PyMySQL~=1.1.1

실제로 requirements.txt에 이런 값들을 넣어서 사용했다.
여기서 PyMySQL이라는 독특한 무언가가 있는데, 원래는 mysql-client를 사용하려고 하였다.

찾아보니 m1 mac에서는 오류가 난다는 것 같더라..
하는 수 없이 PyMySQL을 통해 연결하기로 했다.

2. settings.py

다음은 mysql 연결을 위해 settings.py를 수정해주었다.

...

import os
from dotenv import load_dotenv
import pymysql

pymysql.install_as_MySQLdb()
load_dotenv()

...
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': os.getenv("MYSQL_DATABASE"),
        'USER': os.getenv("MYSQL_USER"),
        'PASSWORD': os.getenv("MYSQL_PASSWORD"),
        'HOST': os.getenv("MYSQL_HOST"),
        'PORT': os.getenv("MYSQL_PORT"),
    }
}
...

나같은 경우에는 수정이 편하도록 .env파일을 작성하고 거기에서 가져오는 방법을 선택했다.

3. env 파일

가장 애를 많이 먹은 부분이다.
계속 실행하는데 HOST를 찾을 수 없다 이러는데
분명 database로 잘 설정을 해두었는데 미칠 뻔 했다..

문제는 내가 mysql 이미지를 띄울 때 로컬에 있는 mysql과 충돌이 나지 않게 하려고 3305:3306으로 작성해두고 MYSQL_PORT에 3305라고 적은 것이었다.

난 이 뜻이 그냥 "3305로 접속해야한다"는 것인 줄 알았는데, 3306을 통해 접속해야 하는 것이었다.

한참 죄없는 MYSQL_HOST만 건드리다가 gpt랑 몇 번 싸우고 깨달았다.

원래 포트 번호로 접속을 요청해야 하는 것을 잊지 말자.

나는 settings.py에 값을 바인딩 할때 .env파일을 사용했는데,
값 조정이 좀 더 편리하게 하려면 settings.py에 하드코딩하는 방식보다는 파일을 하나 따로 둬서 관리하는 것이 좋다고 생각했기 때문이다.

MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=database name
MYSQL_USER=user
MYSQL_PASSWORD=password
# backend 분들은 로컬 작업 시 host를 localhost로 변경해주세요.
# MYSQL_HOST=localhost
# frontend 분들은 그대로 사용하시면 됩니다.
MYSQL_HOST=database
MYSQL_PORT=3306

이정도 작성해보았는데, 중간에 주석은 백엔드가 pycharm에서 작업하려면 run을 해야하는데, 그렇게 했더니 HOST 부분이 오류가 났다.
당연히 database라는 HOST가 없어서였다.

그래서 로컬 데이터베이스에 접속하여 개발 시에만 HOST를 바꾸어 작업하려고 했다.

정말 멍청한 방법이더라

방금 블로그 글을 작성하면서 생각해봤는데, 그냥 도커로 띄워진 서버에 api요청을 날려 작업하면 될 것 같아서 해봤는데 됐다..
volume 설정도 해놔서 실시간으로 수정이 되는 것도 확인했다.

MYSQL_ROOT_PASSWORD=rootpassword
MYSQL_DATABASE=database name
MYSQL_USER=user
MYSQL_PASSWORD=password
MYSQL_HOST=database
MYSQL_PORT=3306

그냥 이렇게 써도 될 듯 하다.
MYSQL_HOST의 경우에는 docker-compose에서의 mysql의 컨테이너 이름을 가져와야한다.

4. docker-compose

version: '3'
services:
  database:
    image: mysql:8.0
    container_name: database
    env_file:
      - .env
    ports:
      - "3305:3306"
    networks:
      - MZ

  backend:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: backend
    ports:
      - "8000:8000"
    volumes:
      - .:/app
    depends_on:
      - database
    command: >
      sh -c "sleep 10 &&
            python manage.py makemigrations &&
            python manage.py migrate &&
            python manage.py runserver 0.0.0.0:8000"
    tty: true
    networks:
      - MZ

networks:
  MZ:
    driver: bridge

아까 말했던 MYSQL_HOST에다가 넣는 값이 mysql의 container_name이 된다.

8000 포트는 웬만해선 사용중일리가 없으니 그냥 두고 mysql 포트만 변경해주었다.

어 그럼 build 할 때마다 database가 날아가는거 아닌가?

내가 했던 생각이다.
그냥 빌드를 해버리니 쓰레기 이미지들이 생겨서 보기 안좋았다.
그래서 나는 지금까지 계속 컨테이너를 지우고 이미지도 지우고 다시 빌드했다.

이때 든 생각은 "이러면 데이터베이스가 다 날아갈텐데 너무 비효율적이지 않나"였고,

방법을 찾아보니 Volume을 이용하라고 하는데, 보다가 너무 어려워서 덮었다.

혹시나 하는 마음에 container의 mysql에서 insert를 진행하고, 이미지를 지우지 않은채로 다시 컴파일을 해보고 테이블을 확인해봤더니 insert한 값이 있었다.

그냥 사용 방법을 잘 몰라서 생긴 오류들인 것 같다.

계속 삽질만 한 것 같은데 결국 성공한 것 같아서 좋더라

이제 docker-compose와 dockerfile 모두 작성해보았으니, 다음 프로젝트부터는 좀 더 원활하게 할 수 있지 않을까 싶다.

0개의 댓글