本文へ移動
cccskills
無料GitHub で公開

linstor-bench

LINSTOR/DRBD ストレージベンチマーク。VM上でfioを実行し、thin/thick-stripe構成の性能を計測する。

インストール方法を見る

含まれるファイル(1)

  • SKILL.md30.3 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

LINSTOR ベンチマークスキル

LINSTOR/DRBD ストレージ上に VM を作成し、fio でベンチマークを実行する。 引数 storage_type で thin (LVM thin pool) または thick-stripe (LVM 4本ストライプ) を選択する。 オプションで region を指定して特定リージョンでベンチマークを実行する。

マルチリージョン構成

リージョンノードDRBD通信特徴
region-a4号機 + 5号機 + 6号機IPoIB 192.168.100.xInfiniBand 高速通信
region-b7号機 + 8号機 + 9号機IPoIB 192.168.100.xInfiniBand 高速通信

region 指定時は、そのリージョンの最初のノードに VM を配置し、同リージョン内の2ノードで DRBD レプリケーションを行う。 config/linstor.yml の regions セクションからノード構成を読み取る。

事前準備

  1. LINSTOR/DRBD が全ノードにインストール済み (linstor-controller, linstor-satellite, drbd-dkms, drbd-utils, linstor-proxmox)
  2. PVE クラスタが構築済み (pvecm status で Quorate)
  3. LINSTOR ノードが登録済み (linstor node list で全ノード Online)
  4. IB インターフェース (ibp*) が登録済み + PrefNic 設定済み (両リージョン)
    • 確認: ssh -F ssh/config pve$N "ip link show type ipoib" で ibp* が UP であること
    • 未設定の場合: scp + ssh ib-setup-remote.sh --persist で設定 (詳細は linstor-node-ops スキル N7 参照)
  5. Debian cloud image が PVE ホスト上にダウンロード済み (パスは config/linstor.yml の benchmark.cloud_image)
  6. vendor snippet (ssh-pwauth.yml) が PVE ホスト上に作成済み (後述)
  7. config/linstor.yml の benchmark: セクションが設定済み

スクリプト一覧

スクリプト用途
./scripts/linstor-bench-preflight.shディスク SMART ヘルスチェック (SCP で PVE ノードに転送して実行)

設定値の読み取り

YQ="${PROJECT_DIR}/bin/yq"
CONFIG="config/linstor.yml"

# リージョン指定時のノード選択
# region-a: nodes[0]=4号機, nodes[1]=5号機
# region-b: nodes[2]=6号機, nodes[3]=7号機
# リージョン未指定時はデフォルトで region-a (nodes[0], nodes[1])
REGION="${2:-region-a}"  # 第2引数

if [ "$REGION" = "region-b" ]; then
    NODE1=$("$YQ" '.regions.region-b[0]' "$CONFIG")
    NODE2=$("$YQ" '.regions.region-b[1]' "$CONFIG")
else
    NODE1=$("$YQ" '.regions.region-a[0]' "$CONFIG")
    NODE2=$("$YQ" '.regions.region-a[1]' "$CONFIG")
fi

# ノード名からIPを取得
NODE1_IP=$("$YQ" ".nodes[] | select(.name == \"$NODE1\") | .ip" "$CONFIG")
NODE2_IP=$("$YQ" ".nodes[] | select(.name == \"$NODE2\") | .ip" "$CONFIG")
DISKS=$("$YQ" ".nodes[] | select(.name == \"$NODE1\") | .storage_disks[]" "$CONFIG")

# ストレージ
VG_NAME=$("$YQ" '.vg_name' "$CONFIG")
RG_NAME=$("$YQ" '.resource_group' "$CONFIG")
PLACE_COUNT=$("$YQ" '.place_count' "$CONFIG")

# ベンチマーク
VM_ID=$("$YQ" '.benchmark.vm_id' "$CONFIG")
VM_NAME=$("$YQ" '.benchmark.vm_name' "$CONFIG")
VM_CORES=$("$YQ" '.benchmark.vm_cores' "$CONFIG")
VM_MEMORY=$("$YQ" '.benchmark.vm_memory' "$CONFIG")
VM_DISK_SIZE=$("$YQ" '.benchmark.vm_disk_size' "$CONFIG")
VM_BRIDGE=$("$YQ" '.benchmark.vm_bridge' "$CONFIG")
VM_MGMT_BRIDGE=$("$YQ" '.benchmark.vm_mgmt_bridge' "$CONFIG")
VM_MGMT_IP=$("$YQ" '.benchmark.vm_mgmt_ip' "$CONFIG")
VM_MGMT_PREFIX=$("$YQ" '.benchmark.vm_mgmt_prefix' "$CONFIG")
VM_USER=$("$YQ" '.benchmark.vm_user' "$CONFIG")
VM_PASS=$("$YQ" '.benchmark.vm_password' "$CONFIG")
CLOUD_IMAGE=$("$YQ" '.benchmark.cloud_image' "$CONFIG")
FIO_RUNTIME=$("$YQ" '.benchmark.fio_runtime' "$CONFIG")
FIO_SIZE=$("$YQ" '.benchmark.fio_size' "$CONFIG")
FIO_SEQ_SIZE=$("$YQ" '.benchmark.fio_seq_size' "$CONFIG")

既知の失敗と対策

前回のベンチマーク実行で発生した失敗パターン。各フェーズでこの対策を適用する。

ID失敗フェーズ検出方法対策
F1ディスク不良セクタPhase 0SMART Current_Pending_Sector > 0ゼロ書きで強制再割り当て
F2LINSTOR リソース名が vm-100-disk-0 ではなく pm-XXXXPhase 3qm importdisk 出力に pm-XXXX と表示importdisk 出力をパースしてリソース名を取得
F3cloud-init SSH パスワード認証無効Phase 3Permission denied (publickey)vendor snippet ssh_pwauth: true + --cicustom
F4VM MAC アドレス不一致で IP 検出失敗Phase 4IP 検出タイムアウト管理用 IP (10.x) が config で設定済みのため不要。DHCP のみの場合は qm config から MAC を動的取得
F5Thick LVM で DRBD 全領域同期Phase 4peer-disk:Inconsistent が長時間ポーリングで待機 (thin は ~30秒)
F6linstor --output-format json 不存在Phase 4unrecognized arguments エラーlinstor -m resource list を使う
F7citype デフォルト (configdrive2) が Debian に非対応Phase 3cloud-init 設定が VM に反映されない--citype nocloud を初回起動前に設定
F8LINSTOR Auto-eviction がノードオフライン時にリソースを自動退去Phase 4-5linstor node list で "Auto-eviction at ..." 表示テスト前に無効化
F9fio JSON 出力ディレクトリが未作成Phase 5No such file or directoryローカルの mkdir -p を先頭に追加
F10--boot order=scsi0 をディスクインポート前に設定Phase 3device 'scsi0' does not existimportdisk → scsi0 接続の後に boot order を設定
F11DRBD 9 の同期確認に /proc/drbd (DRBD 8形式) を使用Phase 4タイムアウトまたは空出力drbdsetup status <res> --verbose を使用
F12sshpass が非コントローラ PVE ホストに未インストールPhase 4sshpass: command not found公開鍵認証 + 10.x 直接 SSH を使用するため sshpass 不要
F13VM 再作成後に SSH known_hosts のホスト鍵が不一致Phase 4REMOTE HOST IDENTIFICATION HAS CHANGEDssh-keygen -R <vm_ip> -f ssh/known_hosts で事前クリア
F14Satellite ノードで linstor コマンドが localhost controller に接続不可Phase 4Connection refused全 linstor コマンドは Controller ノード (4号機) で実行
F15cloud-init DHCP でアドレス取得失敗 → SSH 不能Phase 3IP 検出タイムアウトDHCP 取得を最大5分待機。管理用 SSH は ipconfig1 の static 10.x で行うため DHCP 完了前でもアクセス可能
F16vendor snippet ssh_pwauth=true でもパスワード認証不可Phase 3-4Permission denied (publickey)SSH 公開鍵認証を優先: qm set --sshkeys <pubkey_file>
F17Debian 13 (OpenSSH 10.0) で RSA 鍵が無効化Phase 3-4Permission denied (publickey)Ed25519 鍵 (id_ed25519.pub) を使用すること
F18DRBD non-UpToDate 中に qm resize が失敗Phase 3LINSTOR API 500 エラーDRBD 同期完了後に resize する。resize 後に VM 内で growpart + resize2fs も必要
F19PrefNic 変更後に既存 DRBD リソースが自動再接続されることを知らないPhase 2-4手動 drbdadm adjust を実行してしまうPrefNic 変更すると LINSTOR が自動的に drbdadm adjust 相当を実行し、既存リソースが IB 経由に切り替わる。手動 drbdadm adjust は不要

F1: ディスク不良セクタ

SMART の Current_Pending_Sector が 0 より大きいディスクには不良セクタがあり、I/O エラーの原因になる。 ゼロ書きで該当セクタに書き込むと、ディスクが代替セクタに再割り当てを行う。

# 不良セクタの強制再割り当て (対象ディスクに対して実行)
ssh root@<node_ip> 'dd if=/dev/zero of=/dev/sdX bs=1M count=100 oflag=direct'
ssh root@<node_ip> 'dd if=/dev/zero of=/dev/sdX bs=1M count=100 oflag=direct seek=$(($(blockdev --getsize64 /dev/sdX)/1048576 - 100))'
# 再チェック
ssh root@<node_ip> 'smartctl -A /dev/sdX | grep -E "Current_Pending|Reallocated|Offline_Uncorrectable"'

F2: LINSTOR リソース名

qm importdisk が LINSTOR ストレージにディスクをインポートすると、リソース名が pm-XXXX (ランダム) になる。 vm-100-disk-0 のような標準名にはならないため、importdisk の出力からリソース名をパースする必要がある。

# importdisk 実行結果の例:
# unused0: successfully imported disk 'linstor-storage:pm-bfea68ea_100'
# → パースして 'pm-bfea68ea_100' を取得し、qm set --scsi0 に使用
# 注意: リソース名は pm-<hex>_<vmid> 形式。[0-9]* ではなく [a-z0-9_]+ でマッチすること
IMPORT_OUTPUT=$(ssh root@$NODE1_IP "qm importdisk $VM_ID $CLOUD_IMAGE linstor-storage" 2>&1)
RESOURCE_NAME=$(echo "$IMPORT_OUTPUT" | grep -o "linstor-storage:pm-[a-z0-9_]*" | sed 's/linstor-storage://')
ssh root@$NODE1_IP "qm set $VM_ID --scsi0 linstor-storage:$RESOURCE_NAME,discard=on,iothread=1"

F3: cloud-init SSH パスワード認証

Debian cloud image はデフォルトで SSH パスワード認証が無効。--cipassword を設定しても SSH できない。 vendor snippet で ssh_pwauth: true を設定する必要がある。

# vendor snippet を PVE ホストに作成 (snippets ディレクトリが必要)
ssh root@$NODE1_IP 'mkdir -p /var/lib/vz/snippets'
ssh root@$NODE1_IP 'printf "#cloud-config\nssh_pwauth: true\n" > /var/lib/vz/snippets/ssh-pwauth.yml'
# VM に適用
ssh root@$NODE1_IP "qm set $VM_ID --cicustom 'vendor=local:snippets/ssh-pwauth.yml'"

F4: VM MAC アドレスの動的取得

注: 管理用 IP (10.x) が config で設定済み (vm_mgmt_ip) の場合、MAC アドレス検出・nmap スキャン・ARP 参照は不要。 VM_IP=$VM_MGMT_IP で直接 SSH 接続できる。

以下は DHCP のみの構成で IP 検出が必要な場合の参考手順:

MAC=$(ssh root@$NODE1_IP "qm config $VM_ID" | grep '^net0' | grep -o 'virtio=[0-9A-Fa-f:]*' | cut -d= -f2)
ssh root@$NODE1_IP "ip neigh | grep -i '$MAC' | awk '{print \$1}'"

F7: citype nocloud

Debian の cloud-init は nocloud データソースを使う。PVE のデフォルト configdrive2 では設定が反映されない。

ssh root@$NODE1_IP "qm set $VM_ID --citype nocloud"

F8: LINSTOR Auto-eviction

ノードがオフラインになると LINSTOR は約60分後に Auto-eviction を発動し、リソースを自動退去させる。 ベンチマーク中にノード障害やリブートが発生すると、意図しないリソース再配置が起きる。

検出:

ssh root@$NODE1_IP "linstor node list"
# "Auto-eviction at 2026-XX-XX XX:XX:XX" が表示される

対策 (テスト前に各ノードで無効化):

ssh root@$NODE1_IP "linstor node set-property $NODE1 DrbdOptions/AutoEvictAllowEviction false"
ssh root@$NODE1_IP "linstor node set-property $NODE2 DrbdOptions/AutoEvictAllowEviction false"

テスト終了後に再有効化:

ssh root@$NODE1_IP "linstor node set-property $NODE1 DrbdOptions/AutoEvictAllowEviction"
ssh root@$NODE1_IP "linstor node set-property $NODE2 DrbdOptions/AutoEvictAllowEviction"

F9: fio 出力ディレクトリ未作成

fio の JSON 出力を SSH 経由で stdout リダイレクトする場合、出力先ディレクトリはローカルホスト側 (Claude Code 実行マシン) に必要。

# Phase 5 の先頭で実行
mkdir -p tmp/<session-id>/fio-results/

F10: boot order 設定の順序

qm importdisk → qm set --scsi0 → qm set --boot order=scsi0 の順で実行すること。 importdisk 前や scsi0 接続前に boot order を設定すると、scsi0 デバイスが存在しないためエラーになる。

F11: DRBD 9 の同期確認

DRBD 9 では /proc/drbd は空または DRBD 8 と形式が異なる。同期状態の確認には以下を使用:

# 推奨: 全リソースのステータス
ssh root@$CONTROLLER_IP "drbdsetup status --verbose"
# 特定リソース
ssh root@$CONTROLLER_IP "drbdsetup status <resource> --verbose"
# peer-disk で UpToDate を確認
# drbdadm status も使用可能 (ANSI カラーコード付き)

F12: sshpass 未インストール

公開鍵認証 + 10.x 管理用 IP への直接 SSH を使用するため、sshpass は不要。 VM への SSH は ssh ${VM_USER}@${VM_MGMT_IP} で直接接続する。

F13: SSH known_hosts ホスト鍵不一致

VM を再作成すると SSH ホスト鍵が変わるため、known_hosts に古い鍵が残っているとエラーになる。

# VM の IP に対してホスト鍵をクリア
ssh-keygen -R <vm_ip> -f ssh/known_hosts
# PVE ホスト側でも同様
ssh root@$NODE1_IP "ssh-keygen -R <vm_ip> -f ssh/known_hosts"

F14: Satellite ノードでの linstor コマンド

Satellite ノードには linstor-controller が動いていないため、linstor コマンドがデフォルトの localhost:3370 に接続しようとして失敗する。全 linstor コマンドは Controller ノード (4号機) 経由で実行すること。

F15-F16: SSH 接続の推奨方法

VM にはデュアル NIC を構成し、SSH は 10.x 管理用 IP に直接接続する:

  • net0: vmbr1 (192.168.39.0/24, DHCP, インターネット用)
  • net1: vmbr0 (10.0.0.0/8, static, SSH 管理用)

注意 (F17): Debian 13 cloud image (OpenSSH 10.0) は RSA 鍵が無効化されている。 /root/.ssh/id_rsa.pub ではなく Ed25519 鍵 (/root/.ssh/id_ed25519.pub) を使うこと。

  1. ローカルマシン (Claude Code ホスト) の Ed25519 公開鍵を qm set --sshkeys で設定:
    scp -F ssh/config ~/.ssh/id_ed25519.pub root@$NODE1_IP:/tmp/local_ed25519.pub
    ssh root@$NODE1_IP "qm set $VM_ID --sshkeys /tmp/local_ed25519.pub"
    
    • 注意: PVE ホストの鍵ではなくローカルの鍵を使うこと (SSH はローカルから直接 10.x に接続)
  2. ssh -o StrictHostKeyChecking=no debian@$VM_MGMT_IP でローカルから直接接続 (10.x 経由、sshpass 不要)
  3. DHCP は最大5分かかることがあるが、SSH は static 10.x なので DHCP 完了を待つ必要はない
  4. fio インストール (apt) にはインターネットが必要なので、cloud-init 完了を待つ:
    ssh ${VM_USER}@${VM_MGMT_IP} 'cloud-init status --wait'
    

注意: 192.168.39.0/24 に静的 IP を割り当てないこと (DHCP 衝突の危険)。

fio テスト定義

全7テスト。各テストは --runtime=$FIO_RUNTIME (デフォルト 60秒) で実行。

#テスト名rwbsiodepthsize
1randread-4k-qd1randread4k1$FIO_SIZE
2randread-4k-qd32randread4k32$FIO_SIZE
3randwrite-4k-qd1randwrite4k1$FIO_SIZE
4randwrite-4k-qd32randwrite4k32$FIO_SIZE
5seqread-1m-qd32read1m32$FIO_SEQ_SIZE
6seqwrite-1m-qd32write1m32$FIO_SEQ_SIZE
7mixed-rw-4k-qd32randrw (70/30)4k32$FIO_SIZE

共通オプション: --ioengine=libaio --direct=1 --numjobs=1 --time_based --group_reporting --output-format=json

フェーズ実行


Phase 0: Pre-flight — ディスクヘルスチェック

pve-lock: 不要

各ノードの各ストレージディスクの SMART をチェックし、不良セクタを検出する。

  1. preflight スクリプトを各ノードに転送:

    scp -F ssh/config ./scripts/linstor-bench-preflight.sh root@$NODE1_IP:/tmp/
    scp -F ssh/config ./scripts/linstor-bench-preflight.sh root@$NODE2_IP:/tmp/
    
  2. 各ノードで実行:

    ssh root@$NODE1_IP 'sh /tmp/linstor-bench-preflight.sh /dev/sda /dev/sdb /dev/sdc /dev/sdd'
    ssh root@$NODE2_IP 'sh /tmp/linstor-bench-preflight.sh /dev/sda /dev/sdb /dev/sdc /dev/sdd'
    
  3. 不良セクタ検出時 (exit 1):

    • 対策 F1 のゼロ書き手順でセクタを強制再割り当て
    • 再割り当て後に再実行して Current_Pending_Sector = 0 を確認

Phase 1: クリーンアップ

pve-lock: 必須

既存の VM、LINSTOR リソース、ストレージプール、LVM を解体する。 存在しないリソースの削除はエラーになるので、各ステップで存在確認してからスキップまたは削除する。

削除順序: VM → LINSTOR リソース → リソースグループ → ストレージプール → PVE ストレージ → LVM

  1. VM 停止・削除 (存在する場合):

    ssh root@$NODE1_IP "qm status $VM_ID" 2>/dev/null && \
      ssh root@$NODE1_IP "qm stop $VM_ID" && \
      ssh root@$NODE1_IP "qm destroy $VM_ID --purge"
    
  2. LINSTOR リソース削除 (存在する場合):

    # リソース定義一覧を確認
    ssh root@$NODE1_IP "linstor resource-definition list"
    # 各リソース定義を削除 (--async でタイムアウト回避)
    ssh root@$NODE1_IP "linstor resource-definition delete <resource-name>"
    
  3. PVE ストレージ削除:

    ssh root@$NODE1_IP "pvesm status" | grep linstor-storage && \
      ssh root@$NODE1_IP "pvesm remove linstor-storage"
    
  4. リソースグループ削除:

    ssh root@$NODE1_IP "linstor volume-group delete $RG_NAME 0" 2>/dev/null
    ssh root@$NODE1_IP "linstor resource-group delete $RG_NAME" 2>/dev/null
    
  5. ストレージプール削除:

    ssh root@$NODE1_IP "linstor storage-pool delete $NODE1 <pool-name>"
    ssh root@$NODE1_IP "linstor storage-pool delete $NODE2 <pool-name>"
    
  6. 各ノードで LVM 解体:

    ssh root@$NODE1_IP "vgs $VG_NAME" 2>/dev/null && \
      ssh root@$NODE1_IP "lvremove -f $VG_NAME 2>/dev/null; vgremove -f $VG_NAME; pvremove /dev/sda /dev/sdb /dev/sdc /dev/sdd"
    ssh root@$NODE2_IP "vgs $VG_NAME" 2>/dev/null && \
      ssh root@$NODE2_IP "lvremove -f $VG_NAME 2>/dev/null; vgremove -f $VG_NAME; pvremove /dev/sda /dev/sdb /dev/sdc /dev/sdd"
    
  7. 検証:

    ssh root@$NODE1_IP "linstor storage-pool list"
    ssh root@$NODE1_IP "linstor resource-definition list"
    ssh root@$NODE1_IP "pvesm status"
    

Phase 2: ストレージ構成

pve-lock: 必須

引数 storage_type に応じてストレージを構成する。

共通: VG 作成

各ノードで VG を作成する:

ssh root@$NODE1_IP "wipefs -af /dev/sda /dev/sdb /dev/sdc /dev/sdd && pvcreate /dev/sda /dev/sdb /dev/sdc /dev/sdd && vgcreate $VG_NAME /dev/sda /dev/sdb /dev/sdc /dev/sdd"
ssh root@$NODE2_IP "wipefs -af /dev/sda /dev/sdb /dev/sdc /dev/sdd && pvcreate /dev/sda /dev/sdb /dev/sdc /dev/sdd && vgcreate $VG_NAME /dev/sda /dev/sdb /dev/sdc /dev/sdd"

storage_type=thin の場合

# Thin pool 作成 (各ノード)
ssh root@$NODE1_IP "lvcreate -l 95%FREE -T ${VG_NAME}/thinpool"
ssh root@$NODE2_IP "lvcreate -l 95%FREE -T ${VG_NAME}/thinpool"

# LINSTOR ストレージプール (lvmthin)
POOL_NAME="thinpool"
ssh root@$NODE1_IP "linstor storage-pool create lvmthin $NODE1 $POOL_NAME ${VG_NAME}/thinpool"
ssh root@$NODE1_IP "linstor storage-pool create lvmthin $NODE2 $POOL_NAME ${VG_NAME}/thinpool"

storage_type=thick-stripe の場合

# LINSTOR ストレージプール (lvm)
POOL_NAME="striped-pool"
ssh root@$NODE1_IP "linstor storage-pool create lvm $NODE1 $POOL_NAME $VG_NAME"
ssh root@$NODE1_IP "linstor storage-pool create lvm $NODE2 $POOL_NAME $VG_NAME"

# ストライピングオプション設定 (-i4: 4本, -I64: 64KiB)
# ダッシュ引数が承認プロンプトに引っかかるため scp + ssh パターンで実行
# tmp/<session-id>/lvcreate-opts.sh に以下を Write (ノード名を変数で展開):
#   linstor storage-pool set-property <NODE> <POOL_NAME> StorDriver/LvcreateOptions -- '-i4 -I64'
scp -F ssh/config tmp/<session-id>/lvcreate-opts-node1.sh root@$NODE1_IP:/tmp/lvcreate-opts.sh
ssh root@$NODE1_IP sh /tmp/lvcreate-opts.sh
scp -F ssh/config tmp/<session-id>/lvcreate-opts-node2.sh root@$NODE1_IP:/tmp/lvcreate-opts.sh
ssh root@$NODE1_IP sh /tmp/lvcreate-opts.sh

共通: リソースグループ + DRBD オプション + PVE ストレージ

# リソースグループ
ssh root@$NODE1_IP "linstor resource-group create $RG_NAME --place-count $PLACE_COUNT --storage-pool $POOL_NAME"
ssh root@$NODE1_IP "linstor volume-group create $RG_NAME"

# DRBD オプション
ssh root@$NODE1_IP "linstor resource-group drbd-options --protocol C $RG_NAME"
ssh root@$NODE1_IP "linstor resource-group drbd-options --quorum off $RG_NAME"
ssh root@$NODE1_IP "linstor resource-group drbd-options --auto-promote yes $RG_NAME"

# PVE ストレージ
ssh root@$NODE1_IP "pvesm add drbd linstor-storage --resourcegroup $RG_NAME --content images,rootdir --controller $NODE1_IP"

検証

ssh root@$NODE1_IP "linstor storage-pool list"
ssh root@$NODE1_IP "pvesm status"

Phase 3: VM 作成

pve-lock: 必須

注意: cloud-init は初回起動時のみ実行される。すべての設定 (cicustom, citype, ciuser, cipassword, ipconfig0, ipconfig1) を qm start 前に完了すること。

  1. ブリッジ検証 (★ 7号機 NIC 逆順対策):

    # vmbr0 が 10.x (管理)、vmbr1 が 192.168.39.x (DHCP) であることを確認
    ssh root@$NODE1_IP "ip -4 addr show vmbr0"   # → 10.10.10.x が表示されるべき
    ssh root@$NODE1_IP "ip -4 addr show vmbr1"   # → 192.168.39.x が表示されるべき
    # 逆の場合は VM_BRIDGE と VM_MGMT_BRIDGE を入れ替える
    
  2. VM 作成 (★ デュアル NIC: net0=インターネット用, net1=管理用):

    ssh root@$NODE1_IP "qm create $VM_ID --name $VM_NAME --memory $VM_MEMORY --cores $VM_CORES --cpu host --net0 virtio,bridge=$VM_BRIDGE --net1 virtio,bridge=$VM_MGMT_BRIDGE --ostype l26 --scsihw virtio-scsi-single"
    
  3. ディスクインポート (★ F2 対策: リソース名をパース):

    IMPORT_OUTPUT=$(ssh root@$NODE1_IP "qm importdisk $VM_ID $CLOUD_IMAGE linstor-storage" 2>&1)
    RESOURCE_NAME=$(echo "$IMPORT_OUTPUT" | grep "successfully imported" | grep -o 'pm-[a-z0-9_]*')
    
    • RESOURCE_NAME が空の場合は出力全体を確認しエラー対処
    • 注意: grep は successfully imported 行のみ対象にすること。pm-<hex> と pm-<hex>_<vmid> の両方にマッチするため、正しい行から抽出しないと誤ったリソース名になる
  4. ディスク接続 (パースしたリソース名を使用):

    ssh root@$NODE1_IP "qm set $VM_ID --scsi0 linstor-storage:${RESOURCE_NAME},discard=on,iothread=1"
    
  5. ブート順序 + cloudinit ドライブ (★ F10: scsi0 接続後に設定すること):

    ssh root@$NODE1_IP "qm set $VM_ID --boot order=scsi0"
    ssh root@$NODE1_IP "qm set $VM_ID --ide2 linstor-storage:cloudinit"
    
  6. vendor snippet 作成・適用 (★ F3 対策):

    ssh root@$NODE1_IP 'mkdir -p /var/lib/vz/snippets'
    ssh root@$NODE1_IP 'printf "#cloud-config\nssh_pwauth: true\n" > /var/lib/vz/snippets/ssh-pwauth.yml'
    ssh root@$NODE1_IP "qm set $VM_ID --cicustom 'vendor=local:snippets/ssh-pwauth.yml'"
    
  7. citype 設定 (★ F7 対策):

    ssh root@$NODE1_IP "qm set $VM_ID --citype nocloud"
    
  8. SSH 公開鍵設定 (★ F16/F17 対策: Ed25519 公開鍵認証を使用):

    # ローカルマシン (Claude Code ホスト) の Ed25519 公開鍵を PVE ホストにコピー
    scp -F ssh/config ~/.ssh/id_ed25519.pub root@$NODE1_IP:/tmp/local_ed25519.pub
    ssh root@$NODE1_IP "qm set $VM_ID --sshkeys /tmp/local_ed25519.pub"
    
    • 注意: PVE ホストの鍵ではなく、ローカルマシンの公開鍵を設定すること。SSH はローカルから 10.x 経由で直接接続するため
  9. cloud-init ユーザ・ネットワーク設定 (★ デュアル NIC: DHCP + 管理用 static):

    ssh root@$NODE1_IP "qm set $VM_ID --ciuser $VM_USER --cipassword $VM_PASS --ipconfig0 ip=dhcp --ipconfig1 ip=$VM_MGMT_IP/$VM_MGMT_PREFIX"
    
    • ipconfig0: vmbr1 (DHCP, インターネット用)
    • ipconfig1: vmbr0 (static 10.x, SSH 管理用, ゲートウェイ不要)
  10. VM 起動 (★ resize は DRBD 同期完了後に行うため先に起動):

    ssh root@$NODE1_IP "qm start $VM_ID"
    

Phase 4: 同期待ち + SSH 接続

pve-lock: 不要

DRBD 同期待ち (★ F5)

thick-stripe の場合、全領域の DRBD 初期同期が発生する。thin の場合は使用済み領域のみで ~30秒。

実測同期レート (SATA HDD over IPoIB):

ディスクサイズ所要時間レート
32G~9分—
518 GiB~92分~96 MiB/s

ポーリング間隔: 30秒 (drbdsetup status)

# 同期状態のポーリング (30秒間隔) (★ F11: drbdsetup を使用、/proc/drbd は DRBD 9 で空)
ssh root@$CONTROLLER_IP "drbdsetup status --verbose"
# 出力例 (同期中): peer-disk:Inconsistent
# 出力例 (完了): peer-disk:UpToDate
# ★ F14: linstor/DRBD コマンドは Controller ノード (4号機) で実行すること
# ★ 接続先アドレスの確認には `drbdsetup show <resource>` を使う (IP 表示あり)。
#    `drbdsetup status --verbose` では接続先 IP が表示されない

UpToDate/UpToDate になるまでポーリングで待機する。

ディスクリサイズ (★ F18: DRBD 同期完了後に実行)

ssh root@$NODE1_IP "qm resize $VM_ID scsi0 $VM_DISK_SIZE"
# VM 内でパーティション + ファイルシステム拡張
ssh ${VM_USER}@${VM_MGMT_IP} "sudo growpart /dev/sda 1"
ssh ${VM_USER}@${VM_MGMT_IP} "sudo resize2fs /dev/sda1"

VM 管理 IP

VM の管理用 IP は config から既知 (10.x static)。MAC アドレス検出・nmap スキャン・ARP テーブル参照は不要。

VM_IP=$VM_MGMT_IP

注: F4 (MAC アドレス不一致) は管理用 IP が config で設定済みのため不要。 DHCP の 192.168.39.x IP はインターネット通信専用で、SSH 接続には使用しない。

SSH 接続テスト (★ F13)

# ★ F13: VM 再作成時はホスト鍵をクリア
ssh-keygen -R $VM_IP -f ssh/known_hosts

# 10.x 管理用 IP に直接 SSH (公開鍵認証、Phase 3 で --sshkeys 設定済み)
ssh -o StrictHostKeyChecking=no -o ConnectTimeout=10 ${VM_USER}@${VM_IP} 'uname -a'

cloud-init 完了待ち + fio インストール

DHCP (vmbr1) は最大5分かかる場合がある。SSH は 10.x (static) 経由なので DHCP 完了前でもアクセス可能。 ただし fio インストール (apt) にはインターネットが必要なので、cloud-init 完了を待つ。

ssh ${VM_USER}@${VM_IP} 'cloud-init status --wait'
ssh ${VM_USER}@${VM_IP} 'sudo apt-get update && sudo apt-get install -y fio'

注意 (F6): LINSTOR の JSON 出力は linstor --output-format json ではなく linstor -m (machine-readable) を使う。 --output-format オプションは存在しない。


Phase 5: ベンチマーク実行

pve-lock: 不要

7テストを順番に実行する。各テスト結果は JSON で tmp/<session-id>/fio-results/ に保存する。

# ★ F9: 出力ディレクトリをローカル側に事前作成
mkdir -p tmp/<session-id>/fio-results

各テストの実行 (10.x 管理 IP に公開鍵認証で SSH 接続):

ssh ${VM_USER}@${VM_IP} "sudo fio \
  --name=<test-name> \
  --ioengine=libaio --direct=1 \
  --rw=<rw-pattern> --bs=<block-size> \
  --iodepth=<queue-depth> --numjobs=1 \
  --size=<size> \
  --runtime=$FIO_RUNTIME --time_based \
  --group_reporting --output-format=json" \
  > tmp/<session-id>/fio-results/<test-name>.json

テスト一覧 (fio テスト定義セクション参照):

  1. randread-4k-qd1: --rw=randread --bs=4k --iodepth=1 --size=$FIO_SIZE
  2. randread-4k-qd32: --rw=randread --bs=4k --iodepth=32 --size=$FIO_SIZE
  3. randwrite-4k-qd1: --rw=randwrite --bs=4k --iodepth=1 --size=$FIO_SIZE
  4. randwrite-4k-qd32: --rw=randwrite --bs=4k --iodepth=32 --size=$FIO_SIZE
  5. seqread-1m-qd32: --rw=read --bs=1m --iodepth=32 --size=$FIO_SEQ_SIZE
  6. seqwrite-1m-qd32: --rw=write --bs=1m --iodepth=32 --size=$FIO_SEQ_SIZE
  7. mixed-rw-4k-qd32: --rw=randrw --rwmixread=70 --bs=4k --iodepth=32 --size=$FIO_SIZE

Phase 6: 結果抽出 + レポート

pve-lock: 不要

  1. fio JSON から主要メトリクスを抽出:

    • IOPS (read/write)
    • BW (KiB/s or MiB/s)
    • Avg Latency (ms)
    • p99 Latency (ms)
  2. Python スクリプトで JSON をパース:

    # tmp/<session-id>/extract-fio.py を作成して実行
    python3 tmp/<session-id>/extract-fio.py tmp/<session-id>/fio-results/
    

    fio JSON の構造:

    jobs[0].read.iops, jobs[0].read.bw (KiB/s), jobs[0].read.clat_ns.mean (ns), jobs[0].read.clat_ns.percentile["99.000000"] (ns)
    jobs[0].write.iops, jobs[0].write.bw (KiB/s), jobs[0].write.clat_ns.mean (ns), jobs[0].write.clat_ns.percentile["99.000000"] (ns)
    
  3. report/ にレポート生成 (REPORT.md フォーマット準拠):

    • 環境情報 (ハードウェア、ソフトウェア、DRBD 構成)
    • ストレージ構成 (thin or thick-stripe)
    • ベンチマーク結果テーブル (IOPS, スループット, レイテンシ)
    • 分析 (ボトルネック、前回結果との比較 (あれば))
    • 再現方法

oplog

状態変更操作は ./oplog.sh で記録する:

  • Phase 1 (クリーンアップ): VM 削除、LINSTOR リソース削除、LVM 解体
  • Phase 2 (ストレージ構成): VG 作成、ストレージプール作成
  • Phase 3 (VM 作成): qm create, qm importdisk, qm start

読み取り専用操作 (linstor storage-pool list, drbdadm status, fio 実行) は oplog 不要。

pve-lock の使い方

Phase 1〜3 では状態変更操作に ./pve-lock.sh を使用する:

./pve-lock.sh run <command...>     # 即座に実行(ロック中ならエラー)
./pve-lock.sh wait <command...>    # ロック待ち→実行

ロック中の場合は別の課題に着手し、ロック解放後に再開する。

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

bios-setup

無料日本語概要

Supermicro X11DPU/X10DRT-P BIOS Setup 操作。KVM スクリーンショット + キーストロークで BIOS メニューを操作する。BIOS 設定変更、確認、保存を行う。4-6号機 + 10号機対応。

miminashi/pvese182026年7月6日 更新

dell-fw-download

無料日本語概要

Dell ファームウェアダウンロード。Playwright で dl.dell.com から BIN を取得し firmimg.d7 を抽出する。

miminashi/pvese182026年7月6日 更新

ib-switch

無料日本語概要

Mellanox SX6036 InfiniBand スイッチのシリアルコンソール操作。ステータス確認、show コマンド、IB 設定、FW 管理を行う。

miminashi/pvese182026年7月6日 更新

idrac7

無料日本語概要

iDRAC7 基本操作。SSH 経由で racadm コマンドを実行し、サーバ管理を行う。

miminashi/pvese182026年7月6日 更新

idrac7-fw-update

無料日本語概要

iDRAC7 ファームウェアアップデート。段階的アップグレードパスに従い TFTP 経由で適用する。

miminashi/pvese182026年7月6日 更新

irmc-bios-raid

無料日本語概要

Fujitsu iRMC S4 (TX1320 M3 等) の電源・BIOS・RAID 操作 + BIOS 設定リファレンス。Redfish (HTTPS + SECLEVEL=0) 経由の電源/ブート操作 + iRMC Web UI/KVM 経由の手動 BIOS/RAID 操作手順 + 全 BIOS 設定項目の網羅リファレンス (bios/)。training-tx1320 対応。

miminashi/pvese182026年7月6日 更新

miminashi のスキルをすべて見る

このスキルの問題を報告する