FastAPI in Docker — 공식 배포 가이드 (FastAPI Docs)
Source: https://fastapi.tiangolo.com/deployment/docker/ Type: Article By: Sebastián Ramírez (tiangolo) Valid as of: 2026-04-26
핵심 Takeaway
- 컨테이너(Container): 경량 독립 환경에서 호스트의 Linux 커널 공유하여 애플리케이션 + 의존성 격리 운영
- Dockerfile: 정적 이미지 블루프린트 (파일, 환경변수, 시작 명령 정의)
- 레이어 캐싱 최적화:
requirements.txt먼저 복사 → RUN pip → 앱 코드 나중에 복사 (의존성 변경 빈도 < 코드 변경 빈도) - 기본 Dockerfile 구조:
FROM(기본 이미지) →WORKDIR(작업 디렉토리) →COPY(파일) →RUN(설치) →CMD(시작) - CMD exec form 필수:
CMD ["fastapi", "run", "app/main.py"](shell form 금지:CMD fastapi run app/main.py) - 여러 워커:
CMD ["fastapi", "run", "app/main.py", "--workers", "4"]로 다중 프로세스 병렬 실행 - HTTPS는 외부 처리: 컨테이너는 HTTP(포트 80)만, Traefik/Nginx 역프록시에서 HTTPS/SSL 담당
상세 요약
컨테이너 & 이미지의 기본 개념
컨테이너 (Container):
- 정의: 애플리케이션 및 모든 의존성(라이브러리, 설정)을 격리된 환경에 패키징한 것
- 특징: 호스트 Linux 커널 공유 → 가볍고 빠름 (VM보다 오버헤드 작음)
- 격리: 네트워크, 파일시스템, 프로세스가 서로 독립적
컨테이너 이미지 (Container Image):
- 정의: 컨테이너 생성 시 사용할 정적 패키지
- 포함 요소: 파일 시스템, 환경변수, 시작 명령(CMD)
- 배포: 이미지는 어디서나 동일한 컨테이너 생성 (재현성 보장)
Dockerfile 작성 및 최적화
기본 디렉토리 구조:
.
├── app
│ ├── __init__.py
│ └── main.py
├── Dockerfile
└── requirements.txt
Dockerfile 구조 (6단계):
FROM python:3.14 # 1. 기본 이미지 선택
WORKDIR /code # 2. 컨테이너 내 작업 디렉토리
COPY ./requirements.txt /code/requirements.txt # 3. 의존성 목록 복사
RUN pip install --no-cache-dir --upgrade -r /code/requirements.txt # 4. 의존성 설치
COPY ./app /code/app # 5. 애플리케이션 코드 복사
CMD ["fastapi", "run", "app/main.py", "--port", "80"] # 6. 시작 명령 (exec form)각 단계의 목적:
| 단계 | 명령 | 설명 |
|---|---|---|
| 1 | FROM python:3.14 | 공식 Python 베이스 이미지 사용 (경량화된 -slim 권장) |
| 2 | WORKDIR /code | 컨테이너 내 모든 파일 작업의 루트 (상대 경로 기준점) |
| 3 | COPY requirements.txt /code/ | 의존성 목록만 먼저 복사 |
| 4 | RUN pip install | 의존성 설치 (캐싱됨: requirements.txt 미변경 시 재사용) |
| 5 | COPY ./app /code/app | 애플리케이션 코드 복사 (자주 변경되므로 마지막) |
| 6 | CMD ["fastapi", "run", ...] | 컨테이너 시작 시 실행할 명령 |
레이어 캐싱 & 빌드 최적화
Docker 빌드는 각 명령을 하나의 “레이어”로 캐시한다. 이전 결과가 변경되지 않으면 캐시 재사용.
캐싱 최적화 핵심:
requirements.txt: 변경 빈도 낮음 (수주 단위) → 빌드 초반- 애플리케이션 코드: 변경 빈도 높음 (매일) → 빌드 후반
결과:
- 의존성 미변경 시:
RUN pip install레이어 캐시 재사용 → 빌드 시간 10초 - 코드 변경 시: 5번 단계부터만 재실행 → 나머지 캐시 재사용 → 빌드 시간 20초
캐시 효율 낮은 패턴 (피하기):
# ❌ 나쁜 예: 의존성 먼저, 코드는 함께
COPY . /code/
RUN pip install -r requirements.txt→ 코드 1줄만 변경해도 RUN pip install부터 재실행 (느림)
이미지 빌드 & 컨테이너 실행
이미지 빌드:
docker build -t myimage .-t myimage: 이미지 이름 지정 (태그).: 현재 디렉토리의 Dockerfile 사용
컨테이너 실행:
docker run -d --name mycontainer -p 80:80 myimage-d: 백그라운드 실행--name mycontainer: 컨테이너 이름 지정-p 80:80: 호스트 포트 80 → 컨테이너 포트 80 포워딩
다중 워커(Workers) 설정
기본: FastAPI는 단일 워커(단일 프로세스) 실행 → 동시 요청 처리 제한
다중 워커 활성화:
CMD ["fastapi", "run", "app/main.py", "--port", "80", "--workers", "4"]- 4개 워커 프로세스 병렬 실행
- 동시 요청 처리량 4배 증가
- CPU 다중 코어 활용
CMD 형식: Exec form vs Shell form
올바른 형식 (Exec form):
CMD ["fastapi", "run", "app/main.py", "--port", "80"]- 형태: JSON 배열
- 동작:
fastapi프로세스를 직접 실행 (PID 1) - 장점: 시그널(SIGTERM) 정상 처리 → 컨테이너 우아한 종료
잘못된 형식 (Shell form):
CMD fastapi run app/main.py --port 80- 형태: 문자열
- 동작:
/bin/sh에서 실행 (PID 1은 shell) - 문제: 시그널 미수신 → 강제 종료(SIGKILL) → 우아하지 않음
HTTPS/SSL 처리: 외부 레이어
FastAPI 컨테이너는 HTTP(포트 80)만 처리. HTTPS와 SSL/TLS 인증서는 외부 계층에서 관리:
- Traefik: 리버스 프록시 + 자동 인증서 갱신 (Let’s Encrypt)
- Nginx: 경량 리버스 프록시
- 클라우드 제공자: AWS ALB, Google Cloud Load Balancer 등
구조:
클라이언트 ─(HTTPS 443)─ Traefik ─(HTTP 80)─ FastAPI
↑
SSL/TLS 인증서 관리
선행 개념
이 개념을 배우기 전에 필수로 알아야 할 것:
- Module 1-1 → python-type-hints-fastapi: FastAPI의 타입 기반 검증 이해
- 왜?: Dockerfile 작성 시 FastAPI 애플리케이션의 구조를 이해해야 함
- Module 1-4 → pydantic-validation-velog: Pydantic 모델을 통한 요청/응답 검증
- 왜?: FastAPI 애플리케이션이 Pydantic 모델을 포함하고 있으므로, 의존성 설치 시 이를 고려해야 함
후속 개념 (이 개념이 선행)
이 개념을 배운 후 다음 단계:
- Module 6-2 → docker-compose-multi-service-orchestration: 여러 서비스(FastAPI + DB + Traefik) 통합
- 이 소스: 단일 FastAPI 컨테이너만 다룸
- 다음 단계: Docker Compose로 전체 스택 관리
- Module 4-2 → fastapi-docker-best-practices-production: 프로덕션 배포 모범 사례
연결되는 위키 페이지
- containerization — 컨테이너화 개념 및 Docker 아키텍처
- docker — Docker 도구 및 명령어
- fastapi — FastAPI 프레임워크
- reverse-proxy — 리버스 프록시 개념 (Traefik, Nginx)