Vector移行と3ホスト基盤の設定整理
ログ収集をVectorへ移し、devstackをホスト別に分割。AIシステム開発に使うローカルインフラの配置とGo設定を整理しました。
変更後のホスト配置
3台のホームラボ(storage / desktop / compute)で、ログ収集を Vector に移し、devstack の compose をホスト別に分けました。Go の設定値も1か所にまとめました。変更後の配置は次のとおりです。
desktop.home.arpa compute.home.arpa storage.home.arpa
───────────────── ───────────────── ─────────────────
agent-gateway :8080 vLLM :8000 Vector
NATS :4222 llama.cpp :8001 Loki :3100
reranker :8081 PostgreSQL :5432 Prometheus :9090
LM Studio :1234 Dagster :3300 MinIO :9000
MLflow :5050
desktop はリクエストの振り分け、compute は推論・データ処理・実験管理、storage はログ・メトリクス・オブジェクトの保存を担当します。compose もこの役割分担に合わせました。
背景
agent-gateway を3台で運用しています。storage.home.arpa は 24/7 稼働し、Prometheus、Loki、MinIO、各種 exporter を置いています。macOS の desktop.home.arpa は agent-gateway と NATS JetStream を担当します。compute.home.arpa は必要なときに起動し、GPU 推論(vLLM、llama.cpp)と PostgreSQL、Dagster、MLflow を動かします。
用途は日経225のリアルタイム予測です。イベントの安定した並列実行と、メモリセーフな transform 処理が必要で、Vector の処理層が合いました。クラウドの遅延、情報漏洩、リソース変動を懸念し、マシンを管理できるローカル構成にしています。全コンポーネントはコンテナ化しているため、機材があれば構成を再現できます。AIシステム開発で使う推論とデータ処理の基盤として、次の問題を整理しました。
- Promtail の出力先:Loki 専用で、NATS への publish や Prometheus metrics の生成には対応できません。
- 単一の compose:1つの podman-compose.yml に全サービスがあり、本番のホスト配置と異なっていました。
.envrcとデフォルト値のずれ:固定のホスト名やポートを二重に管理し、設定が食い違っていました。
フェーズ1: Promtail → Vector 移行
移行の動機
Vector は、同じ入力を Loki、NATS、Prometheus metrics など複数の出力へ流せます。将来、インフラログを NATS 経由で Dagster のデータパイプライン に取り込む案もあり、Promtail から移行しました。
本番 Vector の構成
storage.home.arpa では、rootful の systemd quadlet で Vector が稼働していました。メモリ使用量は 19.3M、ピークは 25.7M でした。Prometheus の scrape 対象にも追加済みです。
config の入力は5つです。
- journald——
current_boot_onlyで現在のブートセッションのみ収集 - file_security——alternatives.log, apport.log
- file_apt——apt/dpkg のログ
- syslog_udp——UDP:1514、MikroTik ルーター等からの syslog 受信
- internal_metrics——Vector 自身のメトリクス
journald は route で kernel と systemd に分け、job / host ラベルを付けます。kernel は ._TRANSPORT == "kernel" で判定し、systemd は _SYSTEMD_UNIT と __UID__ も抽出します。syslog は appname / severity / facility をラベルにします。
全 transform 出力を JSON で Loki へ送り、internal_metrics は Prometheus exporter(:9598)で公開します。外部公開ポートは scrape 用の 9598 と NATS 接続用の 4222 に絞りました。
devstack Vector の廃止
devstack にも Vector が1つありました。NATS JetStream の telemetry.> を購読し、JSON を解析してドメイン別に分けていました。storage がログ、devstack がテレメトリを扱う構成です。
連携方法は3案を検討しました。
- A案: storage → NATS publish で
telemetry.infra.*を desktop に流す - B案: devstack → Loki sink で NATS テレメトリも Loki に集約する
- C案: 両方向に流して Loki にも NATS にも全データが揃う状態にする
初めは C案で進めましたが、開発用の devstack に集約機能を持たせず、本番側へ任せる方針に変えました。devstack の Vector を削除し、storage は journald + file + syslog → Loki + Prometheus exporter に戻しました。
NATS への publish は agent-gateway の Go コードが担当します。リクエスト処理中に goroutine が telemetry.* と pipeline.* へ送り、JetStream に保存します。Vector はログ収集に絞り、イベントとの関連は CorrelationID で追うことにしました。
フェーズ2: devstack のホスト単位分割
分割の動機
ルートの podman-compose.yml には、NATS、PostgreSQL、Dagster(3コンテナ)、MLflow、Reranker、minio-init など計8サービスがありました。本番では3台に分かれるため、開発時と接続先が異なる問題が出ていました。
分割結果
本番の配置に合わせて、compose を2つに分けました。
- devstack/desktop/ — NATS + nats-init + Reranker
- devstack/compute/ — PostgreSQL + Dagster (x3) + MLflow + minio-init (for development)
desktop の NATS は JetStream とヘルスチェックを有効にします。nats-init が PIPELINE / TELEMETRY ストリームを作成し、Reranker もここで動かします。
compute の dagster-user-code と dagster-daemon は、NATS_URL: nats://desktop.home.arpa:4222 で NATS に接続します。以前の compose 内参照 nats://nats:4222 をホスト名へ変えました。compose 間の依存は制御できないため、起動順序は運用で管理します。
Dagster / MLflow の配置判断
Dagster UI だけ desktop に置く案も検討しました。webserver と user-code / daemon は分離でき、workspace.yaml でリモートの gRPC エンドポイントを指定できます。
今回使う mlflow server は UI と tracking server をまとめて動かします。Dagster のアセットから MLflow の実験リンクを開くため、両方を compute に置きました。desktop のブラウザから http://compute.home.arpa:3300(Dagster UI)と :5050(MLflow UI)を開きます。
minio-init の扱い
minio-init は一度削除しましたが、復元しました。storage.home.arpa の MinIO に agw-mlflow / agw-iceberg バケットが未作成だったためです。初期化ジョブで作成し、MLflow の depends_on に service_completed_successfully を指定しました。
フェーズ3: .envrc 廃止と defaults.go への一本化
動機
設定は direnv の .envrc にありました。COMPUTE_HOST、STORAGE_HOST、VLLM_BASE_URL、NATS_URL、POSTGRES_DSN など約25行を、go run 時にシェルから渡していました。
この開発環境では、ホスト名、ポート、開発用シークレットが固定です。.envrc が古くなると config.go のデフォルト値と食い違うため、通常の値を Go 側へまとめました。
設計
internal/config/defaults.go の const に3台のホスト名、ポート、DB 接続情報、ログ設定を集約しました。config.go の Load() は envOr / boolEnvOr / intEnvOr / optionalBoolEnv の4つを使い、1つの return 文で AppConfig を作ります。
サービスの接続先は3台のホスト名から組み立てます。
COMPUTE_HOST → vLLM, llama.cpp, PostgreSQL, Dagster, MLflow
STORAGE_HOST → Loki, MinIO, Prometheus
DESKTOP_HOST → NATS, Reranker, LM Studio
通常は個別の URL を指定する必要がありません。環境変数での上書きは残してあり、開発中は VLLM_BASE_URL=http://localhost:8000 go run ./cmd/server のように変更できます。
実装中にポートを2回取り違えました。llama.cpp を 8081、Reranker を 8001 にしていましたが、正しくは compute の llama.cpp:8001、desktop の Reranker:8081 です。DagsterBaseURL も desktop から compute に直しました。defaults.go のコメントに所属ホストを記載しています。
イベントフローの全体像
データは2つの経路で流れます。
- Path A: agent-gateway の goroutine → NATS publish → Dagster sensor。リクエストのリネージ追跡やデータ合成に使う非リアルタイム経路
- Path B: storage の Vector → Loki。インフラログのリアルタイム集約経路
Path A は agent-gateway 側で完結するため、Vector から NATS への転送は不要です。両経路の記録は CorrelationID で関連付けます。
開発時も本番に近い接続構成になりました。compute の Dagster は NATS_URL に nats://desktop.home.arpa:4222 を使います。すべて localhost で動かす場合は、環境変数で上書きします。
