「結城のあ」のバックエンドは、いくつかの部品(会話API・記憶用のデータベース・夜間バッチなど)が常時動き続ける必要があります。最初は1台のミニPCで全部動かしていましたが、管理を楽にしたかったので Kubernetes を導入しました。とはいえ本格的なクラスタは個人にはオーバースペックなので、軽量版の k3s を選んでいます。
なぜ k3s なのか
k3s は Rancher が作っている、1つのバイナリで動く軽量Kubernetesです。本家のKubernetesと比べてメモリ消費が小さく、非力なミニPCやRaspberryPiでも動きます。個人で自宅に置くなら、これで十分すぎるくらいです。
- インストールがスクリプト1本で終わる
- etcd の代わりに軽量DB(SQLite)を使えるので、シングルノードが軽い
- 必要になったらノードを後から追加できる
「コンテナを再起動し続けてくれる」「設定をYAMLで宣言的に書ける」というKubernetesの旨味は、個人運用でも効きます。深夜にプロセスが落ちても勝手に立ち上がってくれるのは安心です。
シングルノードからマルチノードへ
最初はミニPC1台がコントロールプレーン兼ワーカーという構成でした。ここに会話APIやデータベースを載せていたのですが、推論(LLM)の負荷が重く、他の処理を圧迫することがありました。
そこで、推論専用のマシンを エージェントノード(ワーカー)としてクラスタに追加しました。ノード名は ai-studio01 です。k3s ではエージェントノードの追加も、サーバーのトークンを渡して1コマンドで済みます。これで「推論はこのノード、それ以外は別のノード」と役割を分けられるようになりました。
Podをどのノードに置くかは nodeSelector や taint/toleration で制御します。GPUを使う推論系のPodだけを ai-studio01 に寄せ、それ以外を分散させる、といった割り当てができます。
悩みどころ: Ollama をどこで動かすか
一番悩んだのが、推論エンジンの Ollama を「Podの中で動かすか、Podの外(ホスト)で動かすか」でした。結論として、Ollama はホスト側の systemd サービスとして動かし、会話APIのPodからそこへ接続する形にしています。
理由は GPU です。Ollama は Radeon 780M の iGPU を Vulkan 経由で使いますが、iGPUをコンテナの中から素直に扱うのは設定が複雑になりがちです。ホストのsystemdサービスとして動かせば、ドライバまわりの面倒を避けつつ、モデルを常駐させたままにできます。
keep_alive でモデルを常駐させる
Ollama はデフォルトだと、しばらく使わないモデルをメモリから解放します。配信中に次の発話のたびモデルを再ロードしていては数秒の間が空いてしまうので、keep_alive を -1 に設定して、モデルをずっとメモリに載せたままにしています。常駐させるぶんメモリは食いますが、応答のテンポを優先しました。
hostNetwork Pod でホストのOllamaに直結する
では、Podの中で動く会話API(FastAPI)から、ホストのOllamaへどう繋ぐか。ここで使っているのが hostNetwork: true の設定です。
通常、Pod は独自のネットワーク空間を持つので、ホスト側のサービスに繋ぐには工夫が要ります。hostNetwork: true を付けると、その Pod はホストと同じネットワークを共有するので、localhost:11434(Ollama の待ち受けポート)にそのままアクセスできます。会話APIのPodだけにこの設定を入れて、ホストのOllamaへ直結させています。
- 会話API Pod: hostNetwork で ai-studio01 上に配置し、ホストのOllamaへ
localhost:11434で接続 - Ollama: ai-studio01 のホストsystemdサービス(Pod外)
- DBやバッチ: 通常のPodとしてクラスタに配置
夜間バッチも k3s に載せる
「結城のあ」には、毎晩その日の会話を振り返って記憶を整理するバッチがあります(詳しくは RAGの記事)。こうした定期処理も k3s の仕組み(CronJob 相当のスケジュール実行)に載せておけば、PCが起動していれば自動で走ってくれます。バッチ専用のサーバーを別に用意しなくて済むのが、クラスタにまとめておく利点です。
まとめ
自宅の小さなクラスタでも、「役割でノードを分ける」「GPUを使う推論はホスト側に逃がす」「Podからは hostNetwork で直結する」という割り切りで、AITuberの基盤は十分に組めます。最初から完璧を目指さず、1台から始めて必要になったらノードを足す、というやり方が個人運営には合っていると感じています。
続けて読む: ローカルLLMの全体構成 / pgvectorで長期記憶を持たせる / VTube Studioの表情API