コマンド集 / 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 status が running でも中が進んでいるとは限らない(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 になった実例あり。