EPYCとPodmanのローカル開発基盤
EPYC 9175F、Mac Studio、Storage Serverを10GbEでつないだ開発基盤です。LLM導入とインフラ構築に向け、CPU割り当て、ディスク、暗号化、UID/GIDを整理しました。
構築した基盤
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 Server | GPU推論 + データ基盤 + ワークフロー | 作業時のみ |
| Desktop PC | Gateway + メッセージング + UI | 作業時のみ |
| Storage Server | Observability + オブジェクトストレージ | 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 | サイズ | 用途 |
|---|---|---|
| / | 2048GB | OS + アプリ定義 (/opt含む) |
| /var/log | 32GB | システムログ (Loki/promtail用に分離) |
| VG Free | ~1.8TB | Snapshot / 将来拡張 |
/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-7 | DB, IDE, LLM, 監視 |
| バッチ (jobs) | CPU 8-15 | ELT, 分析, バックアップ |
| 軽量常駐 | CPU 6-7 | exporter群 |
用途別の割り当て
| サービス | cpuset | cpus | メモリ上限 | 補足 |
|---|---|---|---|---|
| 監視レーン | 1 | 0.5-1.0 | 256MB-2GB | Prometheus/Loki は SATA推奨 |
| PostgreSQL | 2-3 (バースト 2-4) | 2.0 (3.0) | 32-64GB | |
| PgBouncer | 2 | 0.5 | 512MB | 接続圧縮 |
| VSCode Server | 3-4 | 3.0-4.0 | 24-48GB | 体感優先 |
| Ollama | 5-6 | 1.0-2.0 | 16GB + GPU | 短リク優先 |
| Trino | 4-16 | 6-12.0 | 128GB (256GB) | heavy は同時1本 |
| Dagster | 4-16 | 1.0-2.0 | 2-4GB | 実処理は worker |
oneshot ジョブ
| ジョブ | cpuset | cpus | メモリ上限 |
|---|---|---|---|
| DataFusion Worker | 4-16 | 4-8.0 | 64-256GB |
| dbt run | 4-16 | 6-12.0 | 8-32GB |
| PG Load (120GB級) | 2-3 | - | PG: 64GB |
| Iceberg メンテ | 4-16 | 2-6.0 | 8-32GB |
| VACUUM / REINDEX | 2-3 | 2.0 | 2-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 のどちらで管理するかを統一します。混在すると再起動後に設定が失われる場合があります
最終構成
実行基盤の詳細は次の記事にあります。
- Go + NATS + Dagster AIオーケストレーション基盤 — devstackコンテナ構成、3ホストトポロジー、NATSイベント設計
