🗂

GKEでFastAPIサーバを公開してみた

に公開

今回はkubernetesの練習を兼ねて、FastAPIサーバをGKE上にデプロイしてみました。

GKEへのFastAPIサーバのデプロイ

システム構成

今回はレプリカ数を1としてFastAPIサーバをGKE上で構築します。ロードバランサーサービスを利用して外部公開しました。

Google Cloudの設定

ここではプロジェクトは作成済みであるとします。

まず、Dockerイメージを保管するためのArtifact Registryを作成します。

gcloud artifacts repositories create fastapi-repo --repository-format=docker --location=asia-northeast1
gcloud auth configure-docker asia-northeast1-docker.pkg.dev

Pythonコードの実装

まずはプロジェクトをuvを利用して初期化します。

uv init fastapi_k8s -p 3.12 && cd fastapi_k8s
uv add fastapi uvicorn
touch main.py

次にFastAPIサーバを実装します。今回実装するコードはGETメソッドでhelloと返すだけのAPIを実装します。

main.py
from fastapi import FastAPI


app = FastAPI()


@app.get("/hello")
def hello():
    return {"message": "hello"}

Artifact RegistryへのDockerイメージのpush

まず先ほど実装したFastAPIサーバをデプロイするためのDockerfileを用意します。uvをホストするためのイメージが提供されているので利用します。

FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim

WORKDIR /app
COPY . /app

EXPOSE 80
RUN uv sync

CMD ["uv", "run", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

次に、イメージをビルドしてpushします。なお、私はmacbookを使っているので--platform linux/amd64を指定してGKE上で実行できるようにします。

docker build -t fastapi-gke . --platform linux/amd64
docker tag fastapi-gke asia-northeast1-docker.pkg.dev/<PROJECT_ID>/fastapi-repo/fastapi-gke:latest
docker push fastapi-gke asia-northeast1-docker.pkg.dev/<PROJECT_ID>/fastapi-repo/fastapi-gke:latest

Kubernetes設定ファイルの作成

まずはDeploymentの設定を作成します。今回はReplicaSetは1つだけ作成するものとします。また、dockerイメージのタグは毎回latestを指定したいので、imagePullPolicy: Alwaysにしています。そして、FastAPIサーバはポート80を使っているのでポートの指定もしています。

deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: fastapi-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: fastapi
  template:
    metadata:
      labels:
        app: fastapi
    spec:
      containers:
      - name: fastapi
        image: asia-northeast1-docker.pkg.dev/<PROJECT-ID>/fastapi-repo/fastapi-gke:latest
        imagePullPolicy: Always
        ports:
        - containerPort: 80

次に外部公開するためにロードバランサーを実装します。fastapiというラベルをつけたサーバを対象にポート80番でロードバランサーとして利用します。

apiVersion: v1
kind: Service
metadata:
  name: fastapi-service
spec:
  type: LoadBalancer
  selector:
    app: fastapi
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

GKEへのデプロイ

まずはクラスタを作成します。今回はArtifact Registryなどはasia-northeast1に作成しましたが、GKEクラスタはうまく作成できずus-central1にて構成しました。実際の運用では同じリージョンでするのがベストですね。今回はノードは2つとし、マシンタイプはn1-standard-4を利用しました。

gcloud container clusters create fastapi-cluster --zone us-central1-a --num-nodes 2 --machine-type n1-standard-4

次に、先ほど用意したKubernetes設定を反映します。

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml

デプロイできたかを確認するために、まずはPodを確認します。ちゃんとfastapi-deployment-<hash>のようにPodが一つ作成されていることが確認できました。

kubectl get pods --output wide

NAME                                  READY   STATUS    RESTARTS      AGE   IP          NODE                                             NOMINATED NODE   READINESS GATES
fastapi-deployment-64cb8c5957-jbz2m   1/1     Running   5 (18m ago)   20m   10.80.0.7   gke-fastapi-cluster-default-pool-3e21fba6-rx8c   <none>           <none>

次にロードバランサーの情報を見てみましょう。以下のように、外部IPアドレスが払い出されました(一応隠しています)。

kubectl get service fastapi-service

NAME              TYPE           CLUSTER-IP      EXTERNAL-IP    PORT(S)        AGE
fastapi-service   LoadBalancer   <CLUSTER_IP>    <EXTERNAL-IP>  80:30727/TCP   40m

アプリケーションへのアクセス

先ほど確認したロードバランサーの外部IPアドレスを利用してアクセスしてみます。ブラウザで<EXTERNAL-IP>/helloと入力すると、以下のように指定したメッセージが帰ってくることを確認できました。また、<EXTERNAL-IP>/docsでSwagger UIも表示できることを確認しました。

まとめ

今回は、Kubernetes上でFastAPIサーバをデプロイしてみました。レプリカ数も1にしていますしサーバ構成も最低限のものでありDBなどがないためシンプルでした。今後はもっと複雑なシステムを作ってみたいと思います。

Discussion