KVM・Xen・LXCの違いとVPSの見分け方
KVM、Xen、LXCの違いで、VPSが専用kernelか共有kernelかが決まります。swap、nested virtualisation、steal timeの挙動まで比較し、契約したVPSの実態を見分けます。
VPS プランが実際に提供しているもの
KVM、Xen、LXC は、VPS プランの基盤となる 3 つの仮想化方式です。これはプロバイダーのラック内の細かな違いではありません。自分の kernel を使えるかどうかを決める違いです。モジュールのロード、swap の制御、nested virtualisation の実行、/proc が自分のサーバーと他者のサーバーのどちらを示すか、steal time をそもそも測定できるかどうかなど、利用者が気にする点はすべてこの事実から決まります。
完全仮想化(KVM と Xen HVM)では、各テナントに kernel と仮想マシンが提供されます。準仮想化 Xen でも kernel は提供されますが、その kernel は自分が guest であることを認識し、特権処理を hypervisor に依頼します。コンテナ型プラン(LXC、または OpenVZ と Virtuozzo 系列)では、プロバイダーの kernel 上で filesystem と一連の namespace が提供されます。3 つとも、同じ 3 文字の名称で販売されています。
KVM vs Xen vs LXC: カーネルを個別に持つか、1 つのカーネルを共有するか
KVM と Xen では、uname -r がカーネルを指定します。別のカーネルをインストールし、モジュールを読み込み、そのカーネルで再起動できます。そこで行った操作が、別のテナントに影響することはありません。コンテナプランでは、uname -r がホスト上で実行され、同じマシン上のすべてのコンテナが共有するプロバイダーのカーネルを指定します。カーネルは変更できません。また、apt install linux-image-generic で展開したファイルが起動することもありません。
この違いだけで、仕様表の情報より多くのことが分かります。このガイドの残りは、この違いから生じる結果として読んでください。
完全仮想化: KVM と Xen HVM
KVM (kernel-based virtual machine) は Linux カーネル内のモジュールです。CPU に組み込まれた Intel VT-x または AMD-V 命令を使用し、通常の Linux ホストをハイパーバイザーに変えます。QEMU はその周囲で仮想ハードウェアを提供します。ディスク、ネットワークカード、シリアルコンソールなどです。Xen は異なる設計です。Xen 自体がハイパーバイザーであり、Linux より先に起動します。dom0 と呼ばれる特権管理ドメインが管理スタックを実行し、各テナントは domU になります。Xen HVM (hardware virtual machine) は KVM と同じ CPU 拡張機能を使用します。通常は、エミュレートされたハードウェアが遅いため、ディスクとネットワークに準仮想化ドライバーを使用します。この組み合わせを PVHVM と呼びます。
テナントから見ると、両者の動作はほぼ同じです。カーネル、ブートローダー、実際のブロックデバイス、動作する modprobe、正しい /proc、自分専用の swap、そして実際に起動まで行う再起動を利用できます。プロバイダーが ISO の接続を許可していれば、提供されていないディストリビューションもインストールできます。
その代わり、収容密度は低くなります。4 GB のメモリは自分のマシン用に確保されます。アイドル状態でも隣のユーザーに貸し出すことはできません。また、各ゲストは QEMU プロセス、独自のページテーブル、独自のページキャッシュを持ちます。このコストがあるため、同じ数値を示すコンテナプランより KVM プランの料金は高くなります。
準仮想化 Xen と、その見分け方
Xen PV は、CPU に仮想化命令が搭載される前から存在していました。特権命令をトラップする代わりに、ゲストカーネルを変更してハイパーバイザーを直接呼び出します。VT-x なしで動作します。2005 年当時は、これが目的でした。カーネルは pygrub または pvgrub によって、独自のディスクイメージ内から読み込まれます。そのため自分のカーネルを使用しますが、PV ゲストをサポートするようにビルドされている必要があります。
次のような兆候があれば、その環境で動作しています。lscpu は仮想化の種類として full ではなく para を報告します。/sys/hypervisor/type が存在し、Xen と表示されます。ディスクは vda や sda ではなく xvda です。SMBIOS または DMI テーブルを読み取るツールは、読み取る情報を見つけられません。PV ゲストには、これらのテーブルを公開するファームウェアがないためです。
PV では、ネストした仮想化を恒久的に利用できません。PV ゲストには CPU の仮想化拡張機能が表示されないため、その内部でハイパーバイザーを実行できません。Xen 自体が廃れたわけではありません。廃れたのは Xen PV という方式です。Xen プロジェクトは PVH と HVM へ移行しました。プランに「Xen」とだけ記載されている場合は、どの方式かを確認してください。HVM は、現在一般的な VPS です。PV は、より安い料金で提供されるべきプランです。
コンテナ VPS: LXC と OpenVZ 系統
コンテナ VPS は、Linux namespace(プロセス ID、マウント、ネットワークインターフェース、ホスト名、ユーザーを分離して見せる仕組み)と、cgroups(control group。カーネルによるリソース制限)を組み合わせ、プロバイダーのカーネル上で実行する環境です。使用する init はホスト上のプロセスです。使用する ls はホストのカーネル上で直接実行され、エミュレーションや別のスケジューラーを介しません。そのため、コンテナは高速で高密度に運用できます。
注文ページに表示される名称は、LXC、Proxmox VE コンテナ(LXC を使用)、OpenVZ、Virtuozzo です。OpenVZ 7 と Virtuozzo は、同じ考え方から派生した商用製品です。
利用者に影響する変更は4つあります。
- モジュール。
modprobeは何も挿入しません。WireGuard、ZFS、または特定の netfilter モジュールがプロバイダーのカーネルに組み込まれていなければ、利用できません。 sysctl。/proc/sysの大部分は読み取り専用です。ネットワークは実際の namespace なので、通常はnet.ipv4.ip_forwardとその関連設定を書き換えられます。vm.swappinessやfs.file-maxのようなマシン全体に関わる設定はホスト側に属します。- 入れ子のコンテナ。LXC コンテナ内の Docker は、プロバイダーが nesting を有効にし、ストレージドライバーが対応する場合にのみ動作します。購入前にテストし、利用できると決めつけないでください。
- カーネルのバージョン。再起動を含め、プロバイダーの更新スケジュールに従うことになります。
購入した種類を判別する方法
サーバー上で次のコマンドを実行し、結果をまとめて確認します。1 つのコマンドだけでは判定できません。
systemd-detect-virt
systemd-detect-virt -c
lscpu | grep -iE 'hypervisor|virtualization'
uname -r
ls /lib/modules/$(uname -r) 2>/dev/null | head -n 3
cat /sys/hypervisor/type 2>/dev/nullsystemd-detect-virt は、固定された選択肢から短い識別子を 1 つ出力します。マシン側には kvm、qemu、xen、amazon、vmware が含まれます。コンテナ側には lxc、lxc-libvirt、openvz、docker、systemd-nspawn が含まれます。何も検出しない場合は none を出力し、0 以外の終了ステータスで終了します。-c 形式はコンテナ技術に対してのみ回答するため、ここで none 以外の結果が出れば、販売ページの説明に関係なく判定できます。
lscpu はハイパーバイザーのベンダーを示し、仮想化方式が完全仮想化か準仮想化かも示します。これにより Xen HVM と Xen PV を区別できます。/sys/hypervisor/type は Xen 環境でのみ存在します。
/lib/modules の確認は省略されがちですが、最も直接的な判定方法です。実行中のカーネルバージョン用ディレクトリが存在しないか空であるにもかかわらず、そのカーネルでシステムが明らかに動作している場合、そのカーネルはファイルシステムから起動されていません。ホストから提供されており、モジュールツリーもイメージ内にインストールされていません。これはコンテナです。
別の方法で確認するには、sudo apt install -y virt-what && sudo virt-what を実行します。これは専用ツールとして検出テストを実行します。root が必要で、ベアメタルでは何も出力しません。
コンテナ内で /proc が誤ったマシンを示す理由
KVM または Xen のゲストでは、/proc/meminfo はハイパーバイザーから割り当てられたメモリを、独自の kernel が計上した値です。これはゲスト自身についての値であり、ホストについては何も示しません。これが仮想マシンの仕組みです。
コンテナでは、その計上を行う別の kernel が存在しないため、/proc はホストの /proc です。LXCFS は、これらのファイルの一部を書き換えて cgroup の制限に合わせる小規模な filesystem です。対象は /proc/cpuinfo、/proc/meminfo、/proc/stat、/proc/uptime、/proc/swaps、/proc/diskstats、/sys/devices/system/cpu/online です。Proxmox はデフォルトで LXCFS を mount します。一方、小規模な provider の多くは mount しません。その場合、free -m はホスト全体のメモリを報告し、nproc はマシン上のすべての core を報告することがあり、uptime はホストの稼働時間を報告します。
これは見た目だけの問題ではありません。ソフトウェアはこれらのファイルから自身のサイズを決めるためです。nginx は worker_processes auto を使って認識できる core 数を数えます。2 core の quota が設定された 64 core のホスト上で make -j$(nproc) を実行すると、64 個の compiler を起動します。MemTotal から cache サイズを決める JVM や database は、cgroup が許可しない値を選択します。その値に達すると、kernel は process を kill します。この kill はホストの kernel log に記録されますが、そこは読み取れません。
正しい値は /proc ではなく、cgroup にあります。
cat /sys/fs/cgroup/memory.max
cat /sys/fs/cgroup/memory.current
cat /sys/fs/cgroup/cpu.maxこれらは cgroup v2 の path です。現在の distribution では cgroup v2 が使用されています。memory.max で max を読み取った結果は、その階層に制限が設定されていないことを意味します。cpu.max は quota と period を microsecond 単位で出力します。そのため、200000 100000 は period ごとに 2 core 分の CPU time が割り当てられていることを示します。古い cgroup v1 のホストでは、同じ値が /sys/fs/cgroup/memory/memory.limit_in_bytes と /sys/fs/cgroup/cpu/cpu.cfs_quota_us の下にあります。
Swap と実際の所有者
KVM と Xen では、swap は利用者自身の管理対象です。swap はディスク上のファイルまたはパーティションであり、ページングは利用者の kernel が実行します。
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
swapon --showswapon --show を実行すると、ファイルとそのサイズ、priority が表示されます。swapon でファイルが拒否される場合は、代わりに dd if=/dev/zero of=/swapfile bs=1M count=2048 で作成してください。未書き込みの extent を含む事前割り当てファイルは、一部のファイルシステムで拒否されるためです。/swapfile none swap sw 0 0 を /etc/fstab に追加してください。追加しないと、次回の再起動後に swap が失われます。
コンテナでは、これらはどれも利用者の管理対象ではありません。swapon には、権限のないコンテナが保持していない capability が必要です。そのため、独自の swap ファイルを作成すると、ディスクに到達する前に権限エラーで失敗します。プランで swap と呼ばれているものは、host 側の cgroup 設定です。cgroup v2 では memory.swap.max に該当し、host 自身の swap device を使用します。以前の OpenVZ プランでは「vswap」という割り当てが提供されていました。これはディスクというより、バースト用のクレジットに近い動作でした。上限は確認できます。その上限の下にある device を制御することはできません。
ネスト仮想化と、誤解を招く CPU フラグ
ネスト仮想化とは、VPS 内でハイパーバイザーを実行することです。QEMU ゲストや Vagrant box、独自の VM を持つネスト仮想化ラボなどが該当します。2 つの条件を両方満たす必要があります。プロバイダーがホストでネストを有効にしていることと、ゲストに CPU の仮想化拡張機能が提示されていることです。
lscpu | grep -i virtualization
ls -l /dev/kvm
sudo apt install -y cpu-checker && sudo kvm-okネストを有効にした KVM ゲストでは、/dev/kvm が存在し、kvm-ok によってアクセラレーションを使用できるかどうかを明確に確認できます。Xen HVM では技術的に可能ですが、提供されることはほとんどありません。Xen PV では実行できません。
コンテナでは、この確認が分かりやすい形で失敗します。/proc/cpuinfo はホストのファイルなので、vmx または svm フラグが存在し、その値自体は正しいものです。実際に、その環境下の物理 CPU には該当する命令があります。ただし、それはあなたのものではありません。名前空間内に /dev/kvm はなく、kvm_intel モジュールもロードできません。いま読んだフラグが示しているのは、あなたが制御するマシンではなく、あなたがゲストとして動作しているマシンです。これは一般則を最も明確に示す例です。コンテナでは、/proc は名前空間と周囲のハードウェアを示すものであり、自分が所有するサーバーを示すものではありません。
AES-NI とプランで公開される CPU 機能
AES-NI(advanced encryption standard new instructions)は、AES 暗号化をソフトウェアで同じ計算を行う場合より数倍高速にする CPU 命令セットです。TLS 終端、ディスク暗号化、SSH、バックアップ処理は、いずれも AES-NI に大きく依存します。
KVM では、ゲストから見える CPU 機能は、プロバイダーが QEMU に設定した CPU モデルで決まります。host passthrough を使用すると、実際のフラグが見えます。qemu64 のような汎用モデルや、異なるホスト間でゲストを移行できるよう意図的に古いベースラインを選択した構成では、aes フラグが存在しない場合があります。その場合、OpenSSL は通知なしにソフトウェア処理へフォールバックします。
lscpu | grep -ow aes | head -n 1
openssl speed -evp aes-128-gcm
env OPENSSL_ia32cap='~0x200000000000000:~0x20000000000:~0x0:~0x0:~0x0' openssl speed -evp aes-128-gcm3 番目のコマンドは、OpenSSL のマニュアルにある、ライブラリ内でこれらの命令を無効にする例です。AES-NI ビットと VAES ビットをクリアし、それ以外はそのままにします。2 つのスループット値を比較してください。値が近い場合は、そもそも高速パスが使用されていなかったことを示します。プランを契約する前に 5 分かけて VPS で AES-NI を正しく確認する方法 を調べる価値があります。
コンテナの前段には CPU モデルがないため、/proc/cpuinfo に表示されるフラグはホストの実際のフラグであり、そのまま利用できます。これはコンテナプランの明確な利点です。また、このガイドで共有カーネルが有利に働く唯一の場面でもあります。
Steal time の発生源と、コンテナに存在しない理由
Steal time は、仮想 CPU が実行可能な状態だったにもかかわらず、hypervisor が別の処理を実行していたために実行されなかった時間です。st と top、vmstat では st として表示され、/proc/stat の cpu 行では 8 番目のフィールドとして表示されます。
ゲストは、時間を奪われている間は実行されていないため、この値を自分で測定できません。hypervisor がゲストに通知する必要があります。KVM は paravirtual clock インターフェースを通じてゲストが登録するページに累積値を書き込み、Xen は同じ目的で vCPU ごとの実行状態領域を保持します。読み取る値は hypervisor 自身が申告した値です。そのため、この値が存在し、信頼する価値があります。
Steal time が大きい場合、ホストのリソースが過剰に割り当てられており、その時点で同居する他の利用者が CPU を多く使用しています。これは、販売された vCPU 数と物理コア数の比率が表面化したものです。Steal time を読み取って noisy neighbour を検出することで、プランの実力が仕様に記載された規模どおりかどうかを判断できます。
vmstat 1 5
cat /sys/fs/cgroup/cpu.statコンテナでは、hypervisor がスケジューラーとの間に存在しないため、この列の値は変化しません。プロセスは、ホスト自身の CPU スケジューラーで通常のタスクとして、他のすべてのテナントのプロセスと同じキューに入ります。競合が発生しても、原因を示すカウンターはなく、処理に単純に時間がかかる形で現れます。最も近い指標は quota throttling です。プロバイダーが cpu.max を設定すると、/sys/fs/cgroup/cpu.stat は nr_throttled 回の期間をカウントし、throttled_usec は次の quota window を待機したマイクロ秒数をカウントします。これは自分の quota だけを対象とし、同居する他の利用者との競合は対象にしません。注意点として、プロバイダーのコンテナホスト自体が仮想マシンである場合、/proc/stat に steal の値が現れることがあります。ただし、その値は利用者自身ではなく、そのホストに属します。
過剰販売と、コンテナプランが安い理由
正直な答えは簡単です。コンテナプランが安いのは、プロバイダーが同じマシンをより多くの利用者と共有しているためです。
最も差が大きいのはメモリです。KVM ゲストの RAM はそのゲストに割り当てられるため、256 GB を搭載したホストでは、オーバーヘッドを除き、おおむね 256 GB 分のゲストを販売します。一方、コンテナのメモリ上限は予約ではなく上限です。コンテナが使用していないメモリは、すぐに他のコンテナが利用できます。そのためプロバイダーは、物理 RAM の数倍に相当する上限を販売しても、ほぼ常に問題なく運用できます。何かをごまかしているわけではありません。十分な数のテナントが同時に高負荷になるまでは機能しますが、その状態になると全員に影響します。
CPU は、KVM を含むすべてのプラン種別で過剰販売されています。実際のコア数を超える vCPU を販売するためです。ディスクも、ほぼすべての環境でシンプロビジョニングされています。コンテナでは、さらに高密度化できます。カーネルは 1 つで、ページキャッシュも共有され、ゲストごとの QEMU プロセスも不要です。そのため、1 台のホストに数倍のテナントを収容できます。
その代わりに失うのは分離性です。これは恐怖をあおる話ではなく、実際の設計上のトレードオフです。カーネルを共有するため、カーネルのバグは共有環境全体の問題になります。また、コンテナエスケープが発生すると、攻撃はホストへ直接到達します。仮想マシンからのエスケープにはハイパーバイザーのバグが必要であり、対象ははるかに小さく、悪用も困難です。さらに、プロバイダーのカーネル更新や再起動のスケジュールにも従う必要があります。これらのいずれかが重要なら、価格だけで選ぶ前に VPS ホスティングの実際の安全性 を確認してください。
購入するタイプ
独自の kernel が必要な場合は KVM を選びます。WireGuard や ZFS のモジュール、特定の kernel バージョン、nested virtualisation、swap の実際の制御、監査担当者に説明できる分離境界が必要な場合です。一般的なサービスを低予算で運用し、プロバイダーの kernel が最新で、依存する機能がすでに kernel にコンパイルされていることを確認できている場合は、container plan を選びます。ほとんどの用途では Xen HVM を KVM と同等に扱えます。現在も Xen PV として提供されているものについては、購入前に確認してください。
この区分に当てはまらない形態が2つあります。Firecracker microVM では、container に近い起動コストで、テナントごとに実際の kernel を使用できます。serverless platform はこの方式で動作します。Incus system container では、自分で管理する hardware 上で container model を運用できます。これは、container として提供された環境を利用する場合とは異なります。用語が問題になる場合は、VPS とは実際には何か と VPS、VM、VPC の違い を参照してください。これらでは、このガイドで前提としている用語を説明しています。
FAQ
VPS が KVM かコンテナかを確認するにはどうすればよいですか?
systemd-detect-virt -c を実行します。none 以外の回答が返る場合は、プランに記載された製品名にかかわらず、コンテナ内にいます。検出結果は偽装されることがあるため、さらに 2 通りの方法で確認してください。lscpu はハイパーバイザーのベンダー名と、仮想化方式が完全仮想化か準仮想化かを示します。コンテナでは、実行中の kernel がホストから提供され、module tree がファイルシステムにインストールされていないため、ls /lib/modules/$(uname -r) は存在しないか空になります。sudo virt-what は、この確認専用に作られたツールによる独立した判定を返します。
free -m がプランの容量を大幅に上回るメモリを表示するのはなぜですか?
LXCFS が mount されていないコンテナプランを使用しているため、/proc/meminfo はホストのファイルを参照し、free はホストのメモリをそのまま報告しています。実際の上限は cgroup で決まります。/sys/fs/cgroup/memory.max で上限を、/sys/fs/cgroup/memory.current で現在の使用量を確認してください。古い cgroup v1 のホストでは /sys/fs/cgroup/memory/memory.limit_in_bytes を使用します。cache や worker pool のサイズをこの値から決めるサービスは、free ではなく、この上限を参照するように設定してください。
LXC VPS で Docker または WireGuard を実行できますか?
場合によっては可能ですが、インストールしたものだけで実現できるわけではありません。どちらも provider の kernel に依存するため、kernel に module を load することはできません。WireGuard は、module がホストにすでに存在し、利用できるよう公開されている場合に動作します。利用できない場合は、userspace の wireguard-go 実装が代替手段になります。Docker には、provider が nesting を許可していることと、コンテナ内で動作する storage driver が必要です。購入前に確認するか、問題があれば解約できる期間で試してください。
コンテナ VPS で steal time がまったく報告されないのはなぜですか?
steal time は、ハイパーバイザーが virtual CPU をスケジュールしている場合にのみ存在します。ハイパーバイザーがその値を kernel が読み取る page に書き込むため、報告されます。コンテナの下にはハイパーバイザーがありません。プロセスはホストの scheduler 上で通常の task として実行されるため、競合が発生すると、対応する counter がないまま処理全体が遅くなります。代わりに /sys/fs/cgroup/cpu.stat を確認してください。nr_throttled と throttled_usec は、cgroup が次の CPU quota window を待機した時間を計測します。これは、コンテナにおける steal に最も近い指標です。