ローカルLLMと画像生成環境をMac上に構築しても、手動で操作するだけでは自動化できません。

今回の目的は、ConoHa VPS側で記事や画像の生成ジョブを登録し、自宅にあるMacBook ProまたはMac miniがその仕事を取得して処理することです。

ただし、VPSから自宅Macへ直接接続する構成にはしません。

自宅Mac側からVPSへ問い合わせる方式を採用します。

なぜVPSから直接接続しないのか

VPSから自宅Macへ直接アクセスするには、自宅側のネットワークへ外部から到達できるようにする必要があります。

その場合、次のような課題があります。

  • 自宅ルーターのポート開放
  • 動的IPアドレスへの対応
  • NAT環境への対応
  • Mac側APIの外部公開
  • 認証とアクセス制限
  • 不正アクセスへの対策
  • 回線やルーター変更時の再設定

VPNやトンネルサービスを使う方法もありますが、今回は構成を単純にするため、自宅側を公開しません。

自宅MacからConoHa VPSへHTTPSでアクセスするだけなら、一般的なWebアクセスと同じ方向の通信になります。

ジョブを取りに行く方式

処理の流れは次のとおりです。

  1. 管理画面や自動処理がVPSへ生成ジョブを登録する
  2. Mac上のワーカーがVPSへジョブの有無を問い合わせる
  3. 未処理ジョブがあれば取得する
  4. ローカルLLMまたはComfyUIで生成する
  5. 結果をVPSへ返す
  6. VPSがジョブを完了状態にする

この方式では、VPSは自宅MacのIPアドレスや接続先を知る必要がありません。

Mac側が自分から通信できれば動作します。

通常ポーリングとロングポーリング

Macがジョブを確認する方法として、通常ポーリングとロングポーリングがあります。

通常ポーリング

一定時間ごとに短いリクエストを送ります。

例えば30秒間隔なら、次の動作になります。

  1. Macがジョブの有無を問い合わせる
  2. ジョブがなければ空の応答を受け取る
  3. 30秒待つ
  4. 再び問い合わせる

1台あたり1日2,880回のリクエストになりますが、小さなJSONを返すだけなら、個人利用のVPSでは大きな負荷にはなりにくい回数です。

ロングポーリング

今回採用するのはロングポーリングです。

Macがジョブ取得APIへアクセスすると、VPSはジョブが登録されるまで一定時間リクエストを保持します。

例えば最大30秒待機する場合は次のようになります。

  1. Macがジョブ取得APIへ接続する
  2. すでにジョブがあればすぐ返す
  3. ジョブがなければ最大30秒待つ
  4. 待機中にジョブが登録されたら即座に返す
  5. 30秒経過してもジョブがなければ空の応答を返す
  6. Macはすぐに次の接続を開始する

これにより、ジョブが登録されてから処理開始までの待ち時間を短くできます。

WebSocketほど接続管理が複雑ではなく、通信が切れても再接続しやすい点も利点です。

VPS側の構成

初期構成では、VPS側に次の要素を用意します。

  • FastAPI
  • PostgreSQL
  • ジョブ登録API
  • ジョブ取得API
  • ハートビートAPI
  • 結果送信API
  • 管理用ログ

ジョブの内容はPostgreSQLへ保存します。

初期段階では、専用のメッセージキュー製品を追加せず、PostgreSQLで管理します。

ワーカー数がMacBook ProとMac miniの2台であり、個人運用の規模であれば、まずは十分対応できると考えています。

ジョブに保存する情報

ジョブには、少なくとも次の情報を持たせます。

  • ジョブID
  • ジョブ種別
  • 入力内容
  • 状態
  • 優先度
  • 作成日時
  • 処理開始日時
  • 完了日時
  • 担当ワーカー
  • 最終ハートビート時刻
  • 再試行回数
  • エラー内容
  • 生成結果の保存先

ジョブ種別には、例えば次の値を使用します。

  • article_generate
  • article_rewrite
  • article_summary
  • image_generate
  • image_upscale

記事と画像で必要な入力形式が異なるため、ジョブ種別ごとに入力内容を検証します。

Mac側のワーカー

Mac上では、Python製のワーカーを常駐させます。

ワーカーの役割は次のとおりです。

  1. VPSへロングポーリングする
  2. ジョブを取得する
  3. ジョブ種別を確認する
  4. OllamaまたはComfyUIを呼び出す
  5. 処理中にハートビートを送る
  6. 結果をVPSへ送信する
  7. 次のジョブを待つ

OllamaやComfyUIを外部へ公開する必要はありません。

Pythonワーカーが同じMac内のローカルAPIへ接続します。

認証

MacからVPSへ接続する際には、ワーカーごとに異なる認証情報を使用します。

例えば、MacBook ProとMac miniへそれぞれ次の識別情報を割り当てます。

  • worker-mbp
  • worker-macmini

さらに、それぞれ別のAPIキーを発行します。

APIキーはソースコードに直接書かず、環境変数やmacOSのキーチェーンなどで管理します。

VPS側では、次の内容を記録します。

  • どのワーカーが接続したか
  • どのジョブを取得したか
  • 処理にどれくらい時間がかかったか
  • エラーが発生したか
  • 不自然な回数のアクセスがないか

生成結果の返し方

記事生成結果はJSONとしてVPSへ返せます。

画像はファイルサイズが大きくなるため、次のいずれかの方法を使用します。

  • 結果送信APIへ直接アップロード
  • VPS側で一時アップロードURLを発行
  • オブジェクトストレージへアップロード
  • PayloadのメディアAPIへVPS経由で登録

初期構成では、MacからVPSへ画像を送り、VPS側でPayloadへ登録します。

これにより、Payloadの認証情報を自宅Macへ置かずに済みます。

まとめ

VPSから自宅Macへ直接接続せず、Mac側がジョブを取りに行く構成にすることで、自宅回線を外部へ公開せずに生成処理を自動化できます。

通信方式には30秒待機のHTTPSロングポーリングを使用します。

次回は、MacBook ProとMac miniが同時に接続した場合の二重処理や、Macが途中で停止した場合の復旧方法を設計します。