Python 웹 배포 | Heroku, AWS, Docker 배포 완벽 정리

Python 웹 배포 | Heroku, AWS, Docker 배포 완벽 정리

이 글의 핵심

Python 웹 배포에 대해 정리한 개발 블로그 글입니다. from dotenv import load_dotenv import os

들어가며

”개발은 끝, 이제 배포”

배포는 애플리케이션을 실제 사용자에게 제공하는 과정입니다.


1. 배포 준비

requirements.txt

서버에 올릴 때는 개발 PC에 깔린 패키지 목록을 영수증처럼 고정해 두는 것이 안전합니다. pip freeze로 버전까지 적어 두면, 나중에 같은 조합을 다시 설치하기 쉽습니다.

# 패키지 목록 생성
pip freeze > requirements.txt
Flask==2.3.0
gunicorn==20.1.0
python-dotenv==1.0.0

환경 변수 (.env)

# .env
SECRET_KEY=your-secret-key
DATABASE_URL=postgresql://user:pass@localhost/db
DEBUG=False
# app.py
from dotenv import load_dotenv
import os

load_dotenv()

app.config['SECRET_KEY'] = os.getenv('SECRET_KEY')
app.config['DEBUG'] = os.getenv('DEBUG', 'False') == 'True'

2. Gunicorn 설정

Gunicorn으로 실행

# 설치
pip install gunicorn

# 실행
gunicorn app:app

# 워커 설정
gunicorn -w 4 -b 0.0.0.0:8000 app:app

gunicorn.conf.py

bind = "0.0.0.0:8000"
workers = 4
worker_class = "sync"
timeout = 30
keepalive = 2

3. Docker 배포

Dockerfile

FROM python:3.11-slim

WORKDIR /app

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

COPY . .

EXPOSE 8000

CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:8000", "app:app"]

docker-compose.yml

version: '3.8'

services:
  web:
    build: .
    ports:
      - "8000:8000"
    environment:
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    depends_on:
      - db
  
  db:
    image: postgres:15
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=pass
      - POSTGRES_DB=mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
# 실행
docker-compose up -d

4. Heroku 배포

Procfile

web: gunicorn app:app

runtime.txt

python-3.11.0

배포 명령어

# Heroku CLI 설치 후
heroku login
heroku create myapp

# 환경 변수 설정
heroku config:set SECRET_KEY=your-secret-key

# 배포
git push heroku main

# 로그 확인
heroku logs --tail

5. AWS 배포 (EC2)

EC2 설정

# 서버 접속
ssh -i key.pem ubuntu@ec2-instance

# Python 설치
sudo apt update
sudo apt install python3-pip python3-venv

# 프로젝트 클론
git clone https://github.com/user/myapp.git
cd myapp

# 가상환경
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Gunicorn 실행
gunicorn -w 4 -b 0.0.0.0:8000 app:app

Nginx 설정

# /etc/nginx/sites-available/myapp
server {
    listen 80;
    server_name example.com;
    
    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}
# Nginx 활성화
sudo ln -s /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx

6. 프로덕션 배포 전에 확인할 항목

서버에 올리는 순간 앱은 디버그 모드가 꺼진 채 외부와 연결됩니다. 비밀 키·DB URL은 환경 변수로만 두고, Django라면 ALLOWED_HOSTScollectstatic·migrate까지 한 번에 점검하는 습관이 필요합니다. HTTPS는 인증서(예: Let’s Encrypt)나 프록시 뒤에서 종료하는 방식으로 맞춥니다.

# ✅ 환경 변수
# SECRET_KEY, DATABASE_URL 등

# ✅ DEBUG = False
app.config['DEBUG'] = False

# ✅ ALLOWED_HOSTS (Django)
ALLOWED_HOSTS = ['yourdomain.com']

# ✅ 정적 파일
python manage.py collectstatic

# ✅ 데이터베이스 마이그레이션
python manage.py migrate

# ✅ HTTPS 설정
# Let's Encrypt, Cloudflare

실전 심화 보강

실전 예제: Gunicorn + systemd 유닛 (프로덕션 최소 패턴)

애플리케이션은 myapp.wsgi:app이라고 가정합니다. 소켓 활성화 대신 여기서는 127.0.0.1:8000 바인드 예시를 둡니다.

/etc/systemd/system/myapp.service:

[Unit]
Description=My Gunicorn App
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/myapp
Environment="PATH=/var/www/myapp/venv/bin"
EnvironmentFile=/etc/myapp.env
ExecStart=/var/www/myapp/venv/bin/gunicorn -w 4 -b 127.0.0.1:8000 myapp.wsgi:app
Restart=always

[Install]
WantedBy=multi-user.target

배포 후 sudo systemctl daemon-reload && sudo systemctl enable --now myapp으로 기동합니다.

자주 하는 실수

  • DEBUG=True로 운영에 올려 시크릿·트레이스백이 노출되는 경우.
  • 가상환경 경로를 하드코딩해 배포 스크립트가 깨지는 경우.
  • 헬스체크 없이 로드밸런서만 믿고 프로세스가 죽은 줄 모르는 경우.

주의사항

  • 시크릿은 환경 변수·비밀 저장소에 두고 Git에 넣지 마세요.
  • ALLOWED_HOSTS·CORS·CSRF는 프로덕션 프로파일에서 재검증합니다.

실무에서는 이렇게

  • 리버스 프록시(Nginx/Caddy) 앞에 두고 TLS 종료를 맡깁니다.
  • 로그는 journald + 중앙 집중(CloudWatch, ELK)으로 보냅니다.
  • 컨테이너라면 읽기 전용 루트fs + non-root 유저를 기본으로 합니다.

비교 및 대안

방식장점
PaaS(Heroku 등)운영 단순
VM + systemd제어·비용 트레이드오프
Kubernetes대규모·멀티 서비스

추가 리소스


정리

핵심 요약

  1. Gunicorn: WSGI 서버
  2. Docker: 환경 일관성
  3. Heroku: 간단한 배포
  4. AWS: 유연하고 저렴
  5. Nginx: 리버스 프록시

다음 단계

  • Pandas 데이터 분석
  • 웹 스크래핑

관련 글

  • Python 환경 설정 | Windows/Mac에서 Python 설치하고 시작하기
  • Python 기본 문법 | 변수, 연산자, 조건문, 반복문 완벽 가이드