Jiwon Min Developer

Building a Production-Ready Local Development Environment with Docker Compose

“제 컴퓨터에서는 잘 되는데요?” 개발자라면 한 번쯤 겪어봤을 혹은 내뱉어봤을 말일 겁니다. 개발 환경과 실제 서비스가 운영되는 프로덕션 환경의 미세한 차이는 예상치 못한 버그와 배포 실패의 주된 원인이 됩니다. 라이브러리 버전, 운영체제, 시스템 설정 등 수많은 변수가 존재하기 때문입니다. 이러한 문제를 해결하기 위해 등장한 기술이 바로 Docker입니다.

Docker는 애플리케이션과 그에 필요한 모든 종속성을 ‘컨테이너’라는 격리된 공간에 패키징하여, 어떤 환경에서든 동일하게 실행될 수 있도록 보장합니다. 이를 통해 개발자는 프로덕션 환경과 거의 동일한 환경을 로컬 PC에 손쉽게 구축할 수 있으며, 팀원들과 일관된 개발 환경을 공유할 수 있습니다. 본 포스트에서는 Docker Compose를 사용하여 Python Django 웹 프레임워크, PostgreSQL 데이터베이스, Redis 캐시 서버로 구성된 다중 컨테이너 개발 환경을 구축하는 실용적인 방법을 단계별로 안내하겠습니다.

Building a Production-Ready Local Development Environment with Docker Compose

© AI Generated by Imagen 4.0


왜 Docker를 사용해야 할까요?

본격적인 구축에 앞서 Docker를 사용하는 이유를 명확히 짚고 넘어가겠습니다.

  • 환경 일관성: Docker는 애플리케이션 실행에 필요한 모든 것(코드, 런타임, 시스템 도구, 라이브러리 등)을 컨테이너 이미지 하나에 담습니다. 이 이미지를 통해 개발, 스테이징, 프로덕션 환경 모두에서 동일한 환경이 보장되어 ‘환경 차이로 인한’ 버그를 원천적으로 차단합니다.
  • 격리된 환경: 각 컨테이너는 호스트 시스템 및 다른 컨테이너와 격리되어 실행됩니다. 이를 통해 여러 프로젝트의 각기 다른 버전의 라이브러리나 데이터베이스가 서로 충돌하는 문제를 방지할 수 있습니다.
  • 빠른 구성 및 배포: Dockerfiledocker-compose.yml이라는 코드 기반의 설정 파일을 통해 개발 환경 구축을 자동화할 수 있습니다. 새로운 팀원이 합류하더라도 복잡한 설치 과정 없이 단 몇 개의 명령어로 전체 개발 환경을 즉시 구성할 수 있습니다.
  • 클라우드 친화적: AWS의 ECS (Elastic Container Service)EKS (Elastic Kubernetes Service)와 같은 현대적인 클라우드 서비스는 모두 컨테이너 기반으로 동작합니다. 로컬에서 Docker를 사용하는 것은 클라우드 배포 파이프라인으로 나아가는 첫걸음입니다.

프로젝트 구조 설계

효율적인 관리를 위해 다음과 같은 디렉토리 구조로 프로젝트를 시작하겠습니다.

my-project/
├── .env          # 환경 변수 파일
├── docker-compose.yml # Docker Compose 설정 파일
└── app/
    ├── Dockerfile    # Django 앱을 위한 Dockerfile
    ├── manage.py
    ├── myproject/
    │   ├── settings.py
    │   └── ...
    └── requirements.txt # Python 의존성 목록

1단계: Django 애플리케이션 Dockerfile 작성

먼저 Django 애플리케이션을 실행할 컨테이너 이미지를 정의하는 Dockerfile을 작성합니다. 이 파일은 app/ 디렉토리 내에 위치합니다.

app/Dockerfile

# 1. 베이스 이미지 선택
FROM python:3.11-slim

# 2. 파이썬 관련 환경 변수 설정
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

# 3. 작업 디렉토리 생성 및 설정
WORKDIR /app

# 4. 의존성 파일 복사 및 설치
COPY requirements.txt .
RUN pip install --upgrade pip && pip install -r requirements.txt

# 5. 애플리케이션 코드 복사
COPY . .

# 6. Django 개발 서버 실행
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]

app/requirements.txt

Django>=4.2
psycopg2-binary
redis
gunicorn

Dockerfile은 Python 3.11 이미지를 기반으로, 필요한 패키지를 설치하고 애플리케이션 코드를 복사한 뒤 개발 서버를 실행하는 과정을 정의합니다.

2단계: Docker Compose로 서비스 오케스트레이션

이제 프로젝트의 루트 디렉토리에 docker-compose.yml 파일을 작성하여 여러 서비스(웹, 데이터베이스, 캐시)를 한 번에 정의하고 연결합니다.

docker-compose.yml

version: '3.8'

services:
  # 1. Django 웹 서비스
  web:
    build:
      context: ./app
      dockerfile: Dockerfile
    command: python manage.py runserver 0.0.0.0:8000
    volumes:
      - ./app:/app  # 로컬 코드와 컨테이너 내부 코드 실시간 동기화
    ports:
      - "8000:8000" # 호스트의 8000번 포트와 컨테이너의 8000번 포트 연결
    env_file:
      - ./.env      # 환경 변수 파일 로드
    depends_on:
      - db
      - redis

  # 2. PostgreSQL 데이터베이스 서비스
  db:
    image: postgres:15
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    environment:
      - POSTGRES_DB=${SQL_DATABASE}
      - POSTGRES_USER=${SQL_USER}
      - POSTGRES_PASSWORD=${SQL_PASSWORD}

  # 3. Redis 캐시 서비스
  redis:
    image: redis:7

volumes:
  postgres_data: # 데이터베이스 데이터를 영속적으로 저장하기 위한 볼륨

이 설정 파일은 web, db, redis라는 세 개의 서비스를 정의합니다.

  • web: app/Dockerfile을 빌드하여 생성하며, 로컬의 app 디렉토리를 컨테이너 내부의 /app으로 마운트하여 코드 수정이 즉시 반영되도록 합니다.
  • db: 공식 PostgreSQL 이미지를 사용하며, 컨테이너가 삭제되더라도 데이터가 유지되도록 postgres_data라는 볼륨(volume)을 사용합니다.
  • redis: 공식 Redis 이미지를 사용합니다.
  • depends_on: web 서비스가 dbredis 서비스가 실행된 후에 시작되도록 의존성을 설정합니다.

3단계: 환경 변수 관리 (.env 파일)

데이터베이스 접속 정보와 같은 민감한 정보는 코드에 직접 작성하는 대신 환경 변수를 사용하는 것이 안전하고 바람직합니다. 프로젝트 루트에 .env 파일을 생성합니다.

.env

# PostgreSQL Settings
SQL_DATABASE=mydb
SQL_USER=myuser
SQL_PASSWORD=mypassword

# Django Settings
SECRET_KEY=your-django-secret-key-here
DEBUG=1

이렇게 분리된 환경 변수는 docker-compose.ymlenv_file 지시어를 통해 web 서비스로 주입됩니다. Django의 settings.py에서는 os.environ.get()을 사용하여 이 값들을 읽어오도록 수정해야 합니다.

실행 및 검증

모든 설정이 완료되었습니다. 이제 터미널에서 다음 명령어를 실행하여 전체 개발 환경을 구동합니다.

# 컨테이너 이미지 빌드 및 실행 (백그라운드에서 실행하려면 -d 옵션 추가)
docker-compose up --build

# 실행 중인 컨테이너 목록 확인
docker-compose ps

# Django 데이터베이스 마이그레이션 실행
docker-compose exec web python manage.py migrate

docker-compose up 명령이 성공적으로 실행되면, 이제 웹 브라우저에서 http://localhost:8000으로 접속하여 Django 애플리케이션이 PostgreSQL 데이터베이스 및 Redis와 연동하여 정상적으로 동작하는 것을 확인할 수 있습니다. 코드를 수정한 후에는 별도의 빌드 과정 없이 변경 사항이 즉시 컨테이너에 반영됩니다.

이처럼 Docker Compose를 활용하면 복잡한 다중 서비스 아키텍처도 단 몇 개의 설정 파일과 명령어로 손쉽게 관리할 수 있습니다. 이는 개인 프로젝트뿐만 아니라 여러 개발자가 협업하는 팀 프로젝트에서 개발 환경의 표준화를 이루고 생산성을 극대화하는 강력한 도구가 될 것입니다. 또한, 이렇게 컨테이너화된 애플리케이션은 향후 AWS와 같은 클라우드 환경으로 이전할 때 매우 유리한 고지를 점하게 됩니다.

참고문헌