컴퓨터 활용/노년에 즐기는 코딩
Django + MySQL 웹서비스 개발
easyfly
2025. 8. 16. 16:38
반응형
Docker로 셋업하는 Django + MySQL 개발환경
1) 디렉터리 구조 만들기
작업 폴더를 하나 만들고 아래 파일들을 채웁니다.
myproject/
├─ docker-compose.yml
├─ .env
├─ .dockerignore
├─ web/
│ ├─ Dockerfile
│ └─ requirements.txt
└─ (처음엔 장고 소스가 없음: 컨테이너에서 생성)
2) 환경변수 파일(.env)
비밀번호 같은 값은 코드에 박지 말고 .env에 두겠습니다.
# .env
MYSQL_ROOT_PASSWORD=secret-root
MYSQL_DATABASE=mydb
MYSQL_USER=myuser
MYSQL_PASSWORD=secret-pass
TZ=Asia/Seoul
3) docker-compose.yml
웹(장고), DB(MySQL), DB관리(Adminer)를 한 번에 띄웁니다.
# docker-compose.yml
version: "3.9"
services:
db:
image: mysql:8.0
container_name: mp_db
env_file: .env
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- TZ=${TZ}
command: [
"mysqld",
"--character-set-server=utf8mb4",
"--collation-server=utf8mb4_unicode_ci",
"--default-time-zone=+09:00"
]
ports:
- "3306:3306" # 로컬 DB 클라이언트로 접속 필요 없으면 주석 처리 가능
volumes:
- dbdata:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-u", "root", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 5s
timeout: 3s
retries: 20
web:
build: ./web
container_name: mp_web
depends_on:
db:
condition: service_healthy
env_file: .env
environment:
- DJANGO_SETTINGS_MODULE=config.settings
- PYTHONDONTWRITEBYTECODE=1
- PYTHONUNBUFFERED=1
- TZ=${TZ}
volumes:
- ./:/app
working_dir: /app
command: bash -lc "python manage.py migrate && python manage.py runserver 0.0.0.0:8000"
ports:
- "8000:8000"
adminer:
image: adminer:latest
container_name: mp_adminer
depends_on:
- db
environment:
- ADMINER_DEFAULT_SERVER=db
ports:
- "8080:8080"
volumes:
dbdata:
4) 웹용 Dockerfile
mysqlclient 빌드를 위해 최소한의 개발 패키지를 설치합니다.
# web/Dockerfile
FROM python:3.12-slim
# 시스템 패키지 (mysqlclient 빌드에 필요)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential default-libmysqlclient-dev pkg-config curl \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r /app/requirements.txt
5) Python 패키지 목록
# web/requirements.txt
Django>=5.0,<6.0
mysqlclient>=2.2
django-environ>=0.11
6) .dockerignore
컨테이너 빌드 시 불필요한 파일 제외
.git
__pycache__/
*.pyc
.env
db.sqlite3
staticfiles/
media/
7) 컨테이너 기동 및 장고 프로젝트 생성
7-1. 컨테이너 빌드 & 시작
docker compose up -d --build
7-2. 장고 프로젝트 골격 만들기
처음 한 번만 실행합니다. (config가 프로젝트명)
docker compose exec web django-admin startproject config .
7-3. settings.py에 DB 연결 설정
config/config/settings.py를 열어 아래처럼 수정합니다. (django-environ 사용)
# config/settings.py
from pathlib import Path
import environ, os
BASE_DIR = Path(__file__).resolve().parent.parent
env = environ.Env(
DEBUG=(bool, True),
)
environ.Env.read_env(os.path.join(BASE_DIR.parent, '.env'))
SECRET_KEY = env('SECRET_KEY', default='dev-secret')
DEBUG = True
ALLOWED_HOSTS = ['*']
INSTALLED_APPS = [
'django.contrib.admin','django.contrib.auth','django.contrib.contenttypes',
'django.contrib.sessions','django.contrib.messages','django.contrib.staticfiles',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware','django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
ROOT_URLCONF = 'config.urls'
WSGI_APPLICATION = 'config.wsgi.application'
LANGUAGE_CODE = 'ko-kr'
TIME_ZONE = 'Asia/Seoul'
USE_I18N = True
USE_TZ = True
# MySQL 연결
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': env('MYSQL_DATABASE'),
'USER': env('MYSQL_USER'),
'PASSWORD': env('MYSQL_PASSWORD'),
'HOST': 'db', # compose 서비스 이름
'PORT': 3306,
'OPTIONS': {
'charset': 'utf8mb4',
},
'CONN_MAX_AGE': 60, # 커넥션 재사용
}
}
# 정적 파일
STATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
참고: .env에 SECRET_KEY도 추가하시면 좋습니다.
SECRET_KEY=your-dev-secret
7-4. 마이그레이션 & 관리자 계정
docker compose exec web python manage.py migrate
docker compose exec web python manage.py createsuperuser
7-5. 접속 확인
- 장고: http://localhost:8000
- Adminer: http://localhost:8080
- 서버: db
- 사용자: .env의 MYSQL_USER
- 비번: .env의 MYSQL_PASSWORD
- DB: MYSQL_DATABASE
8) 장고 앱 추가 예시
docker compose exec web python manage.py startapp blog
INSTALLED_APPS에 blog 등록 → 모델 작성 → makemigrations → migrate 순서대로 진행합니다.
9) 정적 파일 수집(배포 준비)
개발은 DEBUG=True로 진행하고, 배포 시:
docker compose exec web python manage.py collectstatic --noinput
Nginx 등 역프록시를 두고 staticfiles/를 서빙하는 구성을 추가합니다.
10) 자주 겪는 문제와 해결
- 장고가 DB에 못 붙음 (OperationalError: Can't connect)
- 해결: depends_on + healthcheck로 DB 준비를 기다리게 했지만, 최초 기동이 오래 걸릴 수 있습니다.
문제가 지속되면 docker compose logs db로 에러 확인 후 docker compose restart web.
- 해결: depends_on + healthcheck로 DB 준비를 기다리게 했지만, 최초 기동이 오래 걸릴 수 있습니다.
- 한글 깨짐
- 해결: compose의 mysqld 옵션에 utf8mb4/utf8mb4_unicode_ci 지정함.
그래도 깨지면 테이블/컬럼의 Collation을 확인.
- 해결: compose의 mysqld 옵션에 utf8mb4/utf8mb4_unicode_ci 지정함.
- 권한 문제(파일 생성이 루트 소유)
- 해결: 개발 시에는 큰 문제없지만 필요하면 web 서비스에 user: "1000:1000" 지정.
- 장고에서 ‘DisallowedHost’
- 해결: ALLOWED_HOSTS = ['*'](개발용). 배포 시 도메인만 열어두세요.
- DB 비번 잊음 / 초기화
- dbdata 볼륨을 삭제하면 DB가 초기화됩니다.
- docker compose down -v docker compose up -d
11) 프로덕션으로 확장할 때
- Gunicorn + Nginx 컨테이너 추가
- 환경변수 분리(dev/prod .env) 및 DEBUG=False
- 보안/성능: SECURE_* 설정, ALB/프록시, 캐시(Redis), 백업 전략
- 마이그레이션 자동화: command 대신 엔트리포인트 스크립트로 migrate/collectstatic 수행
12) 빠른 체킹 명령 모음
# 전체 기동/중지/로그
docker compose up -d --build
docker compose logs -f web
docker compose down
# DB 접속(Adminer 없이)
docker compose exec db mysql -umyuser -psecret-pass mydb
# 장고 명령
docker compose exec web python manage.py migrate
docker compose exec web python manage.py createsuperuser
docker compose exec web python manage.py shell
.
반응형