結論

3台のマシンとRouterOS配下の10GbEネットワークで、LLM推論、データ基盤、開発環境、監視基盤を同居させても衝突しないローカル開発基盤を構築した。設計の核は「CPU帯を先に切る」「SATA/NVMeの役割を分ける」「ディレクトリ配置を3層に整理する」「UID/GIDを固定する」の4点で、これらを先に固定したことで、サービスが増えても配置ルールが崩れない土台になった。

この設計の上に、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 (SATA)

  /opt/containers/
+-- common/
|  +-- networks/create_networks.sh
|  +-- systemd/[email protected]
|  +-- 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 戦略

原則

1サービスにつき1つの専用 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コア高クロック。コア固定 + クォータの併用でレイテンシ安定と暴走抑止を両立する。

帯域分離

プールコア帯用途
常駐 (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 のどちらで持つかは運用ルールとして統一しておかないと、再起動後に設定が消える

最終構成

この設計の上に構築された実行基盤の詳細は以下を参照。