/인프라/FastAPI API, Docker와 Kubernetes로 프로덕션 환경에 배포하는 완벽 실습 가이드
인프라FastAPIDocker

FastAPI API, Docker와 Kubernetes로 프로덕션 환경에 배포하는 완벽 실습 가이드

FastAPI로 개발한 Python API를 Docker 컨테이너로 패키징하고, Kubernetes 클러스터에 안정적으로 배포하는 전 과정을 단계별로 안내합니다. 개발부터 운영까지, 실무에서 바로 적용 가능한 컨테이너 오케스트레이션 로드맵을 경험하세요.

FastAPI API, Docker와 Kubernetes로 프로덕션 환경에 배포하는 완벽 실습 가이드

FastAPI API, Docker와 Kubernetes로 프로덕션 환경에 배포하는 완벽 실습 가이드

"로컬 환경에서는 완벽하게 돌아갔는데, 스테이징 서버에 올리니 500 에러가 나요."

이 문장, 백엔드 개발자라면 누구나 한 번쯤 겪어봤을 법한 고통의 순간일 겁니다. 우리는 수많은 시간을 비즈니스 로직(Business Logic)을 짜는 데 쏟지만, 막상 이 코드를 '실제 운영 환경'이라는 거대한 생태계에 올리는 '배포(Deployment)' 과정은 마치 블랙박스처럼 느껴지곤 합니다.

FastAPI 같은 최신 프레임워크로 멋진 API를 완성했다고 해도, 이 코드가 트래픽을 감당하며 24시간 안정적으로 동작하려면 컨테이너화(Containerization)와 오케스트레이션(Orchestration)이라는 거대한 산을 넘어야 합니다.

이 가이드는 이론으로만 접했던 Docker와 Kubernetes를, 여러분이 직접 개발한 FastAPI 코드를 가지고 '실제로 배포'하는 과정을 따라 하며 완벽하게 이해할 수 있도록 설계되었습니다. 주니어 개발자부터 DevOps 엔지니어까지, 이 포스트 하나로 배포의 전 과정을 마스터할 수 있을 겁니다.


🚀 1단계: FastAPI 애플리케이션 컨테이너화하기 (Dockerizing)

애플리케이션을 독립적인 '패키지'로 만드는 과정이 바로 컨테이너화입니다. Docker는 이 패키징을 표준화하는 가장 강력한 도구입니다.

1. FastAPI 기본 코드 준비

먼저, 배포할 간단한 FastAPI 코드를 준비합니다. main.py 파일에 아래 코드를 작성해 주세요.

Python
# main.py
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
def read_item(item_id: int, q: str = None):
    """
    특정 ID의 아이템 정보를 조회하는 엔드포인트입니다.
    """
    return {"item_id": item_id, "q": q, "message": "Successfully deployed via Docker!"}

# 참고: 실제 운영 시에는 uvicorn을 사용하여 서버를 구동합니다.

그리고 의존성 파일 requirements.txt를 작성합니다.

TEXT
# requirements.txt
fastapi
uvicorn[standard]

2. 최적화된 Dockerfile 작성 원칙

단순히 FROM python:3.10만 사용하는 것은 최적화가 아닙니다. 운영 환경에서는 이미지 크기 최소화보안 강화가 핵심입니다. 이를 위해 '멀티 스테이지 빌드(Multi-stage Build)'를 사용합니다.

Dockerfile 예시:

Dockerfile
# --------------------------------------
# STAGE 1: Builder Stage (의존성 설치 및 빌드)
# --------------------------------------
FROM python:3.11-slim AS builder
WORKDIR /app

# 캐시 효율성을 위해 requirements.txt를 먼저 복사하여 레이어를 분리
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# 나머지 소스 코드를 복사
COPY . .

# --------------------------------------
# STAGE 2: Final Stage (최종 실행 이미지)
# --------------------------------------
# 가장 가볍고 보안에 강한 기본 이미지 사용
FROM python:3.11-slim
WORKDIR /app

# 빌더 스테이지에서 설치된 라이브러리만 복사 (불필요한 빌드 도구 제거)
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /app /app

# 컨테이너가 노출할 포트 정의
EXPOSE 8000

# 컨테이너 시작 시 실행할 명령어 정의
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

3. 로컬 빌드 및 테스트

이제 터미널에서 다음 명령어를 실행하여 이미지를 빌드하고, 로컬에서 동작을 검증합니다.

Bash
# 1. 이미지 빌드 (my-fastapi-app:latest 태그 사용)
docker build -t my-fastapi-app:latest .

# 2. 로컬 포트 8080으로 컨테이너 실행 및 테스트
docker run -d -p 8080:8000 --name fastapi-test my-fastapi-app:latest

✅ 테스트 확인: 브라우저나 curlhttp://localhost:8080/items/1?q=test에 접속해 보세요. FastAPI가 정상적으로 응답하는 것을 확인할 수 있습니다.


🌐 2단계: Kubernetes 환경 이해 및 Manifest 작성하기 (Orchestration)

Docker가 '단일 컨테이너'를 패키징하는 것이라면, Kubernetes(K8s)는 이 컨테이너들을 '대규모로 관리하고 자동 복구'하는 운영체제 같은 역할을 합니다.

K8s에서 애플리케이션을 배포하려면 최소한 다음 세 가지 개념을 이해해야 합니다.

  1. Deployment: 애플리케이션의 '상태'를 정의합니다. "항상 3개의 Pod가 이 이미지를 사용해서 실행되어야 한다"와 같은 선언적 상태를 유지합니다.
  2. Service: Pod들은 IP 주소가 계속 바뀝니다. Service는 이 변동하는 Pod들에게 **안정적인 네트워크 접근 주소(Cluster IP)**를 제공하는 역할을 합니다.
  3. Ingress: 외부 트래픽(인터넷)이 클러스터 내부로 들어오는 '관문' 역할을 합니다. (예: api.mycompany.com/items 요청을 특정 Service로 라우팅)

💡 K8s Manifest YAML 작성 예시

실제 배포를 위해 deployment.yamlservice.yaml을 작성합니다. (여기서 my-fastapi-app:latest는 1단계에서 만든 이미지 이름입니다.)

deployment.yaml:

YAML
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
  labels:
    app: fastapi
spec:
  replicas: 3 # 3개의 Pod를 항상 유지하도록 설정
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
      - name: fastapi-container
        image: your-docker-registry/my-fastapi-app:latest # 실제 레지스트리 경로로 변경 필수
        ports:
        - containerPort: 8000
        # 환경 변수 설정 예시
        env:
        - name: ENVIRONMENT
          value: production

service.yaml:

YAML
apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
spec:
  selector:
    app: fastapi # Deployment에서 정의한 레이블과 일치해야 함
  ports:
    - protocol: TCP
      port: 80 # 클러스터 내부에서 접근할 포트
      targetPort: 8000 # 컨테이너가 실제로 리스닝하는 포트
  type: ClusterIP # 내부 서비스용 기본 타입

🛠️ 3단계: 실제 클러스터에 배포하고 검증하기 (실습 중심)

이제 준비된 Manifest 파일을 클러스터에 적용할 차례입니다.

1. 배포 실행 명령어

클러스터에 접속한 후, 다음 명령어를 순차적으로 실행합니다.

Bash
# 1. Deployment와 Service를 한 번에 적용
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

# 2. 배포 상태 확인 (Pod가 Running 상태가 될 때까지 대기)
kubectl get pods -l app=fastapi

💡 문제 해결: Pod가 Pending 상태일 때?

만약 Pod가 Pending 상태로 멈춰있다면, 다음 명령어로 상세 로그를 확인하세요. kubectl describe pod <pod-name>

🚀 실제 서비스 노출 (Ingress/Service Type 변경)

외부에서 접근 가능하게 하려면, Service 정의 시 type: LoadBalancer를 사용하거나, 실제 운영 환경에서는 Ingress Controller를 사용하는 것이 표준입니다.


📚 요약 및 학습 포인트

단계도구/개념목적핵심 명령어
컨테이너화Dockerfile애플리케이션을 격리된 환경으로 패키징docker build, docker push
오케스트레이션Kubernetes (K8s)컨테이너의 배포, 확장, 관리를 자동화kubectl apply -f, kubectl get pods
서비스 노출Service / Ingress외부 트래픽을 내부 컨테이너로 라우팅kubectl expose, Ingress Controller

이 과정을 통해 여러분은 단순히 코드를 작성하는 것을 넘어, 실제 운영 환경에서 서비스를 배포하고 관리하는 엔지니어링 사이클을 완벽하게 경험하게 됩니다.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Reviewer·검토 · 사람 편집자·발행 · 2026년 6월 7일

댓글

불러오는 중...