/인프라/Complete Hands-On Guide to Deploying a FastAPI API to Production with Docker and Kubernetes
InfrastructureFastAPIDocker

Complete Hands-On Guide to Deploying a FastAPI API to Production with Docker and Kubernetes

A step-by-step walkthrough of packaging a FastAPI Python API into a Docker container and deploying it reliably to a Kubernetes cluster. Follow a production-ready container orchestration roadmap you can apply from development through operati

Complete Hands-On Guide to Deploying a FastAPI API to Production with Docker and Kubernetes

Complete Hands-On Guide to Deploying a FastAPI API to Production with Docker and Kubernetes

"It worked perfectly locally, but as soon as I pushed it to staging I got a 500."

If you're a backend developer, you've almost certainly lived through that painful moment. We pour countless hours into business logic, but the moment we try to drop that code into the vast ecosystem of a real production environment, deployment often feels like a black box.

Even after you've built a polished API with a modern framework like FastAPI, getting that code to handle traffic and run reliably 24/7 means climbing two big mountains: containerization and orchestration.

This guide is designed so you can fully understand Docker and Kubernetes—topics you've probably only seen in theory—by actually deploying FastAPI code you wrote yourself. From junior developers to DevOps engineers, this one post should take you through the entire deployment lifecycle.


🚀 Step 1: Containerizing Your FastAPI Application (Dockerizing)

Containerization is the process of turning your application into a self-contained package. Docker is the most powerful tool for standardizing that packaging.

1. Prepare a Basic FastAPI App

First, prepare a simple FastAPI app to deploy. Put the following code in 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을 사용하여 서버를 구동합니다.

Then create a requirements.txt dependency file.

TEXT
# requirements.txt
fastapi
uvicorn[standard]

2. Principles for Writing an Optimized Dockerfile

Simply using FROM python:3.10 is not an optimized approach. In production, minimizing image size and hardening security are what matter. That's why we use a multi-stage build.

Example 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. Local Build and Test

Now run the following commands in your terminal to build the image and verify it locally.

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

✅ Verify the test: Open http://localhost:8080/items/1?q=test in a browser or with curl. You should see FastAPI respond successfully.


🌐 Step 2: Understanding Kubernetes and Writing Manifests (Orchestration)

If Docker packages a single container, Kubernetes (K8s) is like an operating system that manages those containers at scale and automatically heals them.

To deploy an application on K8s, you need at least these three concepts:

  1. Deployment: Defines the desired state of your application. It maintains a declarative state such as "there should always be 3 Pods running this image."
  2. Service: Pod IPs keep changing. A Service gives those changing Pods a stable network address (Cluster IP).
  3. Ingress: Acts as the gateway for external (internet) traffic into the cluster. (For example, routing api.mycompany.com/items to a specific Service.)

💡 Example K8s Manifest YAML

For the actual deployment, write deployment.yaml and service.yaml. (Here my-fastapi-app:latest is the image name from Step 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 # 내부 서비스용 기본 타입

🛠️ Step 3: Deploy to a Real Cluster and Verify (Hands-On)

Now it's time to apply the prepared manifests to the cluster.

1. Deployment Commands

After connecting to the cluster, run the following commands in order.

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

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

💡 Troubleshooting: Pod Stuck in Pending?

If a Pod is stuck in Pending, inspect the details with: kubectl describe pod <pod-name>

🚀 Exposing the Service (Ingress / Changing Service Type)

To make it reachable from outside, set type: LoadBalancer on the Service, or—in real production—use an Ingress Controller, which is the standard approach.


📚 Summary and Key Takeaways

StepTool / ConceptPurposeKey Commands
ContainerizationDockerfilePackage the app into an isolated environmentdocker build, docker push
OrchestrationKubernetes (K8s)Automate container deployment, scaling, and managementkubectl apply -f, kubectl get pods
Service exposureService / IngressRoute external traffic to internal containerskubectl expose, Ingress Controller

By going through this process, you move beyond just writing code and fully experience the engineering cycle of deploying and operating a service in production.

References: Official Docs

The primary source for the behavior, configuration, and errors covered in this post is the official documentation below. Check it for version-specific options and exact behavior.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·

Comments

Be the first to comment.