Kubernetes本番運用に踏み出そう:FastAPI×Kubernetesデプロイ実践ガイド――Deployment/Service/Ingress/ConfigMap/Secret/HPA/ヘルスチェック
はじめに:この記事でできることと対象読者
FastAPIアプリを Docker で動かせるようになったあとは、「クラスタで運用したい」「スケールさせたい」というタイミングがきますよね。この記事では、FastAPIアプリを Kubernetes(K8s) 上にデプロイし、本番に近い形で スケール・設定管理・ヘルスチェック・オートスケール などを一通り体験できる構成を、サンプルとともに丁寧にまとめていきます。
対象読者(かなり具体的に)
-
個人開発者さん(学部生・社会人学習者)
Docker Compose までは使っているけれど、「Kubernetesって難しそう」と感じている方。
→ まずは 単一の FastAPI サービスをクラスタに載せる ところまで一緒にやっていきます。 -
小規模チームのエンジニアさん(3〜5名)
既に Docker イメージを本番で動かしているけれど、スケールやローリングアップデートが辛くなってきた方。
→ Deployment/Service/Ingress/ConfigMap/Secret/HPA をひと通り揃えた「雛形」を持ち帰っていただくイメージです。 -
スタートアップのSaaS開発チームさん
将来はマイクロサービス化も視野に入れており、FastAPI を複数サービスとして Kubernetes 上で動かしていきたい方。
→ 本記事ではシングルサービス前提ですが、サービスごとのマニフェスト分割や名前空間、共通設定のパターンにも触れます。
アクセシビリティ評価(読みやすさの観点)
- 構成は「最初に全体像 → 主要リソース(Deployment/Service/Ingressなど) → 設定管理 → スケール → 運用Tips → おさらい」の順で、逆三角形を意識しています。
- コードや YAML は固定幅ブロックで示し、長すぎる例は用途を分けて提示しました。
- 専門用語は初出で短く説明しつつ、その後は用語を統一して迷子になりにくくしています。
- 行間と見出しを多めに取り、スクリーンリーダーでも章構造が追いやすいように配慮しています。
全体として、技術的背景が少しある方を対象にした AA 相当の読みやすさを目標にしました。
1. Kubernetesデプロイの全体像をつかむ
まずは、FastAPI アプリが Kubernetes 上でどういうリソースに分かれて動くのか、ざっくりイメージをそろえましょう。
1.1 主な登場人物
-
Deployment
アプリの Pod(コンテナ)の 望ましい数とテンプレート を定義。ローリングアップデートやセルフヒーリングの中核です。 -
Service
Pod の IP は短命なので、安定した 名前付きの入口 を用意するリソース。LoadBalancer や ClusterIP などの種類があります。 -
Ingress
外部からの HTTP/HTTPS を適切な Service に振り分けるためのルール。クラスタ外の世界とのゲートウェイ役です。 -
ConfigMap / Secret
環境変数・設定値・機密情報(パスワード、トークン)を外出しして管理するためのリソースです。 -
Horizontal Pod Autoscaler (HPA)
CPU やカスタムメトリクスを見ながら、Pod 数を自動的にスケールさせるためのリソースです。 -
Liveness / Readiness Probe
コンテナの中身が「生きているか」「リクエストを受け取る準備ができているか」を判断するためのヘルスチェック設定です。
1.2 今回つくる最小構成
-
既にある FastAPI の Docker イメージ(例:
my-fastapi:latest)を使う -
以下の Kubernetes マニフェストを用意する
Deployment(FastAPIコンテナ + liveness/readiness)Service(ClusterIP / NodePort など)Ingress(/api へのルーティング)ConfigMap(非機密の設定)Secret(DBパスワードなど)HPA(CPUベースのオートスケール)
-
ローカルの Minikube や kind、もしくはクラウドのマネージドK8s(EKS/GKE/AKSなど)で動作確認する、という流れで考えます。
2. FastAPIイメージの前提を確認する
Kubernetes 側の話に入る前に、FastAPI のコンテナイメージがどんな構成になっているかを確認しておきます。
2.1 典型的な Dockerfile(復習)
FROM python:3.11-slim AS base
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt /app/
RUN pip install --upgrade pip && pip install -r requirements.txt
COPY app /app/app
# 非rootユーザーで動かす
RUN useradd -m appuser && chown -R appuser:appuser /app
USER appuser
ENV HOST=0.0.0.0 \
PORT=8000
EXPOSE 8000
CMD ["bash", "-lc", "exec uvicorn app.main:app --host ${HOST} --port ${PORT}"]
ここでは uvicorn で直接起動していますが、Gunicorn+UvicornWorker にしても構いません(本記事では詳細割愛します)。
2.2 Kubernetesで前提にすること
- コンテナは
/appで起動済み HOSTとPORTは環境変数で切り替え可能/health/livenessと/health/readinessのようなヘルスチェックエンドポイントが実装済み(以前の記事で紹介してきた形)
この前提でマニフェストを書いていきますね。
3. Deployment:FastAPIコンテナをクラスタに配置する
3.1 基本の Deployment マニフェスト
# k8s/deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: fastapi-app
labels:
app: fastapi-app
spec:
replicas: 2
selector:
matchLabels:
app: fastapi-app
template:
metadata:
labels:
app: fastapi-app
spec:
containers:
- name: fastapi
image: my-fastapi:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8000
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "8000"
livenessProbe:
httpGet:
path: /health/liveness
port: 8000
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/readiness
port: 8000
initialDelaySeconds: 5
periodSeconds: 5
failureThreshold: 3
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
ポイント
-
replicas: 2で常に 2 Pod を維持(最小の冗長構成)。 -
selector.matchLabelsとtemplate.metadata.labelsを揃えることで、Deployment と Pod を紐付け。 -
livenessProbeとreadinessProbeで FastAPI のヘルスチェックを実行。liveness失敗 → Kubelet がコンテナを再起動。readiness失敗 → Service からこの Pod を外して、新規リクエストを流さない。
-
resourcesで「最低限必要なリソース」と「上限」を決めておくと、HPA やノードスケジューリングの制御に役立ちます。
4. Service:安定した入口を作る
Deployment だけだと Pod を直接叩けないので、Service を定義します。
4.1 ClusterIP の例(クラスタ内アクセス用)
# k8s/service.yaml
apiVersion: v1
kind: Service
metadata:
name: fastapi-service
labels:
app: fastapi-app
spec:
type: ClusterIP
selector:
app: fastapi-app
ports:
- name: http
port: 80 # Serviceのポート
targetPort: 8000 # コンテナポート
selector.app: fastapi-appによって、Deployment が作る Pod へトラフィックを振り分け。- Service 自体は
fastapi-serviceという DNS 名でクラスタ内から参照できます(例:http://fastapi-service)。
4.2 外部公開したい場合(NodePort / LoadBalancer)
ローカルの Minikube なら NodePort、クラウドのマネージドK8sなら LoadBalancer を使うケースが多いです。
例:ロードバランサService(クラウド前提)
apiVersion: v1
kind: Service
metadata:
name: fastapi-service
spec:
type: LoadBalancer
selector:
app: fastapi-app
ports:
- port: 80
targetPort: 8000
ただし、HTTP の細かいルーティングや TLS 終端を考えると、Ingress コントローラを使うほうが柔軟なので、次の章で Ingress の例も紹介します。
5. Ingress:外部からのHTTPをFastAPIへつなぐ
Ingress は「URLパスなどのルールに基づいて、複数の Service にトラフィックを振り分ける」ための入口です。ここではシンプルに 1 つの FastAPI サービスだけを扱います。
5.1 シンプルな Ingress (/api を FastAPI にルーティング)
Ingress クラスターでよく使われるのは NGINX Ingress Controller などです。以下はその前提の例です。
# k8s/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: fastapi-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
ingressClassName: nginx # 利用するIngressクラスに合わせて変更
rules:
- host: example.local # 実環境では FQDN を指定
http:
paths:
- path: /api(/|$)(.*)
pathType: Prefix
backend:
service:
name: fastapi-service
port:
number: 80
hostによってドメイン単位でルーティングが可能。pathで/api以下のパスを FastAPI のサーバへ流しています。- 実際には TLS 設定(証明書の Secret)なども必要になりますが、ここでは本質に絞っています。
6. ConfigMap と Secret:設定と秘密を外出しする
FastAPI アプリの設定は、以前の記事で紹介したように pydantic-settings を使って環境変数から読み込むのがおすすめです。Kubernetes はその「環境変数」を作る役として、ConfigMap と Secret を提供してくれます。
6.1 ConfigMap(非機密設定)
# k8s/configmap.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: fastapi-config
data:
APP_NAME: "My FastAPI on K8s"
ENV: "prod"
LOG_LEVEL: "info"
CORS_ORIGINS: "https://app.example.com"
6.2 Secret(機密設定)
# k8s/secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: fastapi-secret
type: Opaque
data:
SECRET_KEY: cHJvZC1zZWNyZXQ= # base64("prod-secret")
DATABASE_URL: cG9zdGdyZXNxbCtwc3ljcGc6Ly91c2VyOnBhc3NAaG9zdDoyNTQzL2FwcA==
※ data の値は base64エンコード文字列 です(echo -n "prod-secret" | base64 などで生成)。
6.3 Deployment で環境変数として使う
# k8s/deployment.yaml(env部分の抜粋)
containers:
- name: fastapi
image: my-fastapi:latest
envFrom:
- configMapRef:
name: fastapi-config
- secretRef:
name: fastapi-secret
# 必要なら個別のenvも併用可能
env:
- name: HOST
value: "0.0.0.0"
- name: PORT
value: "8000"
envFromで ConfigMap / Secret を丸ごと環境変数として注入します。- pydantic-settings の
env_fileの代わりに、これらの環境変数を使う形になります。
7. Horizontal Pod Autoscaler(HPA)でオートスケール
Kubernetes の HPA を使うと、CPU 使用率が一定値を超えたときに Pod 数を増やすことができます。
7.1 シンプルな HPA の例
# k8s/hpa.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: fastapi-hpa
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: fastapi-app
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 60
averageUtilization: 60は、「全 Pod の平均 CPU 使用率が 60% を超えたらスケールアウトする」という意味です。- HPA を使うには、クラスタ側で metrics-server などが有効になっている必要があります(クラウドマネージドK8sでは大抵標準で入っています)。
7.2 FastAPI 側で意識しておきたいこと
- CPU 使用率が変わりやすいように、ブロッキング I/O の多用は避け、非同期 I/O を活かす設計にしておくとスケールが効きやすくなります。
- メトリクスを Prometheus 形式で出しておくと、HPA を「カスタムメトリクス」で制御することも視野に入ります(ここでは詳細割愛)。
8. ローカルクラスタでのデプロイ手順(例:kubectlベース)
ここまででリソースの YAML をいくつか紹介しました。次は「実際に kubectl で適用する流れ」をざっくり整理しますね。
8.1 手順の一例
-
Docker イメージをビルド
docker build -t my-fastapi:latest . -
(Minikubeの場合)イメージをクラスタで使えるようにする
eval $(minikube docker-env)してから build する
または- レジストリに push(ECR/GCR/Docker Hubなど)
-
Kubernetes マニフェストを適用
kubectl apply -f k8s/configmap.yaml kubectl apply -f k8s/secret.yaml kubectl apply -f k8s/deployment.yaml kubectl apply -f k8s/service.yaml kubectl apply -f k8s/ingress.yaml kubectl apply -f k8s/hpa.yaml -
状態を確認
kubectl get pods kubectl get svc kubectl get ingress kubectl get hpa -
Pod のログを確認
kubectl logs -f deploy/fastapi-app -
Ingress 経由でアクセス(Minikubeの場合)
minikube ip # 例: http://<minikube-ip>/api/meta
※ ローカル環境の詳細は使用しているツール(Minikube, kind, Docker Desktop など)によって少し変わります。
9. 運用の実務ポイント:ローリングアップデートとロールバック
9.1 ローリングアップデート
Deployment はイメージタグや環境変数を変更して kubectl apply すると、自動的にローリングアップデートを行います。
裏側では:
- 新しい Pod を 1つずつ起動
readinessProbeが成功したら古い Pod を 1つ落とす- これを繰り返すことで、ダウンタイムを最小化する
という動きになります。
9.2 ロールバック
もし新しいバージョンで問題が起きた場合は、前のリビジョンに戻すことも可能です。
kubectl rollout history deploy/fastapi-app
kubectl rollout undo deploy/fastapi-app
FastAPI 側では、マイグレーションとの整合性 に注意してください。DBスキーマが変わる場合は、先にマイグレーションを適用してからアプリを更新するなど、順序をしっかり決めておくことが大切です。
10. ログとメトリクスの扱い(軽く触れておきます)
10.1 ログ
-
基本は 標準出力(stdout)に構造化ログ(JSON) を吐き、
kubectl logsやログ集約基盤(Cloud Logging, Elasticsearch, Lokiなど)で閲覧します。 -
コンテナ内部でファイルに書くのではなく、Kubernetes に寄せるイメージで設計するとシンプルになります。
10.2 メトリクス・トレース
- Prometheus や OpenTelemetry と組み合わせる場合は、サイドカーや別 Podでエージェントを動かす設計もあります。
- 多サービス化していくと、「どのサービスが遅いのか」を把握するために分散トレース(Jaeger、Tempo など)を入れることがよくあります。
ここはかなり奥深い領域なので、この記事ではキーワードだけにとどめますね。
11. よくある落とし穴と対策
| 症状 | 原因 | 対策 |
|---|---|---|
| Pod が起動してすぐ落ちる | 環境変数不足、Secret名の間違い | kubectl describe pod でイベントを確認、env 出力やログでキーを確認 |
| Service 経由でアクセスできない | selector ラベル不一致 / ポート違い | Deployment と Service の labels/selector と port/targetPort を見直す |
| Ingress が 404 を返す | IngressClass 名・path 設定の不整合 | ingressClassName と Ingress Controller の設定、path の正規表現を確認 |
| HPA が動かない | metrics-server 未導入 | クラスタのメトリクス周りのセットアップを確認(クラウドならドキュメント通りに) |
| ローリングアップデートで一瞬落ちる | readinessProbe 未設定または甘い | /health/readiness の実装とプローブ設定を見直し、起動完了まで時間を持たせる |
12. 読者別に得られるメリットを整理
-
個人開発者さん
- 「Kubernetesって何から触ればいいの?」という不安が、具体的な Deployment/Service/Ingress/HPA の雛形で解消されます。
- ローカルクラスタ(Minikube等)での練習を通じて、本番クラスタへのデプロイイメージが掴みやすくなります。
-
小規模チームさん
- Docker Compose から Kubernetes への移行を考える際の「最小構成のチェックリスト」が手に入ります。
- ローリングアップデートと HPA を組み合わせて、サービス停止時間を減らしつつ、負荷の波に強い運用が目指せます。
-
スタートアップのSaaS開発チームさん
- ConfigMap/Secret/HPA などを組み合わせることで、環境ごとに設定を変えつつ、安全にスケールできるアーキテクチャの基礎が固まります。
- 将来的なマイクロサービス化に向けて、サービスごとに Deployment/Service/Ingress を切るイメージが持てます。
13. 参考リンク(公式ドキュメント中心)
-
Kubernetes
-
FastAPI
-
ローカルK8s
14. まとめ:FastAPIをKubernetesの「一市民」にする
ここまで、FastAPI アプリを Kubernetes にデプロイするための基本的なリソースと設定を、ひと通り見てきました。
- Deployment で Pod の数とテンプレート を管理し、liveness/readiness プローブでヘルスチェック。
- Service で 安定した入口 を用意し、必要なら Ingress で外部 HTTP と結びつける。
- ConfigMap/Secret で 設定と秘密を外出し し、環境変数として FastAPI からシンプルに参照。
- HPA を使って、CPU 使用率に応じて 自動的に Pod をスケール させる。
- ローリングアップデート/ロールバックで、安全にバージョンアップとトラブルシュートを行う。
最初は YAML の量に圧倒されてしまうかもしれませんが、1つ1つの役割を理解すると「そんなに怖くないかも…」と感じてもらえるはずです。
この雛形をベースに、少しずつ自分たちのプロジェクトに合った形へ育てていってくださいね。
わたしも、あなたの FastAPI アプリが Kubernetes 上で元気に動く姿を想像しながら、そっと応援しています。
