構築した基盤

3台のマシンを RouterOS 配下の10GbEでつなぎ、LLM 推論、データ処理、開発、監視の基盤を構築しました。CPU の割り当て、SATA / NVMe の用途、3層のディレクトリ配置、UID/GID を先に決めています。LLM導入のインフラ構築で、各サービスの配置と資源を管理するための設計です。

この基盤で Go + NATS + Dagster によるAIオーケストレーション基盤の devstack(podman-compose)が稼働しています。


ハードウェア構成

Compute Server (Ubuntu 24.04.3 LTS)

  CPU: AMD EPYC 9175F (第5世代 Turin) 16core 4.2GHz-5GHz L3 cache 512MB
GPU: Nvidia RTX PRO 6000 MAX-Q (300W) 96GB (Blackwell世代)
RAM: DDR5-6400 64GB x 12 (768GB)
MB: Supermicro H13SSL-NT
Storage1: SATA 6Gbps 3.84TB
Storage2: M.2 PCIe4.0 3.84TB
PSU: 1500W (80Plus)
NIC: 10GbE x 2 (en0: 10.10.10.4, en1: disabled)
  

Desktop PC (macOS latest)

  Mac Studio M1 Ultra
CPU: M1 Ultra
RAM: 64GB
Storage: 1TB
NIC: 10GbE x 1 (10.10.10.2)
Wi-Fi: disabled
  

Storage Server (Ubuntu 24.04.3 LTS)

  Mac mini late 2018
CPU: Core i3
RAM: DDR4 SO-DIMM 8GB
Storage: SSD 2TB, ext M.2 SSD 4TB, SATA HDD 24TB
NIC: 1GbE, ext 10GbE (RTL8159, 10.10.10.3)
Wi-Fi: disabled
  

ネットワーク

全ホストを RouterOS (CRS304) 配下の10GbEで接続しています。

  VDSL -> Router (RouterOS)
          Wi-Fi 7 -> mobile SSID, IoT SSID
          DHCP Server
             | -> CRS304 (Router+Switch)
                    |-- Port1 → Desktop PC     10.10.10.2
                    |-- Port2 → Storage Server 10.10.10.3
                    |-- Port3 → Compute Server 10.10.10.4
                    |-- Port4 → Wi-Fi 6 AP     128.0.0.1 (DHCP Server)
                    |-- Port5 → WAN            192.168.0.2/24 (1GbE DHCP Client)
  
ホスト役割稼働
Compute ServerGPU推論 + データ基盤 + ワークフロー作業時のみ
Desktop PCGateway + メッセージング + UI作業時のみ
Storage ServerObservability + オブジェクトストレージ24/7

Desktop PC と Compute Server は同時に起動・停止する前提です。Storage Server は常時稼働し、Prometheus/Grafana/Loki で全体を監視します。


ディスク設計

設計方針

SATA は OS、設定、シーケンシャル書き込みに使います。NVMe はランダム I/O と実データに使います。

SATA 3.84TB (ブートディスク)

LUKS → LVM → ext4 としました。LVM で root とログ領域を段階的に拡張できます。

LVサイズ用途
/2048GBOS + アプリ定義 (/opt含む)
/var/log32GBシステムログ (Loki/promtail用に分離)
VG Free~1.8TBSnapshot / 将来拡張

/var/log を分け、ログ増加で root 領域が埋まることを防ぎます。

NVMe (M.2) 3.84TB

LUKS → xfs とし、LVM は使いません。全体を /home に割り当て、サービスの実データを保存します。

  /home/ksh3/
  +-- postgres/data         # DB本体 (WAL含む)
  +-- trino/{spill,exchange,cache}
  +-- prometheus/data       # TSDB
  +-- loki/{data,cache}
  +-- qdrant/data           # ベクトルインデックス
  +-- models/               # LLMモデル群 (vLLM/llama.cpp/ollama)
  +-- dagster/{runs,storage,tmp}
  +-- workspace/            # VSCode clone repos
  +-- obsidian/
  

暗号化と起動時解除

  • SATA: Dropbear-initramfs でリモートSSH LUKS解除
  • M.2: /etc/crypttab の鍵ファイルで、root解除後に自動解除
  # /etc/crypttab
dm_crypt-0 UUID=... none luks,discard,initramfs
home-crypt UUID=... /etc/luks-keys/home.key luks
  

root はリモートで解除でき、/home は手動で解除する必要がありません。


ディレクトリ配置: 3層分離

原則

層パス内容ディスク
定義/opt/containers/{app}/compose.yml, .env, secrets, systemdテンプレートSATA
本番データ/srv/gitリポジトリ, Icebergウェアハウス, メディアSATA
実行時データ/home/ksh3/{app}/DB本体, spill, cache, モデル, ビルド成果物NVMe

ディレクトリ配置

  /opt/containers/
+-- common/
|  +-- networks/create_networks.sh
|  +-- systemd/podman-compose@.service
|  +-- env/                   # 共有.env
+-- postgres/
|  +-- compose.yml, conf/, .env, secrets/
+-- trino/
+-- nessie/
+-- prometheus/
+-- loki/
+-- dagster/
+-- vllm/
+-- qdrant/
  

/srv (SATA)

  /srv/
+-- git/bare/                 # git --bare init
+-- iceberg/warehouse         # データレイク本体
+-- nessie/data               # RocksDBストア
+-- media/{raw,derived,thumbs,archive}
  

NVMe の透過的利用

I/O 負荷の高いデータは NVMe に置き、/etc/fstab の bind マウントで利用パスを統一します。

  # /etc/fstab
/mnt/nvme/postgresql/data   /home/postgres/data   none bind 0 0
  

バックアップツールは /home 配下をスキャンしてデータを収集できます。


UID/GID 戦略

原則

サービスごとに専用 UID/GID を作り、コンテナ内 UID と合わせます。

  • 予約レンジ: 2001-2999(コンテナアプリ専用)
  • 基盤系 (2001-2099): Caddy, Registry, Monitoring
  • データ系 (2101-2199): Trino, MinIO, Postgres (公式イメージ UID 999)
  • AI/LLM系 (2301-2399): vLLM, llama.cpp

設定例

  # Trino ユーザー作成
groupadd -g 2101 trino && useradd -r -u 2101 -g 2101 -m -d /home/trino -s /usr/sbin/nologin trino
install -d -o 2101 -g 2101 -m 0750 /home/trino/{data,logs,scratch}
  

Podman での明示指定

  services:
  trino:
    image: trinodb/trino:443
    user: "2101:2101"
    volumes:
      - /opt/trino/etc:/etc/trino:ro    # 設定は /opt から readonly
      - /home/trino/data:/var/trino/data # データは /home へ
      - /home/trino/logs:/var/log/trino
      - /home/trino/scratch:/var/trino/scratch
    tmpfs:
      - /tmp:rw,nosuid,nodev,relatime,size=8g
  

CPU 帯設計

9175F の16コアを用途別に割り当てます。コア固定とクォータで、レイテンシの変動と過剰なCPU使用を抑える方針です。

CPUの割り当て

プールコア帯用途
常駐 (apps)CPU 0-7DB, IDE, LLM, 監視
バッチ (jobs)CPU 8-15ELT, 分析, バックアップ
軽量常駐CPU 6-7exporter群

用途別の割り当て

サービスcpusetcpusメモリ上限補足
監視レーン10.5-1.0256MB-2GBPrometheus/Loki は SATA推奨
PostgreSQL2-3 (バースト 2-4)2.0 (3.0)32-64GB
PgBouncer20.5512MB接続圧縮
VSCode Server3-43.0-4.024-48GB体感優先
Ollama5-61.0-2.016GB + GPU短リク優先
Trino4-166-12.0128GB (256GB)heavy は同時1本
Dagster4-161.0-2.02-4GB実処理は worker

oneshot ジョブ

ジョブcpusetcpusメモリ上限
DataFusion Worker4-164-8.064-256GB
dbt run4-166-12.08-32GB
PG Load (120GB級)2-3-PG: 64GB
Iceberg メンテ4-162-6.08-32GB
VACUUM / REINDEX2-32.02-4GB

起動パラメータ例

  # PostgreSQL (常用)
podman run -d --name pg \
  --cpuset-cpus=2-3 --cpus=2.0 --cpu-weight=900 \
  --memory=48g -v /opt/postgres:/var/lib/postgresql/data postgres:18

# PostgreSQL (重い日)
podman update --cpuset-cpus=2-4 --cpus=3.0 --memory=64g pg
  

サービス配置

Linux Server (Backend, Data Engine)

  +-- PostgreSQL 18 + pgvector (JIT有効)
+-- Dagster (daemon + sensor + user-code gRPC)
+-- NATS 2.11 (JetStream)        ← Desktop PCと同居
+-- multi-bert-inference (Rust + ONNX Runtime)
+-- vLLM / llama.cpp / LM Studio
+-- Vector 0.45 (Rust)
+-- Trino + Nessie (Phase 2, Lakehouse)
+-- Podman rootless
  

Mac Studio (Frontend, UI Hub)

  +-- agent-gateway (Go/Gin)
+-- VSCode.app (Remote-SSH → Linux)
+-- Grafana UI
+-- Dagit UI
+-- Web Browser (Trino Web UI, etc.)
  

Storage Server (24/7 Observability)

  +-- Prometheus
+-- Grafana
+-- Loki
+-- Vector (aggregator)
+-- MinIO
  

運用ルール

バックアップ

  • NAS: 毎日 tar.gz、14世代
    • 対象: /home/ksh3/, /srv/iceberg/, /srv/nessie/, /srv/media/, PGバックアップ
    • 除外: */{tmp,cache,spill,exchange}
  • R2: 必要に応じて成果物を rclone sync

掃除

  find /home/ksh3/*/cache -type f -mtime +14 -delete
find /home/ksh3/*/tmp   -type f -mtime +7  -delete
  

監視

  • Prometheus node_exporter の textfile collector で /home/ksh3/*/ の使用量を監視
  • pg_stat_activity, wait_event, PSI, Trino query memory / spill を確認
  • correlation_id 付きの構造化ログで全経路トレーシング

OS 初期化

Ubuntu Server 24.04.3 LTS (minimized) に、次の依存パッケージを導入しました。

  sudo apt install -y --no-install-recommends \
  build-essential curl wget git unzip vim less man-db \
  net-tools iputils-ping nmap iperf3 mtr \
  htop btop nvtop iftop logrotate rclone \
  fzf ripgrep bat \
  openssh-server dropbear-initramfs libfido2-1 libu2f-udev fido2-tools \
  nvidia-headless-580 nvidia-utils-580 \
  podman podman-compose \
  dbus-user-session \
  locales fonts-noto-cjk fonts-noto-cjk-extra
  

GPU、コンテナ、リモート接続、日本語フォント、CLI ツールを用意します。dbus-user-session は rootless Podman と user service に必要です。


注意事項

  • /home を M.2 に集約しているため、NVMe 故障時にサービスデータを失います。世代を分けたバックアップが必要です
  • rootless Pod の userns / slirp4netns で、1024未満のホストポートを使うには別途設定が必要です
  • PostgreSQL 18 の JIT 用に shm_size: 4gb を設定しています。不足すると OOM kill のリスクがあります
  • CPU ピン留めを YAML と CLI のどちらで管理するかを統一します。混在すると再起動後に設定が失われる場合があります

最終構成

実行基盤の詳細は次の記事にあります。