기능이 갖춰졌다면 실행 환경을 프로덕션 수준으로 정리해야 합니다. 환경 변수는 운영체제가 보관하는 설정 값이라서 소스 코드에 비밀을 남기지 않고 주입할 수 있습니다. uvicorn은 FastAPI 앱을 실제 요청과 연결하는 ASGI 서버라서 배포 시 기본 실행기 역할을 합니다. uv 개발 서버는 확인용이지만, 실제 배포에서는 uvicorn, 프로세스 매니저, 환경 변수 관리가 필요합니다.
이번 글에서 새로 나오는 용어
- 환경 변수: 운영체제가 들고 있는 설정 값으로, 비밀번호나 DB 주소를 코드 밖에서 안전하게 주입하기 위해 사용합니다.
- .env: 개발용으로 환경 변수를 미리 적어 두는 파일 형식으로,
pydantic-settings가 읽어 기본값 위에 덮어씁니다. - pydantic-settings: 환경 변수·
.env·기본값을 한 클래스에서 계층적으로 읽어 주는 라이브러리로, 글에서Settings클래스를 만들 때 사용합니다. - 프로세스 매니저: systemd, Supervisor 같은 도구로, uvicorn 프로세스를 재시작·모니터링해 서비스가 항상 살아 있도록 유지합니다.
실습 카드
- 예상 소요 시간: 50분
- 사전 준비: 10편 인증 코드,
.env사용 경험- 실습 목표:
pydantic-settings로 환경 값을 읽고 uvicorn 실행 명령을 구분한다
설정 계층 만들기
설정 계층은 환경 변수 → .env → 기본값 순으로 읽는 구조가 가장 예측 가능합니다. pydantic-settings는 이 계층을 작은 클래스로 묶어 줍니다.
위 흐름을 머릿속에 두면 어느 값이 실제로 적용됐는지 빠르게 추적할 수 있고, CI에서도 동일한 순서를 그대로 재현할 수 있습니다.
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
database_url: str = "sqlite:///./todo.db"
secret_key: str
uv_reload: bool = False
model_config = {
"env_file": ".env",
"env_prefix": "APP_",
}
settings = Settings()
.env 예시:
APP_SECRET_KEY=please-change
APP_DATABASE_URL=postgresql+psycopg://user:pass@db/todo
코드에서 기본값을 제공하고 .env로 덮어쓴 뒤, 최종적으로 운영 환경 환경 변수가 가장 높은 우선순위를 가져갑니다. 이 계층 덕분에 같은 코드를 어디서든 안전하게 실행할 수 있습니다.
uvicorn 실행 전략
개발 단계에서는 자동 리로드와 상세 오류가 필요합니다.
uv run fastapi dev app/main.py
배포 단계에서는 고정된 실행 명령과 프로세스 관리가 중요합니다.
uv run uvicorn app.main:app --host 0.0.0.0 --port 8000 --workers 4
--workers는 CPU 코어 수에 맞춰 정합니다. 로드밸런서 뒤라면 --proxy-headers로 원래 클라이언트 IP를 읽습니다. 멀티 프로세스를 안정적으로 유지하려면 systemd 서비스, Supervisor, 혹은 컨테이너 오케스트레이터를 사용합니다.
정적 파일 및 미디어
정적 자산은 단순한 경우에만 FastAPI StaticFiles로 제공합니다. 대용량 이미지는 CDN이나 객체 스토리지로 위임하면 트래픽 비용을 낮출 수 있습니다. CORS 정책은 환경마다 달라지니 설정 값으로 분리해 두어야 합니다.
로깅과 모니터링
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s %(message)s",
)
logger = logging.getLogger("todo")
로깅 포맷을 처음부터 맞춰 두면 배포 환경에서도 같은 로그를 읽을 수 있습니다. 구조화된 JSON이 필요하면 loguru나 structlog를 추가합니다. Prometheus나 OpenTelemetry 익스포터를 붙이면 지표 대시보드를 빠르게 만들 수 있습니다.
컨테이너 예시 Dockerfile
FROM ghcr.io/astral-sh/uv:python3.12-slim
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --frozen
COPY app ./app
CMD ["uv", "run", "uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
컨테이너 이미지를 만들면 CI/CD 파이프라인에서 테스트 → 이미지 빌드 → 배포 단계를 자동화할 수 있습니다. 동일 이미지가 모든 서버에 배포되므로 설정 차이가 줄어듭니다.
헬스체크와 설정 검증
/health 엔드포인트는 DB 연결과 외부 API 접속을 짧게 확인합니다. 배포 전에 Settings.model_validate를 호출해 필수 환경 변수가 빠지지 않았는지 검사합니다. 이런 검증을 CI에 넣으면 배포 실패를 사전에 막을 수 있습니다.
실습
- 따라 하기:
Settings클래스를 만들고.env에서APP_SECRET_KEY를 읽어 uvicorn 실행 시 주입한다. - 확장하기: Dockerfile을 작성하거나 systemd 서비스 유닛을 만들어 프로덕션 실행 명령을 스크립트로 남긴다.
- 디버깅: 환경 변수가 누락되었을 때 앱이 친절한 오류를 출력하도록
ValidationError를 확인한다. - 완료 기준: 로컬/프로덕션 실행 명령이 분리돼 있고, 설정 검증이 배포 전 자동화된다.
마무리
환경 변수와 uvicorn 실행 전략을 명확히 나눠 두면 배포 환경에서도 예측 가능한 동작을 유지할 수 있습니다. 지금 정리한 구성을 토대로 다음 편에서는 인증, 데이터, 설정을 묶어 작은 서비스를 완성해 보겠습니다.
💬 댓글
이 글에 대한 의견을 남겨주세요