コマンド集 / Proxmox VE

Proxmox VE コマンド集

Proxmox VE 9 のクラスタ状態・qm/pct の操作・テンプレートと cloud-init・ストレージ・pve-firewall・移行・詰まったときの復旧手順を、ホームラボで実際に踏んだ罠つきで引ける。

更新

Debian 13 ベースの Proxmox VE 9 を複数ノード(node1 〜)でクラスタ <クラスタ名> として動かしている環境向け。共有ストレージは NFS の shared だけで、ゲストのディスクは各ノードの local-lvm に置いている。

状態を見る#

クラスタとクォーラム#

片ノードを止める前と、/etc/pve が書けなくなったときに最初に打つ。

pvecm status
pveversion -v | head -3

⚠️ 3 ノード以上なら two_node: 1 を入れない。2 ノード時代の暫定設定で、3 ノードでは有害。

ゲストの一覧と所在#

pvesh はどのノードにいるかを含めてクラスタ全体を返す。

qm list
pct list
pvesh get /cluster/resources --type vm

⚠️ qm / pctそのノードにあるゲストしか扱えない。別ノードのゲストに打つと Configuration file ... does not exist になる。先に所在を引く。

1 台の状態と設定#

qm status <vmid>
qm config <vmid>
pct config <ctid>

⚠️ qm statusrunning でも中が進んでいるとは限らない(UEFI の「Press any key」で止まっていた例あり)。

ゲストエージェントに聞く#

エージェント経由で OS 情報や IP を取る。エージェントが入っていない cloud image では応答しない。

qm agent <vmid> ping
qm agent <vmid> get-osinfo
qm guest exec <vmid> -- <実行ファイ> <>

⚠️ qm guest exec--synchronous 0--timeout を併用できない。引用符つきの引数は多段の経路で壊れるので、ASCII だけのスクリプトをゲストに置いてから引用符なしで呼ぶ。

作る・消す#

VM の起動・停止・強制リセット#

shutdown は ACPI(エージェント有効時はエージェント経由)。効かなければ reset

qm shutdown <vmid> --timeout 300 && qm start <vmid>
qm shutdown <vmid> --timeout 120 --forceStop 1 && qm start <vmid>
qm reset <vmid>

⚠️ エージェントが死んでいると qm shutdown は効かないので --forceStop 1 を付ける。qm shutdown ... | tail -1; echo $? はパイプの終了コードを見てしまう。

LXC を作る#

Debian テンプレートから非特権 CT を作る例。

pct create <ctid> local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst --arch amd64 \
  --hostname <ホスト> --cores 1 --memory 1024 --swap 512 --rootfs local-lvm:8 \
  --net0 name=eth0,bridge=vmbr0,ip=dhcp \
  --nameserver 8.8.8.8 --onboot 1 --unprivileged 1 && pct start <ctid>

⚠️ 8.8.8.8 は「まだ内部 DNS が無い時期」の仮置き。戻し忘れると、その CT からだけ内部名が引けず、上に載せたサービスが静かに壊れる(外形監視では見えなかった実例あり)。

CT の DNS を戻す#

pct set <ctid> --nameserver '<DNS1のIP> <DNS2のIP>'
pct push <ctid> ./resolv.conf /etc/resolv.conf

⚠️ pct set --nameserver動いている CT の /etc/resolv.conf を書き換えないpct push で今すぐ直すか再起動する。

CT の中でコマンドを打つ#

pct exec <ctid> -- /usr/bin/systemctl is-active dns cloudflared

⚠️ pct exec の PATH は最小。フルパス必須

消す#

qm stop <vmid> && qm destroy <vmid> --purge
pct stop <ctid> && pct destroy <ctid> --purge

テンプレートと cloud-init#

テンプレートから複製する#

フルクローンにすると、出来た機はテンプレートの置き場に依存しない。

qm clone <テンプレートID> <新VMID> --name <> --full

⚠️ qm template した VM は普通の VM に戻せない。

cloud-init の値を入れて起動する#

Windows も cloudbase-init を仕込んであれば同じ形で通る(citype の指定は不要)。

qm set <vmid> --ciuser <ユーザ> --cipassword '<パスワード>' \
  --ipconfig0 ip=<VMのIP>/24,gw=<GWのIP> --nameserver <DNSのIP>
qm set <vmid> --sshkeys ~/.ssh/id_ed25519.pub
qm start <vmid>

⚠️ --sshkeysファイルパスを取る。API 側は値を URL エンコードして渡す決まりなので、同じつもりで書くと「そんなファイルは無い」で落ちる。

vendor-data でゲストエージェントを仕込む#

cloud image には qemu-guest-agent が入っていない。テンプレート側に仕込むと払い出した全機に入る。

qm set <vmid> --cicustom vendor=local:snippets/cloud-agent.yaml
qm cloudinit update <vmid>

⚠️ local は既定で snippets を含まない。--cicustom は設定しただけでは反映されず qm cloudinit update が要る。snippets はノード単位なので、無くなるとそのノードのクローンが起動しない。

テンプレートを共有ストレージへ移す#

scsi0 だけ移すと EFI と TPM が元ノードに残り、そのノードでしか複製できない。

for d in scsi0 efidisk0 tpmstate0; do qm move-disk <vmid> $d shared --format qcow2 --delete; done

構築が終わったら ISO を外す#

ISO の参照が残ったまま ISO 名を変えると、次の再起動で volume 'local:iso/...' does not exist で起動しなくなる。稼働中は気づかない。

qm set <vmid> --ide2 none,media=cdrom
qm set <vmid> --boot order=scsi0

ストレージを見る#

空きと使用量#

pvesm status の列は Total / Used / Available / %

pvesm status
pvesm list local-lvm
df -h /var/lib/vz
lvs

⚠️ Used を「空き」と読み違えた実例あり。迷ったら df と突き合わせる。

ZFS ノードなら#

zpool status
zfs list -o name,used,avail,refer

ファイアウォール(pve-firewall)#

解釈結果を読む#

設定ファイルの見た目ではなく、PVE が解釈した結果を読む。

pve-firewall status
pvesh get /nodes/<node>/qemu/<vmid>/firewall/options

⚠️ [OPTIONS] の行に末尾コメントを書くとその行ごと黙って捨てられるpolicy_in が消えると既定の DROP になり受信が全部落ちる。コメントは行の上に置く。

ゲストで有効にする#

.fw を置くだけでは効かない。NIC に firewall=1 が要る。

cur=$(pct config <ctid> | sed -n 's/^net0: //p')
pct set <ctid> -net0 "${cur},firewall=1"

⚠️ 立てた瞬間 NIC が瞬断する。稼働中の Windows VM で qm set -net0 するとホットプラグになりゲストエージェントが落ちた。VM は停止 → 設定 → 起動で当てる。

本当に通っているか#

ログが 0 件でも、チェーンのカウンタが 0 なら「1 パケットも通っていない」。

iptables -L GROUP-<グループ>-OUT -n -v | head -3
tail -f /var/log/pve-firewall.log

⚠️ カウンタはノード再起動で 0 に戻る。回転した .1 / .N.gz も読むこと。当日分だけ見て「7 日観測した」と言った実例あり。

移行#

ライブマイグレーション#

共有ストレージが無くてもローカルディスクごと動かせる。

qm migrate <vmid> <移行先ノー> --online --with-local-disks
pct migrate <ctid> <移行先ノー> --restart

⚠️ cpu: host の VM は別 CPU のノードへライブ移行できない。表に出るのは mirror-scsi0: Input/output error なのでディスクを疑いやすいが真因は CPU。停止してから移すか、種別を x86-64-v3 などにする。

困ったとき#

ロックされた VM#

qm unlock <vmid>
pct unlock <ctid>

片ノード障害で /etc/pve が read-only#

2 ノード構成で相方を失ったとき、生き残り側で期待投票数を下げる。

pvecm expected 1

リンクが落ちた#

USB NIC の自己リセットで vmbr0 がポートを失ったときの復旧。

ip link set nic0 up && ifreload -a
ip -br link show master vmbr0

⚠️ ifreload は過去に事故がある。リモートから打つときは二次経路を確保してから。

証明書(ACME)が期限切れ#

自動更新は pve-daily-update.timer。先にそのログを見てから強制更新する。

journalctl -u pve-daily-update --no-pager -n 50
pvenode acme cert renew --force

⚠️ pvenode acme plugin list は API トークンを平文で表示する。打たない。

メモリが返ってこない(バルーン)#

QEMU はゲストが触ったページを返さない。shares: 0 で自動バルーンから外し、手動で目標値を入れる。

qm set <vmid> --balloon <下限MiB> --shares 0
echo "balloon <下限MiB>" | qm monitor <vmid>

⚠️ ピンは再起動で消える。恒久化するなら post-start の hookscript で入れ直す。

見るべきログ#

ホスト側#

journalctl -u pvedaemon -u pveproxy --since "1 hour ago"
journalctl -u pve-cluster -u corosync -b
journalctl -p err -b
tail -n 20 /var/log/pve/tasks/index

⚠️ qmshutdown ... got timeout のまま「再起動した」と言わない。結果はタスク index に残る。

ゲストエージェントのタイムアウト#

qga command ... got timeout が多いときは、そのゲストがホストの全コアを取っていないか見る。

journalctl -u pvedaemon --since today | grep -c "got timeout"

⚠️ 4 コアのホストで 4 コアの VM を動かすと pvedaemon に回るコアが残らない。コア数を減らして 8 分の 1 になった実例あり。