2026年7月18日
2026年7月18日
KVM/VMwareの仮想マシンでWordPressを動かすときの最適な設定と注意点
KVMやVMware上の仮想マシン(VM)でWordPressが遅い・不安定なとき、原因はWordPressの設定ではなく「仮想ハードウェアの選び方」と「ゲストOS内のメモリ配分」にあることが少なくありません。この記事では、ハイパーバイザー側で見直す項目(準仮想化ドライバー、CPUモデル、ディスクのキャッシュ方式、スナップショット)と、ゲストOS側で見直す項目(PHP-FPMとMySQLのメモリ配分、時刻同期、TRIM)を、確認コマンドとあわせて説明します。自前の物理サーバーやプライベートクラウドでVMを管理している方向けの内容です。
設定変更の多くはVMの再起動を伴います。作業前にVM全体のバックアップ(またはスナップショット)とWordPressのファイル・データベースのバックアップを取り、可能なら同じ構成の検証用VMで試してから本番に反映してください。
まず「VMの中」で起きていることを確認する
チューニングの前に、遅さの原因がVMの外(ホストの混雑)にあるのか、中(ゲストのリソース不足)にあるのかを切り分けます。
# 仮想化の種類を確認(kvm / vmware などと表示される)
systemd-detect-virt
# 1秒ごとに5回、CPU・メモリ・I/Oの状況を表示
vmstat 1 5
vmstat の見どころは次の3列です。
- st(steal):ゲストが使いたかったのにホストに割り当ててもらえなかったCPU時間の割合です。常に数%以上出ている場合、ホスト側で他のVMとCPUを取り合っています。ゲストの中をいくら調整しても改善しないため、ホストの割り当てを見直します。
- wa(I/O wait):ディスク待ちの割合です。高い場合はディスクのドライバーやキャッシュ方式、ストレージそのものの性能を疑います。
- si / so(swap in / out):0以外が続く場合はメモリ不足です。PHP-FPMやMySQLの設定がVMのメモリ量に合っていない可能性があります。
この切り分けをしておくと、どの章の対策から始めるべきかが分かります。
ハイパーバイザー側の設定
準仮想化ドライバーを使う
VMのディスクやネットワークを「実在するハードウェアのふり」(エミュレーション)で動かすと、処理のたびに変換が入り遅くなります。KVMでは virtio、VMwareでは VMXNET3(ネットワーク)と PVSCSI(ディスクコントローラー)が準仮想化デバイスにあたり、WebサーバーのVMではこちらを選ぶのが基本です。
ゲスト側で実際に使われているドライバーは次のように確認できます。
# ネットワークのドライバー名(virtio_net / vmxnet3 など)
ethtool -i eth0 | grep driver
# 読み込まれている virtio 関連モジュール
lsmod | grep virtio
インターフェース名は環境によって ens3 などになるので、ip -br link で確認してから置き換えてください。最近の主要なLinuxディストリビューションはvirtioとVMXNET3のドライバーを標準で含んでいますが、既存VMのディスクコントローラーを後から変更すると起動しなくなることがあります。変更は検証用VMで手順を確かめてから行います。
CPUモデルとvCPU数
KVM(libvirt)では、ゲストに見せるCPUの種類を <cpu mode='host-passthrough'/> にすると、ホストCPUの命令セットをそのまま使えます。PHPやMySQLの処理効率に関わる一方、CPUの世代が異なるホスト間でライブマイグレーションができなくなる制約があります。クラスタで移動させる運用なら host-model や共通のCPUモデルを選びます。
vCPUは多ければ速いわけではありません。ホストの物理コア数に対して全VMのvCPU合計を大きく上回らせると、前述のsteal時間が増えます。小〜中規模のWordPressなら2〜4 vCPUから始め、負荷を見て増やす方が安全です。
ディスクのキャッシュ方式と形式
KVMでは、ディスク定義の cache と io の指定が性能と安全性の両方に影響します。libvirtのドメインXML(virsh edit VM名 で編集)の例です。
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' cache='none' io='native' discard='unmap'/>
<source file='/var/lib/libvirt/images/wordpress.qcow2'/>
<target dev='vda' bus='virtio'/>
</disk>
cache='none'はホストのページキャッシュを経由せずに書き込みます。ゲスト内のMySQLが自前でキャッシュを持つため二重キャッシュを避けられ、停電時のデータ整合性の面でも一般に推奨される設定です。io='native'はcache='none'(またはdirectsync)と組み合わせて使います。discard='unmap'はゲストのTRIMをディスクイメージに伝え、削除した領域を解放できるようにします。
cache='unsafe' のようにベンチマークで速く見える設定もありますが、ホスト障害時にデータベースが壊れるおそれがあるため本番のWordPressには使いません。VMwareでは、ディスクのシン・プロビジョニングは容量効率が良い反面、データストアの空きが尽きるとVMが停止します。データストアの残量監視をセットで行ってください。
スナップショットは「一時的な保険」として使う
スナップショットはプラグイン更新前などの一時的な戻り先として便利ですが、長期間残すと差分ファイルが大きくなり、ディスクI/Oが遅くなります。特にVMwareでは、スナップショットを何世代も残したままにするとパフォーマンス低下や容量逼迫の原因になると案内されています。作業が終わったら削除(統合)し、長期保管はバックアップで行います。
また、稼働中のVMをそのままスナップショットすると、MySQLの書き込み途中の状態を切り取ることがあります。KVMならゲストに qemu-guest-agent を入れて、ファイルシステムを一時停止してから取得すると整合性が保ちやすくなります。
# ゲスト側:エージェントを導入(Debian/Ubuntu系の例)
sudo apt install qemu-guest-agent
sudo systemctl enable --now qemu-guest-agent
# ホスト側:ゲストのファイルシステムを静止させてディスクのみのスナップショットを取得
virsh snapshot-create-as wordpress-vm before-update --disk-only --quiesce
ゲストエージェントを使うには、ドメインXMLに org.qemu.guest_agent.0 のチャネル定義が必要です。virt-manager などで作成したVMには最初から入っていることもあるので、virsh dumpxml で確認してください。VMwareでは VMware Tools(Linuxでは open-vm-tools)が同様の静止処理を担います。それでもデータベースの確実な戻り先として、mysqldump などの論理バックアップを別に取っておくと安心です。
ゲストOS側の設定
メモリの配分を先に決める
VMはメモリの上限がはっきりしているため、PHP-FPMとMySQL(MariaDB)にどれだけ割り当てるかを先に決めておくと、スワップによる急な遅延を防げます。たとえば4GBのVMにWordPressとMySQLを同居させるなら、OSと余裕分を残したうえで、MySQLのバッファとPHP-FPMのプロセス群に分けて考えます。
PHP-FPMの子プロセスがどれくらいメモリを使っているかは次のように測れます(プロセス名はPHPのバージョンやディストリビューションで異なります)。
# php-fpm 子プロセスの平均メモリ使用量(MB)
ps --no-headers -o rss -C php-fpm8.3 | awk '{s+=$1; n++} END {if (n) printf "%.1f MB\n", s/n/1024}'
この平均値で「PHP-FPMに使ってよいメモリ量」を割った値が pm.max_children の目安です。プラグインが多いサイトでは1プロセスあたりの使用量が大きくなるので、実測してから決めます。
; /etc/php/8.3/fpm/pool.d/www.conf の例(2GBをPHP-FPMに割り当て、1プロセス約80MBの場合)
pm = dynamic
pm.max_children = 24
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
MySQLを同じVMで動かす場合は、innodb_buffer_pool_size をデータベースの実サイズとVMのメモリ量に合わせて設定します。データベース専用VMでなければ、メモリの大半を割り当てるとPHP側が足りなくなるため、PHP-FPMの見積もりと合計して収まるかを確かめてください。
メモリバルーニングとスワップ
KVMのvirtio-balloonやVMwareのバルーンドライバーは、ホストのメモリが逼迫したときにゲストからメモリを回収します。ゲスト側から見ると突然メモリが減るため、PHP-FPMやMySQLがスワップを使い始めて応答が遅くなることがあります。重要なWordPressのVMは、ホスト側でメモリを予約(VMwareの予約設定、KVMならオーバーコミットしない設計)しておくと安定します。スワップ自体は、メモリ不足時にプロセスが強制終了されるのを避ける緩衝材として小さめに用意しておくのが一般的です。
時刻同期を一本化する
VMは一時停止やライブマイグレーションで時計がずれることがあります。時刻がずれると、WordPressの予約投稿、WP-Cronの実行タイミング、SSL証明書の検証、ログイン用のCookieの有効期限などに影響します。ゲスト内では chrony などのNTPクライアントを使い、VMware Toolsの定期的な時刻同期と二重にならないようにします。
# chrony の同期状態
chronyc tracking
# VMware Tools の定期時刻同期の状態(VMwareのみ)
vmware-toolbox-cmd timesync status
TRIMとI/Oスケジューラー
前述の discard='unmap' を設定したら、ゲスト側で定期的にTRIMを実行します。多くのディストリビューションには週1回実行するタイマーが用意されています。
sudo systemctl enable --now fstrim.timer
# 現在のI/Oスケジューラー([ ] で囲まれたものが有効)
cat /sys/block/vda/queue/scheduler
virtioディスクでは、ゲスト側のスケジューラーは none や mq-deadline が使われることが多く、通常は既定のままで問題ありません。並べ替えはホスト側のストレージに任せるという考え方です。
WordPress側で合わせて見直すこと
VMの設定を整えたら、WordPress側ではOPcacheの有効化、オブジェクトキャッシュ(Redisなど)の導入、ページキャッシュの利用といった一般的な高速化が効きやすくなります。VMならではの注意点としては、WP-Cronをアクセス任せにせず、wp-config.php で define( 'DISABLE_WP_CRON', true ); としたうえでシステムのcronから定期実行する方法があります。アクセスが少ない時間帯でも予約投稿や更新処理が遅れず、アクセスが多い時間帯にCronがリクエストに便乗して重くなることも避けられます。
# crontab -e で追加する例(5分ごと、WP-CLIを使用)
*/5 * * * * cd /var/www/wordpress && /usr/local/bin/wp cron event run --due-now --quiet
WP-CLIのパスやWordPressの設置場所は環境に合わせて変更してください。
よくあるつまずき
- ドライバーを変えたら起動しない:ディスクコントローラーをIDEやSATAからvirtio/PVSCSIへ変える場合、ゲストのinitramfsに該当ドライバーが含まれていないと起動ディスクが見つかりません。先に追加のディスクをvirtioで接続して認識を確認する、といった段階的な手順が安全です。
- ベンチマークは速いのに本番が遅い:stealやI/O waitを見ずに、ゲストの設定だけを変えているケースです。ホスト全体の負荷を確認します。
- スナップショットから戻したらDBが壊れていた:静止処理なしで取得したスナップショットの可能性があります。論理バックアップとの併用を検討します。
ハイパーバイザーのバージョンやVMwareの製品・ライセンス体系は変わることがあるため(2026年10月現在)、設定項目の名称や対応状況は利用中の製品の公式ドキュメントで確認してください。
まとめ
- まず
vmstatのst・wa・si/soで、原因がホストの混雑か、ゲストのリソース不足かを切り分けます。 - ハイパーバイザー側は、準仮想化ドライバー(virtio、VMXNET3/PVSCSI)、適切なCPUモデルとvCPU数、
cache='none'などの安全なディスク設定を基本にします。 - スナップショットは一時的な戻り先として使い、長期保管はバックアップで行います。DBの整合性にはゲストエージェントや論理バックアップを併用します。
- ゲスト側は、PHP-FPMとMySQLのメモリ配分を実測で決め、時刻同期を一本化し、TRIMを有効にします。
- 変更は検証用VMで試し、バックアップを取ってから本番に反映します。