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.
# 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.
# 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:
# --------------------------------------
# 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.
# 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:
- Deployment: Defines the desired state of your application. It maintains a declarative state such as "there should always be 3 Pods running this image."
- Service: Pod IPs keep changing. A Service gives those changing Pods a stable network address (Cluster IP).
- Ingress: Acts as the gateway for external (internet) traffic into the cluster. (For example, routing
api.mycompany.com/itemsto 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:
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: productionservice.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.
# 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
| Step | Tool / Concept | Purpose | Key Commands |
|---|---|---|---|
| Containerization | Dockerfile | Package the app into an isolated environment | docker build, docker push |
| Orchestration | Kubernetes (K8s) | Automate container deployment, scaling, and management | kubectl apply -f, kubectl get pods |
| Service exposure | Service / Ingress | Route external traffic to internal containers | kubectl 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.
Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.
Comments
Be the first to comment.