시리즈: Hot Item 프로젝트 구축기
태그: Python Django PostgreSQL Redis Docker Docker Compose .env .gitignore


이 글에서 다루는 내용

  • .env와 .gitignore로 민감한 정보 보호하기
  • requirements.txt에 라이브러리를 명시하는 방법과 각 라이브러리의 역할
  • Dockerfile로 Django 서버 이미지 설계하기
  • docker-compose.yml로 세 서비스(Django + PostgreSQL + Redis) 연결하기
  • Django 프로젝트를 컨테이너 안에서 생성하는 방법

1. 먼저 .env와 .gitignore를 만드는 이유

파일을 채우기 전에, 반드시 먼저 해야 할 일이 있습니다. 바로 .env와 .gitignore 설정입니다.

docker-compose.yml을 보면 PostgreSQL의 DB 이름, 사용자 이름, 비밀번호 같은 민감한 정보가 필요합니다. 이 값들을 docker-compose.yml에 직접 적어버리면 나중에 GitHub에 올렸을 때 전 세계에 비밀번호가 공개됩니다. 이를 막기 위해 민감한 정보는 .env 파일에 따로 분리해 관리합니다.

.env 만들기

touch .env
nano .env
# .env

# PostgreSQL
POSTGRES_DB=hot_item_db
POSTGRES_USER=hot_item_user
POSTGRES_PASSWORD=your_password_here

# Django
SECRET_KEY=your_django_secret_key_here
DEBUG=True

.env 파일은 KEY=VALUE 형태로 환경 변수를 정의합니다. docker-compose.yml에서 ${POSTGRES_DB} 처럼 ${} 문법으로 이 값들을 가져다 씁니다.


.gitignore 만들기

.env 파일을 만들었다면, 이것이 Git에 올라가지 않도록 반드시 .gitignore에 등록해야 합니다.

touch .gitignore
nano .gitignore
# 환경 변수 (절대 올리면 안 됨)
.env

# Python
__pycache__/
*.pyc
*.pyo
.pytest_cache/

# Django
*.log
db.sqlite3

# Docker
.dockerignore

💡 .gitignore란?
Git이 추적하지 않을 파일 목록을 적어두는 파일입니다. 이 파일에 등록된 항목은 git add .를 해도 커밋에 포함되지 않습니다.


2. requirements.txt — 필요한 라이브러리 목록

# Web Framework
Django>=5.0,<5.1

# Database (PostgreSQL)
psycopg[binary]>=3.1.18

# Cache & Queue (Redis)
redis>=5.0.3

# Asynchronous Task (Celery)
celery>=5.3.6

django-environ>=0.11.2
requests>=2.31.0

각 라이브러리가 무슨 역할을 하는지 살펴봅니다.

라이브러리 역할

Django>=5.0,<5.1 백엔드 웹 프레임워크 (5.0 이상, 5.1 미만 버전 사용)
psycopg[binary] Django와 PostgreSQL을 연결해주는 드라이버
redis Django에서 Redis 서버에 명령을 보낼 수 있게 해주는 클라이언트
celery 비동기 작업 큐 라이브러리 (나중에 사용 예정)
django-environ .env 파일의 환경 변수를 Django 설정에서 쉽게 읽어오는 라이브러리
requests HTTP 요청을 보내는 라이브러리

💡 버전 명시 방법
>=5.0,<5.1처럼 범위로 명시하면 "5.0 이상 5.1 미만"이라는 뜻입니다. 이렇게 버전을 고정해두면 나중에 환경이 달라져도 동일한 라이브러리 버전이 설치되어 예상치 못한 오류를 예방할 수 있습니다.


3. Dockerfile — Django 서버 이미지 설계도

FROM python:3.12-slim-bookworm

RUN apt-get update && apt-get install -y \
    build-essential \
    libpq-dev \
    curl \
    && rm -rf /var/lib/apt/lists/*

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

한 줄씩 의미를 살펴보겠습니다.

FROM python:3.12-slim-bookworm
어떤 기반 이미지 위에 우리 서버를 만들지 지정합니다. slim은 불필요한 패키지를 제거한 경량 버전이고, bookworm은 Debian 12 버전을 의미합니다. 용량을 줄이면서도 안정적인 환경을 가져갈 수 있습니다.

RUN apt-get update && apt-get install -y ...
컨테이너 안에 필요한 시스템 패키지를 설치합니다.

  • build-essential: C 컴파일러 등 빌드 도구 모음
  • libpq-dev: psycopg(PostgreSQL 드라이버)가 컴파일될 때 필요한 헤더 파일
  • curl: URL로 데이터를 주고받는 명령줄 도구

설치 후 rm -rf /var/lib/apt/lists/*로 캐시를 삭제해 이미지 용량을 최소화합니다.

WORKDIR /app
이후 명령들이 실행될 컨테이너 내부의 작업 디렉토리를 /app으로 설정합니다.

COPY requirements.txt . → RUN pip install ...
전체 코드를 복사하기 전에 requirements.txt만 먼저 복사해서 라이브러리를 설치합니다. 이렇게 하면 코드만 바뀌었을 때 라이브러리 설치 단계를 다시 실행하지 않아 빌드 속도가 빨라집니다. (Docker 레이어 캐싱 활용)

COPY . .
프로젝트의 모든 파일을 컨테이너의 /app 폴더로 복사합니다.

CMD [...]
컨테이너가 시작될 때 기본으로 실행할 명령어입니다. Django 개발 서버를 0.0.0.0:8000에서 실행합니다. 0.0.0.0은 "모든 네트워크 인터페이스에서 접속을 받겠다"는 의미로, 컨테이너 외부(우리 브라우저)에서 접속할 수 있게 해줍니다.


4. docker-compose.yml — 세 서비스를 하나로 연결하기

services:
  db:
    image: postgres:16-alpine
    container_name: hot_item_db
    environment:
      POSTGRES_DB: ${POSTGRES_DB}
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
    ports:
      - "5433:5432"

  redis:
    image: redis:7.2-alpine
    container_name: hot_item_redis
    ports:
      - "6380:6379"

  web:
    build: .
    container_name: hot_item_web
    volumes:
      - .:/app
    ports:
      - "8001:8000"
    env_file:
      - .env
    depends_on:
      - db
      - redis

image vs build

  • db, redis는 image:로 Docker Hub에 이미 올라와 있는 공식 이미지를 바로 사용합니다.
  • web은 build: .으로 우리가 작성한 Dockerfile을 빌드해 사용합니다.

environment와 ${}
${POSTGRES_DB}처럼 ${} 문법을 사용하면 docker-compose.yml과 같은 위치에 있는 .env 파일의 값을 자동으로 읽어옵니다. 민감한 정보를 코드에 직접 적지 않아도 됩니다.

ports: "5433:5432"
호스트포트:컨테이너포트 형식입니다. 컨테이너 내부의 5432 포트를 로컬의 5433 포트로 연결합니다. PostgreSQL 기본 포트(5432)를 그대로 쓰지 않는 이유는 로컬에 이미 PostgreSQL이 설치된 경우 포트 충돌을 피하기 위해서입니다. Redis도 같은 이유로 6379 대신 6380을 사용합니다.

volumes: - .:/app
로컬의 현재 폴더(.)와 컨테이너의 /app 폴더를 연결합니다. 덕분에 로컬에서 코드를 수정하면 컨테이너를 재시작하지 않아도 변경 사항이 즉시 반영됩니다.

depends_on
web 서비스는 db와 redis가 먼저 시작된 후에 실행됩니다. Django 서버가 데이터베이스보다 먼저 켜져서 연결 오류가 나는 상황을 방지합니다.


5. Django 프로젝트 생성 — 왜 이 명령어를 썼을까?

환경 설정이 끝났다면 이제 Django 프로젝트를 생성할 차례입니다. 그런데 한 가지 주의할 점이 있습니다. 우리는 로컬에 Python이 설치되어 있지 않을 수 있습니다. 개발 환경을 완전히 Docker 안에 가두는 것이 목표였으니까요.

그래서 아래 명령어를 사용합니다.

docker-compose run --rm web django-admin startproject config .

명령어를 쪼개서 이해해보겠습니다.

부분 의미

docker-compose run 특정 서비스의 컨테이너를 일회성으로 실행한다
--rm 명령이 끝나면 컨테이너를 자동으로 삭제한다
web docker-compose.yml에 정의된 web 서비스를 사용한다
django-admin startproject config config라는 이름의 Django 프로젝트를 생성한다
. (마지막 점) 현재 폴더(/app)에 바로 생성한다 (별도 하위 폴더 없이)

💡 왜 docker-compose up이 아닌 run을 썼냐면?
up은 서비스를 계속 실행하는 명령이고, run은 특정 명령을 한 번만 실행하고 끝내는 명령입니다. 프로젝트 초기화처럼 딱 한 번만 실행해야 하는 작업에는 run --rm이 적합합니다.

이 명령어를 실행하면 컨테이너 안의 Django가 프로젝트 파일들을 생성하고, volumes 설정 덕분에 그 파일들이 로컬 폴더에도 그대로 나타납니다.


6. 최종 폴더 구조 확인

여기까지 완료하면 프로젝트 구조가 아래처럼 됩니다.

hot-item/
├── config/              # Django 프로젝트 설정 폴더
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── .env                 # 환경 변수 (Git에 올리지 않음)
├── .gitignore           # Git 추적 제외 목록
├── Dockerfile           # Django 서버 이미지 설계도
├── docker-compose.yml   # 멀티 컨테이너 설정
├── manage.py            # Django 관리 명령어 진입점
└── requirements.txt     # 필요한 라이브러리 목록

7. 정리

오늘 한 작업을 요약하면:

  • .env로 민감한 정보를 분리하고, .gitignore로 GitHub에 올라가지 않도록 보호했습니다.
  • requirements.txt에 프로젝트에 필요한 라이브러리와 버전을 명시했습니다.
  • Dockerfile로 Django 서버 컨테이너 이미지를 정의했습니다.
  • docker-compose.yml로 Django, PostgreSQL, Redis 세 서비스를 하나로 연결했습니다.
  • docker-compose run --rm web django-admin startproject config . 명령어로 컨테이너 안에서 Django 프로젝트를 생성했습니다.

다음 포스트에서는 Dev Container를 설정해서 VS Code에서 컨테이너 내부를 직접 개발 환경으로 사용하는 방법을 다루겠습니다. 🚀

 

+ Recent posts