VM インスタンスのネストされた仮想化の有効化

このドキュメントでは、Compute Engine VM インスタンスでネストされた仮想化のサポートを有効にする方法について説明します。また、ネストされた VM の起動と構成の基本的な手順についても説明します。

ネストされた仮想化は、Intel VT-x プロセッサの仮想化命令が Compute Engine VM でサポートされるようにします。ネストされた仮想化を使用すると、Compute Engine で通常のように VM インスタンスを起動してから、その VM インスタンスに KVM 互換のハイパーバイザをインストールし、そのハイパーバイザ上で別の VM インスタンスを実行できます。Haswell または新しいプラットフォーム上で実行されている Linux VM インスタンスでは、ネストされた仮想化を使用できます。その他の制約については、ネストされた仮想化の制限というサブセクションをご覧ください。

ネストされた仮想化は、VM イメージを Compute Engine に変換またはインポートできないような、VM ベースのアプリケーションやワークロードに最適です。たとえば、ネストされた仮想化を使用すると、Compute Engine 上で動作する VM にシームレスにフェイルオーバーできるような KVM ベースの仮想マシン上で動作するオンプレミスのワークロード用の障害復旧ソリューションを、KVM ベースの VM をネイティブの Compute Engine イメージに変換するのに必要な余分な時間やオーケストレーションなしで構築できます。ネストされた仮想化に適した別のワークロードとしては、さまざまな KVM 互換 OS の多くのバージョンでソフトウェア パッケージの新しいバージョンをテストし検証する必要のあるソフトウェア検証フレームワークが挙げられます。ネストされた VM を実行すると、Compute Engine イメージの大規模なライブラリを変換して管理する必要がなくなります。

始める前に

ネストされた仮想化のしくみ

Compute Engine VM は、L0 環境と呼ばれる物理ハードウェア(ホストサーバー)の上で実行されます。ホストサーバー内には、プリインストールされたハイパーバイザがあり、Compute Engine 上で L1 またはネイティブ VM として参照される複数の Compute Engine VM を単一のサーバーがホストできます。ネストされた仮想化を使用する場合、L1 ゲスト OS の上に別のハイパーバイザをインストールし、L1 ハイパーバイザを使用して L2 VM と呼ばれるネストされた VM を作成します。ゲストのハイパーバイザとネストされた VM を実行している L1 またはネイティブの Compute Engine VM は、ホスト VM と呼ぶこともできます。

ネストされた仮想化の図

制限事項

  • ネストされた仮想化は、Haswell プロセッサ以降で動作する L1 VM に対してのみ有効にできます。ゾーンのデフォルト プロセッサが Sandy Bridge または Ivy Bridge の場合、最小 CPU の選択を使用し、特定のインスタンス向けに Haswell 以降を選択できます。リージョンとゾーンページを確認し、Haswell 以降のプロセッサをサポートするゾーンを決定します。
  • ネストされた仮想化は、Linux インスタンスで実行されている KVM ベースのハイパーバイザでのみサポートされています。Hyper-V、ESX、Xen のハイパーバイザはサポートされていません。
  • Windows VM ではネストされた仮想化はサポートされていません。つまり、ホスト VM で Linux OS を実行する必要があります。ただし、ネストされた VM は特定の Windows OS では実行できます(以下で説明)。

テスト済みの KVM バージョン

Google では、次のホスト VM とネストされた VM の組み合わせを使用して、ネストされた仮想化の基本的な起動および統合テストを行います。

  • 次のネストされた VM をホストする、カーネル バージョン 4.9 の Debian 9:
    • CentOS 6.5、カーネル バージョン 2.6
    • Debian 9、カーネル バージョン 4.9
    • RHEL 5.11、カーネル バージョン 2.6
    • SLES 12 SP3、カーネル バージョン 4.4
    • Ubuntu 16.04 LTS、カーネル バージョン 4.15
    • Windows Server 2008 R2
    • Windows Server 2016 Datacenter Edition
  • 次のネストされた VM をホストする、カーネル バージョン 4.4 の SLES 12 SP3:
    • SLES 12 SP3、カーネル バージョン 4.4
  • 次のネストされた VM をホストする、カーネル バージョン 4.15 の Ubuntu 16.04 LTS:
    • Ubuntu 16.04 LTS、カーネル バージョン 4.15

ここに記載されていないディストリビューションおよびカーネル / KVM バージョンでネストされた VM を実行する際に問題が発生した場合は、上記の環境のいずれかをホスト Compute Engine インスタンスでゲスト オペレーティング システムとして使用して問題を再現してから、問題を報告してください。

パフォーマンス

ハードウェア補助によるネストされた仮想化であっても、ネストされた VM 自体、およびそれらの内部で実行されているアプリケーションやワークロードには、パフォーマンス上のペナルティが発生します。特定のアプリケーションまたはワークロードの厳密なパフォーマンス低下を予測することは不可能ですが、CPU バウンドのワークロードには少なくとも 10% のペナルティが存在し、I/O バウンドのワークロードにはさらにペナルティが増える可能性があります。

インスタンス上でネストされた仮想化を有効にする

ネストされた仮想化を有効にするには、API または gcloud コンポーネントを使用します。ネストされた仮想化を有効にするには、L1 またはホスト VM インスタンスで VMX を有効にする特別なライセンスキーを使用してカスタム イメージを作成し、ネストされた仮想化の制限を満たすインスタンスでそのイメージを使用する必要があります。ライセンスキーには追加料金はかかりません。

  1. 公開イメージから、またはオペレーティング システムを含むカスタム イメージからブートディスクを作成します。または、この手順をスキップして、いずれかの VM インスタンスから既存のディスクにライセンスを適用することもできます。

    gcloud

    gcloud コマンドライン ツールを使用して、選択したブートディスク イメージからディスクを作成します。この例では、debian-9 イメージ ファミリーから disk1 という名前のディスクを作成します。

    gcloud compute disks create disk1 --image-project debian-cloud --image-family debian-9 --zone us-central1-b

    API

    debian-9 イメージ ファミリーから disk1 という名前のディスクを作成します。

    POST https://www.googleapis.com/compute/v1/projects/[PROJECT_ID]/zones/us-central1-b/disks
    
    {
     "name": "disk1",
     "sourceImage": "/projects/debian-cloud/global/images/family/debian-9"
    }

    ここで、[PROJECT_ID] はプロジェクト ID です。

  2. 作成したブートディスクまたは既存のインスタンスのブートディスクと仮想化に必要な特別なライセンスキーを使用して、カスタム イメージを作成します。

    gcloud

    「gcloud」コマンドライン ツールを使用してイメージを作成する場合は、「--licenses」フラグを使用して次のライセンス URL を指定します。

    https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx

    たとえば、次のコマンドは、「disk1」という名前のサンプル ディスクから「nested-vm-image」という名前のイメージを作成します。

    gcloud compute images create nested-vm-image \
      --source-disk disk1 --source-disk-zone us-central1-b \
      --licenses "https://www.googleapis.com/compute/v1/projects/vm-options/global/licenses/enable-vmx"

    API

    API で、API リクエストにライセンス プロパティを含めます。

    POST https://www.googleapis.com/compute/v1/projects/[PROJECT_ID]/global/images
    
    {
       "licenses": ["projects/vm-options/global/licenses/enable-vmx"],
       "name": "nested-vm-image",
       "sourceDisk": "zones/us-central1-b/disks/disk1"
    }

    ここで、[PROJECT_ID] はプロジェクト ID です。

  3. 必要なライセンスを使用してイメージを作成した後、不要になったソースディスクを削除できます。
  4. そのライセンスを含む新しいカスタム イメージを使用して VM インスタンスを作成します。Haswell CPU プラットフォーム以降をサポートするゾーンにインスタンスを作成する必要があります。次に例を示します。
    gcloud compute instances create example-nested-vm --zone us-central1-b \
                  --min-cpu-platform "Intel Haswell" \
                  --image nested-vm-image
  5. ネストされた仮想化が VM で有効になっていることを確認します。
    1. VM インスタンスに接続します。次に例を示します。
      gcloud compute ssh example-nested-vm
    2. 次のコマンドを実行して、ネストされた仮想化が有効になっていることを確認します。ネストされた仮想化が有効であれば、ゼロ以外のレスポンスが返されます。
      grep -cw vmx /proc/cpuinfo

ネストされた VM の起動

ネストされた VM はさまざまな方法で起動できます。このセクションでは、Debian を実行している L1 VM 上で qemu-system-x86_64 を使用してネストされた VM を起動する例を示します。ここで文書化されたプロセス以外の方法を使用して、ネストされた VM を実行する際に問題がある場合は、このプロセスを使用して問題を再現してから、問題をバグとして報告してください。

  1. VM インスタンスに接続します。次に例を示します。

    gcloud compute ssh example-nested-vm
    
  2. VM インスタンスを更新し、必要なパッケージをいくつかインストールします。

    sudo apt-get update && sudo apt-get install qemu-kvm -y
    
  3. OS イメージをダウンロードします。

    wget https://people.debian.org/~aurel32/qemu/amd64/debian_squeeze_amd64_standard.qcow2
    
  4. screen を実行します。

    screen
    
  5. screen ウェルカム プロンプトで Enter キーを押します。

  6. ネストされた VM を起動します。プロンプトが表示されたら、user: rootpassword: root でログインします。

    sudo qemu-system-x86_64 -enable-kvm -hda debian_squeeze_amd64_standard.qcow2 -m 512 -curses
    
  7. VM が外部からアクセスできるかどうかテストします。

    user@nested-vm:~$ wget google.com && cat index.html
  8. 作業が終了したら、Ctrl + a キー、Ctrl + d キーを押して screen セッションから切断します。

ホストとネストされた VM 間のプライベート ブリッジの開始

ホストとネストされた VM 間の接続を有効にするには、プライベート ブリッジを作成します。このサンプル手順は、Debian を実行している L1 VM を対象としています。

  1. VM インスタンスに接続します。次に例を示します。

    gcloud compute ssh example-nested-vm
    
  2. VM インスタンスを更新し、必要なパッケージをいくつかインストールします。

    sudo apt-get update && sudo apt-get install uml-utilities qemu-kvm bridge-utils virtinst libvirt-daemon-system libvirt-clients -y
    
  3. libvirt パッケージに付属しているデフォルト ネットワークを起動します。

    sudo virsh net-start default
    
  4. virbr0 ブリッジがあることを確認します。

    sudo ifconfig -a
    
     eth0      Link encap:Ethernet  HWaddr 42:01:0a:80:00:02
               inet addr:10.128.0.2  Bcast:10.128.0.2  Mask:255.255.255.255
               UP BROADCAST RUNNING MULTICAST  MTU:1460  Metric:1
               RX packets:14799 errors:0 dropped:0 overruns:0 frame:0
               TX packets:9294 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:1000
               RX bytes:97352041 (92.8 MiB)  TX bytes:1483175 (1.4 MiB)
    
     lo        Link encap:Local Loopback
               inet addr:127.0.0.1  Mask:255.0.0.0
               inet6 addr: ::1/128 Scope:Host
               UP LOOPBACK RUNNING  MTU:65536  Metric:1
               RX packets:0 errors:0 dropped:0 overruns:0 frame:0
               TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:0
               RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
    
     virbr0    Link encap:Ethernet  HWaddr 5a:fa:7e:d2:8b:0d
               inet addr:192.168.122.1  Bcast:192.168.122.255  Mask:255.255.255.0
               UP BROADCAST MULTICAST  MTU:1500  Metric:1
               RX packets:0 errors:0 dropped:0 overruns:0 frame:0
               TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:0
               RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)
  5. ホスト VM からネストされた VM に移動するための tun インターフェースを作成します。

    sudo tunctl -t tap0
    sudo ifconfig tap0 up
    
  6. tun インターフェースをブリッジ VM に接続します。

    sudo brctl addif virbr0 tap0
    
  7. ブリッジ ネットワークが正しく設定されていることを再度確認します。

    sudo brctl show
    
    bridge name     bridge id               STP enabled     interfaces
    virbr0          8000.5254005085fe       yes              tap0
  8. OS イメージをダウンロードします。

    wget https://people.debian.org/~aurel32/qemu/amd64/debian_squeeze_amd64_standard.qcow2
    
  9. screen を実行します。

    screen
    
  10. screen ウェルカム プロンプトで Enter キーを押します。

  11. ネストされた VM を起動します。

    sudo qemu-system-x86_64 -enable-kvm -hda debian_squeeze_amd64_standard.qcow2 -m 512 -net nic -net tap,ifname=tap0,script=no -curses
    
  12. プロンプトが表示されたら、user: rootpassword: root でログインします。

  13. ネストされた VM 上で ifconfig を実行し、VM の virbr0 領域に 192.168.122.89 などのアドレスがあることを確認します。

    user@nested-vm:~$ ifconfig
  14. ポート 8000 でダミーのウェブサーバーを起動します。

    user@nested-vm:~$ python -m SimpleHTTPServer
  15. Ctrl + a キー、Ctrl + d キーを押して screen セッションから切断します。

  16. ホスト VM がネストされた VM に対して ping を実行できるかどうかをテストします。

    curl 192.168.122.89:8000
    

    ネストされた VM は、次のような内容を返します。

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
    <title>Directory listing for /</title>
    <body>
    <h2>Directory listing for /</h2>
    <hr>
    <ol>
    <li><a href=".aptitude/">.aptitude/</a>
    <li><a href=".bashrc">.bashrc</a>
    <li><a href=".profile">.profile</a>
    </ol>
    <hr>
    </body>
    </html>
    

ネストされた VM をホスト VM の外部からアクセスできるように構成する

ホスト VM の外部にある VM が、ネストされた VM に対して ping を実行できるように、複数のネットワーク インターフェースでインスタンスを設定するか、エイリアス IP を使用してインスタンスを設定できます。

次のサンプル手順は、エイリアス IP を使用して同じネットワーク上の他の VM からネストされた VM にアクセスできるように、ホストとネストされた VM を設定します。このプロセスでは、以前に作成された subnet1 という名前の架空のサブネットを使用します。subnet1 を独自のサブネット名に置換することも、subnet1 という名前の新しいサブネットを作成することもできます。

最後に、この手順は、Debian を実行している L1 VM を対象としていることに注意してください。

  1. ネストされた仮想化が有効になった VM を作成しますが、必ずエイリアス IP 範囲と HTTP/HTTPS トラフィックのサポートが含まれるようにしてください。次に例を示します。

    gcloud compute instances create example-nested-vm --image nested-vm-image \
        --tags http-server,https-server --can-ip-forward \
        --min-cpu-platform "Intel Haswell" \
        --network-interface subnet=subnet1,aliases=/30
    
  2. VM インスタンスに接続します。次に例を示します。

    gcloud compute ssh example-nested-vm
    
  3. VM インスタンスを更新し、必要なパッケージをいくつかインストールします。

    sudo apt-get update && sudo apt-get install uml-utilities qemu-kvm bridge-utils virtinst libvirt-daemon-system libvirt-clients -y
    
  4. libvirt パッケージに付属しているデフォルト ネットワークを起動します。

    sudo virsh net-start default
    
  5. virbr0 ブリッジがあることを確認します。

    sudo ifconfig -a
     
     eth0      Link encap:Ethernet  HWaddr 42:01:0a:80:00:02
               inet addr:10.128.0.2  Bcast:10.128.0.2  Mask:255.255.255.255
               UP BROADCAST RUNNING MULTICAST  MTU:1460  Metric:1
               RX packets:14799 errors:0 dropped:0 overruns:0 frame:0
               TX packets:9294 errors:0 dropped:0 overruns:0 carrier:0
               collisions:0 txqueuelen:1000
               RX bytes:97352041 (92.8 MiB)  TX bytes:1483175 (1.4 MiB)

    lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

    virbr0 Link encap:Ethernet HWaddr 5a:fa:7e:d2:8b:0d inet addr:192.168.122.1 Bcast:192.168.122.255 Mask:255.255.255.0 UP BROADCAST MULTICAST MTU:1500 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)

  6. ホスト VM からネストされた VM に移動するための tun インターフェースを作成します。

    sudo tunctl -t tap0
    sudo ifconfig tap0 up
    
  7. tun インターフェースをブリッジ VM に接続します。

    sudo brctl addif virbr0 tap0
    
  8. ブリッジ ネットワークが正しく設定されていることを再度確認します。

    sudo brctl show
    
    bridge name     bridge id               STP enabled     interfaces
    virbr0          8000.5254005085fe       yes              tap0
  9. OS イメージをダウンロードします。

    wget https://people.debian.org/~aurel32/qemu/amd64/debian_squeeze_amd64_standard.qcow2
    
  10. screen を実行します。

    screen
    
  11. screen ウェルカム プロンプトで Enter キーを押します。

  12. ネストされた VM を起動します。

    sudo qemu-system-x86_64 -enable-kvm -hda debian_squeeze_amd64_standard.qcow2 -m 512 -net nic -net tap,ifname=tap0,script=no -curses
    
  13. プロンプトが表示されたら、user: rootpassword: root でログインします。

  14. ネストされた VM 上で ifconfig を実行し、VM の virbr0 領域に 192.168.122.89 などのアドレスがあることを確認します。

    user@nested-vm:~$ ifconfig
  15. ポート 8000 でダミーのウェブサーバーを起動します。

    user@nested-vm:~$ python -m SimpleHTTPServer
  16. Ctrl + a キー、Ctrl + d キーを押して screen セッションから切断します。

  17. ホスト VM がネストされた VM に対して ping を実行できるかどうかをテストします。

    curl 192.168.122.89:8000
    

    ネストされた VM は、次のような内容を返します。

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
    <title>Directory listing for /</title>
    <body>
    <h2>Directory listing for /</h2>
    <hr>
    <ol>
    <li><a href=".aptitude/">.aptitude/</a>
    <li><a href=".bashrc">.bashrc</a>
    <li><a href=".profile">.profile</a>
    </ol>
    <hr>
    </body>
    </html>
    
  18. ホスト VM 上で、iptables を設定し、ホスト VM からネストされた VM への転送を許可します。これらの手順で使用される L2 ゲストイメージ(debian_squeeze_amd64_standard.qcow2)については、最初に IP テーブルをフラッシュする必要があります。

    sudo iptables -F
    

    次に、VM のエイリアス IP を調べます。

    ip route show table local
    

    VM が以下のような出力を返すはずです。この例では、VM のイーサネット デバイス eth0 に 2 つの IP アドレスが関連付けられています。1 つは 10.128.0.2 で、sudo ifconfig -a によって返される VM のプライマリ IP アドレスです。もう 1 つは 10.128.0.13 で、VM のエイリアス IP アドレスです。

    local 10.128.0.2 dev eth0 proto kernel scope host src 10.128.0.2
    broadcast 10.128.0.2 dev eth0 proto kernel scope link src 10.128.0.2
    local 10.128.0.13/30 dev eth0 proto 66 scope host
    broadcast 127.0.0.0 dev lo proto kernel scope link src 127.0.0.1
    local 127.0.0.0/8 dev lo proto kernel scope host src 127.0.0.1
    local 127.0.0.1 dev lo proto kernel scope host src 127.0.0.1
    broadcast 127.255.255.255 dev lo proto kernel scope link src 127.0.0.1
    broadcast 192.168.122.0 dev virbr0 proto kernel scope link src
    192.168.122.1 linkdown
    local 192.168.122.1 dev virbr0 proto kernel scope host src 192.168.122.1
    broadcast 192.168.122.255 dev virbr0 proto kernel scope link src
    192.168.122.1 linkdown
    

    エイリアス IP(10.128.0.13)からネストされた VM(192.168.122.89)にトラフィックを転送するには次のコマンドを実行します。

    echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
    sudo iptables -t nat -A PREROUTING -d 10.128.0.13 -j DNAT --to-destination 192.168.122.89
    sudo iptables -t nat -A POSTROUTING -s 192.168.122.89 -j MASQUERADE
    sudo iptables -A INPUT -p udp -j ACCEPT
    sudo iptables -A FORWARD -p tcp -j ACCEPT
    sudo iptables -A OUTPUT -p tcp -j ACCEPT
    sudo iptables -A OUTPUT -p udp -j ACCEPT
    
  19. 次に、ホストされている VM と同じネットワーク上にある別の VM にログインし、エイリアス IP に対して curl リクエストを実行します。次に例を示します。

    user@another-vm:~$ curl 10.128.0.13:8000

    ネストされた VM は、次のような内容を返します。

    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"><html>
    <title>Directory listing for /</title>
    <body>
    <h2>Directory listing for /</h2>
    <hr>
    <ol>
    <li><a href=".aptitude/">.aptitude/</a>
    <li><a href=".bashrc">.bashrc</a>
    <li><a href=".profile">.profile</a>
    </ol>
    <hr>
    </body>
    </html>
    

トラブルシューティング

Google では、Compute Engine インスタンスで特定の Linux ディストリビューションとカーネル /KVM バージョンを使用して、ネストされた仮想化の基本的な起動および統合テストを行います。さらに、これらのテストでは特定のプロセスを使用します。問題をバグとして報告する前に、以下の項目を使用して問題を再現してください。

grep -c vmx /proc/cpuinfo を実行すると、0 が返され、VM でネストが有効になっていないと表示されます。

  1. Haswell 以上の CPU プラットフォームで VM を起動していることを確認してください。
  2. VM イメージで正しいライセンスを使用していることを確認してください。

自分のネストされた VM を終了できません。

それぞれのネストされた VM セッションの前に screen を実行しなかった場合、ネストされた VM をシャットダウンするか、別のデバイスからプロセスを終了できます。ネストされた VM をシャットダウンするには、ネストされた VM 内から poweroff コマンドを実行します。または、新しいネストされた VM を起動する前に、別のデバイスのホスト VM にログインしてプロセスを終了し、ホスト VM 上で screen を実行します。

iptables ルールが、ネストされた VM にトラフィックを転送していません。

  • iptables は、ルールを上から下に解決するので、ご使用のルールの優先順位が他のルールの優先順位よりも高いことを確認します。
  • パケットを妨害するような競合するルールがないことを確認します。
  • iptables をフラッシュすることを検討してください。

    1. まず、デフォルトのポリシーを設定します。

      sudo iptables -P INPUT ACCEPT
      sudo iptables -P FORWARD ACCEPT
      sudo iptables -P OUTPUT ACCEPT
      
    2. 次に、すべてのテーブルとチェーンをフラッシュし、デフォルト以外のチェーンを削除します。

      sudo iptables -t nat -F
      sudo iptables -t mangle -F
      sudo iptables -F
      sudo iptables -X
      
このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...

Compute Engine ドキュメント