データサイエンティストのためのKubernetes - 予測のホスティング

Built for Speed: ~10ms Latency, Even Under Load
Blazingly fast way to build, track and deploy your models!
- Handles 350+ RPS on just 1 vCPU — no tuning needed
- Production-ready with full enterprise support
前回号では、データサイエンティストのワークフローと、Kubernetes がそのためのプラットフォームを構築する上でいかに有用な基盤となり得るかについて説明しました。
今回号では、実践的な経験を積むために、簡単な例を通して説明します。
前提条件
- Docker - https://docs.docker.com/get-docker/ - クラスターノードをコンテナとして起動するため
- kubectl - https://kubernetes.io/docs/tasks/tools/#kubectl - 実行中の Kubernetes クラスターと対話するための CLI ツール。
環境のセットアップ
開始する前に、デモを実行するための環境が必要です。そのために、ローカルマシンに Kubernetes クラスターをセットアップします。クラスターはフォールトトレランスと高可用性のために複数のノードを含むべきですが、私たちは優れたツールを使ってその動作を模倣します。 kind (kubernetes-in-docker)。
このセクションの終わりには、各コンテナが個別のクラスターノードとして機能する形で、複数のコンテナが実行されている状態になります。
インストール
提供されている指示に従って こちら
インストールをテストするには、以下を実行します。
$ kind --version
kind version 0.14.0
クラスターを起動しています
では、これよりローカルクラスターを起動します。 kindを使用します。コントロールプレーンを1つ、ワーカーノードを2つ作成します。どちらも複数構成にすることが可能です。
<aside> 💡 Kubernetesは複数のコントロールプレーンとワーカーノードを持つことができます。集中管理されるクラスター管理コンポーネントはすべてコントロールプレーンノード上に存在し、ユーザーのワークロードはワーカーノード上で実行されます。詳細はこちらをご覧ください。 こちら
</aside>
まず、 kind の設定を、 kind-config.yamlという名前のファイルに作成します。ファイルは こちらにあります。これにより、クラスターの構造が定義されます。
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
ここでは、3つのノードを定義し、そのうち1つをコントロールプレーン、残りの2つをワーカーノードとしています。
この設定を使ってクラスターを起動します。これには時間がかかる場合があります。実行する前に、システムでDockerデーモンが起動していることを確認してください。
$ kind create cluster --config kind-config.yaml
...
kindをご利用いただきありがとうございます!😊
クラスターが起動していることを確認するために、 kubectl を実行してみましょう。
$ kubectl cluster-info
Kubernetes control plane is running at <https://127.0.0.1:63122>
CoreDNS is running at <https://127.0.0.1:63122/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy>
...
これにより、クラスターが実際に起動していることがわかります。また、 docker psを実行することで、ノードとして機能している個々のコンテナを確認することもできます。
アーキテクチャ

クラスターが起動したところで、これからプロビジョニングするものの全体的なアーキテクチャを見ていきましょう。
大まかに言えば、クラスター内にアプリケーションの複数のレプリカを配置し、外部からアクセスできるようにします。その際、リクエストは各インスタンス間でロードバランスされます。
これを実現するために、いくつかKubernetes固有の用語を知っておく必要があります。
PodPodは、Kubernetesで作成および管理できる最小のデプロイ可能なコンピューティング単位です。今回の場合、アプリケーションの1つのインスタンスが1つの独立したPod内で実行されます。これらは一時的なリソースであり、必要に応じてコントロールプレーンがノード間で移動させることができます。Deploymentデプロイメントは、アプリケーションに対して複数のレプリカを持ちたい場合に役立ちます。Kubernetesは、デプロイメントで指定されたレプリカの数を常に維持しようとします。私たちのアプリケーションには、3つの同一のレプリカを作成します。Serviceサービスは、クラスター上で実行されているPodのセット間でロードバランスを行うのに役立ちます。Podは本質的に一時的であり、いつでも置き換えられる可能性があるため、サービスは背後で実行されているPodにアクセスするための安定したインターフェースを提供します。私たちのアプリケーションをテストするためにサービスを使用します。
これら3つのリソースにより、アプリケーションを提供するためのスケーラブルなエンドポイントをホストできるようになります。
イメージの準備
クラスターが起動したら、アプリケーションをデプロイしてテストできます。人気のIris分類器データセットを使用してアプリケーションを作成します。
リポジトリをクローンする
リポジトリはこちらで入手できます: https://github.com/shubham-rai-tf/iris-classifier-kubernetes。これには、予測を構築し、提供するためのコードがすでに含まれています。 /iris/classify_iris エンドポイントで、 fastapi。
Dockerイメージの構築
このコードをDockerイメージにパッケージ化し、その準備をする必要があります。 Kubernetes。 Dockerfile がリポジトリに用意されています。 こちら。
この Dockerfile は、予測エンドポイントをホストするコンテナを、 Uvicorn サーバー(ポート5000)で作成するために必要なイメージを指定しています。構文の詳細については、以下で確認できます。 こちら。
ローカルイメージをビルドするには、このコマンドを実行します。
$ docker build . -t iris-classifier:poc
...
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
iris-classifier poc 549913d5b1f9 12 seconds ago 737MB
イメージが正常に作成され、名前 iris-classifier およびタグ pocが付けられたことがわかります。このイメージをクラスターにロードし、クラスター内で使用します。
イメージのロード
<aside> 💡 このステップは、新しくビルドされたイメージをプルするためのイメージレジストリがない場合にのみ必要です。本番環境では、イメージはDockerhubやAWS ECRのようなプライベートレジストリでホストされ、そこから直接クラスターにプルされるべきです。
</aside>
ローカルでビルドされたイメージをクラスターにロードするには、このコマンドを実行します -
$ kind load docker-image iris-classifier:poc
イメージ: "iris-classifier:poc" (ID "sha256:549913d5b1f9456a4beedc73e04c3c0ad70da8691a8745a6b56a4f483c4f0862") はノード "kind-worker2" にまだ存在しません。ロード中...
イメージ: "iris-classifier:poc" (ID "sha256:549913d5b1f9456a4beedc73e04c3c0ad70da8691a8745a6b56a4f483c4f0862") はノード "kind-control-plane" にまだ存在しません。ロード中...
...
イメージがロードされたことを確認するには、3つのコンテナのいずれかでイメージをリスト表示します -
$ docker exec -it kind-worker crictl images
IMAGE TAG IMAGE ID SIZE
docker.io/library/iris-classifier poc 549913d5b1f94 753MB
Kubernetesへのデプロイ
Kubernetesは本質的に宣言型システムです。つまり、私たちは行いたいことの概要を記述し、コントロールプレーンコンポーネントは、その状態に到達するようにシステムを常に駆動します。
先に説明したアーキテクチャを実装するために、私たちは意図を〜の形式で記述します YAML ファイルで、意図を記録する役割を果たします。Kubernetesの用語では、これらは マニフェストと呼ばれます。
すべてのKubernetesマニフェストには、以下のフィールドがあります。
apiVersion- 複数のリソースが同じAPIバージョンにまとめられています。これにより、Kubernetesのバージョン間でリソースを非推奨にしたり、昇格させたりする標準的な方法が提供されます。kind- 作成される正確なオブジェクトタイプを識別します。metadata- 作成されるオブジェクトのメタデータとして機能するフィールドが含まれています。apiVersion、kindおよびmetadata.nameフィールドは合わせて、namespacespec- このフィールドには、作成されるオブジェクトの仕様が含まれています。各kindは、独自の構造と実装でこのフィールドを定義します。
リポジトリ内のマニフェストを、以下のディレクトリ内のファイルで使用します。 manifests ディレクトリ こちら。
これにより、2つのKubernetesリソースが定義されます。 Deployment と Service に deployment.yaml と service.yaml それぞれ定義されています。両方のセクションを見ていきましょう。
Deployment
apiVersion: apps/v1
kind: Deployment
spec:
# レプリカ数
replicas: 3
template:
spec:
containers:
# イメージ名
- image: iris-classifier:poc
name: iris-classifier
デプロイメントマニフェストは deployment.yaml 主に、デプロイしたいポッドの仕様(イメージ名とレプリカ数)を定義します。これを適用すると、Kubernetesはここで指定したレプリカ数を常に維持するように動作します。
Service
apiVersion: v1
kind: Service
spec:
# サービスの種類
type: ClusterIP
ports:
# サービスがアクセス可能になるポート
- port: 8080
# トラフィックが転送されるコンテナ上のポート
targetPort: 5000
プロトコル: TCP
セレクタ:
アプリ: iris-classifier
サービスマニフェスト service.yaml は、デプロイメントによって作成されたレプリカ間でどのようにロードバランシングを行うかを定義します。ここでは、サービス上のポートをコンテナ上のポートにどのようにマッピングするかを定義しています。アプリケーションはポート5000で実行されるため、 ターゲットポート は5000に設定されています。サービスはポート8080で公開されます。8080に送信されたTCPトラフィックは、コンテナ上のポート5000にロードバランシングされます。
マニフェストの適用
以下のコマンドを実行して、マニフェストをKubernetesに適用します。
$ kubectl apply -f manifests/
deployment.apps/iris-classifier created
service/iris-classifier created
両方のリソースがクラスター上に正常に作成されました。以下のコマンドを実行して確認できます。
$ kubectl get service iris-classifier
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
iris-classifier ClusterIP 10.96.107.238 <none> 8080/TCP 37m
$ kubectl get deployment iris-classifier
NAME READY UP-TO-DATE AVAILABLE AGE
iris-classifier 3/3 3 3 38m
$ kubectl get pods
名前 準備完了 ステータス 再起動 経過時間
iris-classifier-5d97498ff9-77wqw 1/1 稼働中 0 39m
iris-classifier-5d97498ff9-8twjm 1/1 稼働中 0 39m
iris-classifier-5d97498ff9-znrz8 1/1 稼働中 0 39m
ご覧の通り、サービスはポート8080で公開され、指定した通り3つのPodが作成されました。
変更 deployment.yaml を、レプリカ数を3から2に変更して再適用してください。Kubernetesは、仕様に合わせてレプリカの1つを削除します。
予測の実行
クラスターにリソースが作成されたので、サービスエンドポイントを使用してモデルを呼び出すことで、デプロイメントを確認できます。ローカル環境を使用しているため、 ポートフォワード する必要があります。
<aside> 💡 クラウドプロバイダーの環境では、このサービスは外部ロードバランサーにバインドされ、必要に応じてインターネットからアクセスできます。
</aside>
サービスのポートフォワーディングを実行するには、次のコマンドを実行します。
$ kubectl port-forward services/iris-classifier 8080
127.0.0.1:8080 から 5000 へフォワーディング中
[::1]:8080 から 5000 へフォワーディング中
を呼び出すことで確認できます。 /healthcheck モデル上のエンドポイント -
$ curl '<http://localhost:8080/healthcheck>'
「Iris分類器は準備完了です!」
テスト予測を実行するために、サンプル入力を送信して予測を取得します。
$ curl '<http://localhost:8080/iris/classify_iris>' -X POST \\
-H 'Content-Type: application/json' \\
-d '{"sepal_length": 2, "sepal_width": 4, "petal_length": 2, "petal_width": 4}'
{"class":"setosa","probability":0.99}
クラス setosa の予測が99%の確率で得られます。これらの予測を複数回実行することで、リクエストが実際にラウンドロビン方式で異なるポッドにルーティングされていることを確認できます。
クリーンアップ
まず、インストールしたすべてのKubernetesリソースを削除しましょう。
$ kubectl delete -f manifests/
これにより、以前のセクションで作成したすべてのKubernetesリソースがクリーンアップされます。次に、クラスターも停止できます。
$ kind delete cluster
クラスター "kind" を削除中...
まとめ
この号では、Kubernetesでモデルを呼び出し可能なサービスとしてホストする方法について説明しました。これは、Dockerイメージをローカルで構築し、同じマシン上で実行されているクラスターで実行するおもちゃのような例でしたが、一般的な本番環境のセットアップも同様の原則で動作します。これら2つのリソースだけでも多くのことが達成できます。
今後の記事では、Day 2オペレーションに移行するにつれて不可欠となる、マルチテナンシーやアクセス制御といった、さらに高度な機能について掘り下げていきます。
TrueFoundry AI Gateway delivers ~3–4 ms latency, handles 350+ RPS on 1 vCPU, scales horizontally with ease, and is production-ready, while LiteLLM suffers from high latency, struggles beyond moderate RPS, lacks built-in scaling, and is best for light or prototype workloads.

















.webp)
.webp)



.png)

.png)














