仮想マシン・コンテナの概念と利用
コンピューティングの環境では、仮想化を行うために「仮想マシン」と「コンテナ」という技術が使われていますが、その基本技術と違いを解説します。(LinuCレベル1 主題:1.01.2)
仮想化とは、コンピューターをはじめとした種々の物理的なハードウェア環境を抽象化し、ソフトウェア化することです。現在は、コンピューティング、ストレージ、クライアント環境、ネットワークなどが仮想化出来るようになっています。
コンピューティング環境では、仮想化を行うため、「仮想マシン」と、「コンテナ」という技術が使われています。ここでは、それぞれの技術の基本と、違いについて学びます。
目次
コンピューティング環境の仮想化の利点、欠点
一台のサーバーで一つの業務処理を行えば、複数の業務同士が干渉することはありません。しかし、業務の負荷次第では、サーバーのリソースを無駄にしてしまうこともあります。そこで、一台の物理的なサーバー上で複数の論理的な、「仮想の」サーバーを用意し、おのおので業務処理を動かすようにすれば合理的です。そのための技術がコンピューティングにおける仮想化技術です。
コンピューティング環境に仮想化技術を導入すると、以下のようなメリットが得られます。
- 物理的なサーバー台数を削減できる。
- コストと運用管理の負担を軽減できる。
- サーバーの設置面積を節約できる。
- サーバーを迅速に用意できる。
- サーバーを柔軟に増減できる。
- サーバーの利用効率を高められる。
ただし、以下のようなデメリットもあります。
- 処理速度が低下する場合がある。
- 障害発生時の影響範囲が大きくなる場合がある。
- 導入・運用管理の専門知識が必要になる。
仮想マシンとコンテナ
仮想マシンとは
コンピューティングにおける仮想化技術の一つに「仮想マシン」があります。仮想マシンは、物理的なサーバーと同等の機能・動作を再現(エミュレート)した仮想的なハードウェア環境のことです。この機能を実現するのが、「ハイパーバイザー」と呼ばれるソフトウェアです。
ハイパーバイザーは、ハードウェア上で直接動作する「Type1(ネイティブ型)」と、ハードウェアのOS(ホストOS)上で稼働するアプリケーションが仮想マシンを再現する「Type2(ホスト型)」の二種類に分けられます。代表的なものとしては以下があります。
Type1の例:KVM、VMware ESX/ESXi、Microsoft Hyper-V、Citrix Xen Serverなど
Type2の例:VMware Workstation Player、Oracle VM VirtualBox、Microsoft Virtual Serverなど
LinuxではKernel-based Virtual Machine(KVM)がOSの一部として組み込まれています。これは、Linuxカーネルにハイパーバイザーを埋め込んだもので、仮想化機能としてはType1に属します。


仮想マシンには以下のような特徴があります。
- それぞれの仮想マシンには個別にOS(ゲストOS)、ライブラリ(実行環境)、ミドルウェア、アプリケーションをインストールして、独立したコンピューティング環境が構築できます。
- ハードウェアをエミュレートするため、CPUやメモリのリソースを多く消費します。
- 仮想マシンは、ホスト OS とは独立しているため、実行環境が変わっても、そのまま動作させることができます。
- ホストOSとは異なる種類のOSを仮想マシン上で実行することが可能です。
コンテナとは
もう一つの仮想化技術として「コンテナ」があります。これは、物理的なコンピューター上で稼働するOS(ホストOS)のリソースの一部を隔離し、仮想的に作り出された実行環境のことです。昔からある chroot の機能を拡張したものと考えるとわかりやすいでしょう。
代表的なコンテナ技術にDockerがあります。
Dockerはもともと、Linux上で独立した別のLinuxシステムを起動できるコンテナ管理ソフトウェアとして開発されました。ホストOSのカーネルを共有しながら、完全に隔離されたアプリケーション実行環境を構築することができます。
コンテナには以下のような特徴があります。
- ホストOSとは隔離されたプロセスを作成し、その上にライブラリ(実行環境)、ミドルウェア、アプリケーションをインストールして、独立したコンピューティング環境を構築します。
- ホストOSのプロセスとして動作するので、CPUやメモリのリソース消費は少なく、起動するまでの時間がかかりません。
- コンテナ管理ソフトウェアがハードウェアやOSごとの違いを吸収するため、他の実行環境へコンテナを容易に移動・配布できます。
- コンテナ内部で実行されるOS環境はホストOSと同じものに限定されます。

仮想マシンの作成
仮想マシンを実現する技術はいくつかありますが、ここでは、Linux に組み込まれている KVM を使ってみることにします。KVM は、利用するCPUに仮想化支援機能が組み込まれている場合に利用可能です。
※以下のKVMの実行環境については、巻末の「KVMの実行環境に関する注意事項」を参照ください。
KVMのセットアップ
KVM は Linux に組み込まれていますので、KVMの制御に必要なパッケージをインストールすれば、多くのディストリビューションですぐに利用できます。
たとえば、CentOS ではインストール時にベース環境を「サーバー(GUI使用)」、選択した環境のアドオンに「仮想化クライアント」、「仮想化ハイパーバイザー」、「仮想化ツール」を選択すれば、KVM がGUI の操作環境で利用できます。

KVM環境の設定と確認
以下の操作はCentOS7をGUIモードで起動後、デスクトップ上で右クリックから「端末を開く」でコンソール端末を開いて、rootユーザーで操作することを想定しています。


まず、CPUが仮想化支援機能に対応していることを確認します。これには/proc/cpuinfoでCPU情報を確認します。CPUがIntel VT-x/d対応の場合はvmx、AMD-V対応の場合はsvmが表示されます。
egrep '(vmx|svm)' /proc/cpuinfo

また、lsmodでカーネルにkvmのモジュールが読み込まれていることを確認します。
lsmod | grep kvm

rpmコマンドでKVMの実行に必要なパッケージの確認を行います。
必要なパッケージは、qemu-kvm、qemu-img、libvirt、virt-install、virt-manager、virt-viewerです。
rpm -q qemu-kvm qemu-img libvirt virt-install virt-manager virt-viewer

パッケージの確認後、仮想化デーモンのlibvirtdの起動状態を確認します。
systemctl status libvirtd

起動していれば、Active:active(running)と表示されます。
もし起動していない場合は、libvirtdを起動します。
systemctl start libvirtd

次回のLinux起動時にlibvirtdが自動的に起動する設定が有効であることを確認します。
「enabled」と表示が出ればlibvirtdの自動起動が有効になっています。
systemctl is-enabled libvirtd

「disabled」と表示された場合は下記コマンドで有効にします。
systemctl enable libvirtd

ゲストOSのISOイメージをダウンロード
/tmpに移動してCentOS7のMinimalのISOイメージをダウンロードします。
cd /tmp
curl -LO http://ftp.riken.jp/Linux/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2009.iso

ダウンロードできたら確認します。
ls -l CentOS-7-x86_64-Minimal-2009.iso

仮想マシンのイメージファイルの作成
仮想マシンも物理マシンと同様、OSを格納するストレージ領域が必要です。そこで、仮想マシンで使用するストレージのイメージファイルを作成します。容量を10GBとします。
qemu-img create -f qcow2 /var/lib/libvirt/images/centos7.img 10G

作成できたことを確認します。
ls -l /var/lib/libvirt/images/centos7.img

仮想マシンの作成とゲストOSのインストール
仮想マシンを作成し、ISOイメージからCentOS7のインストールを行います。
ゲストOSの仮想マシン設定は下記とします。
- 仮想マシン名 centos7
- CPU数 1
- メモリ 1024MB
- --disk pathで先ほど作成したストレージのイメージファイルを指定します。
- --locationでダウンロードしたCentOS7のISOイメージを指定します。
virt-install --connect=qemu:///system \
--name=centos7 \
--vcpus=1 \
--ram=1024 \
--hvm \
--os-type=linux \
--os-variant=rhel7 \
--virt-type=kvm \
--disk path=/var/lib/libvirt/images/centos7.img \
--location=/tmp/CentOS-7-x86_64-Minimal-2009.iso
(virt-installコマンドを1行で記述すると長くなるので、見やすいように適宜バックスラッシュで改行しています。)

別のウィンドウが開きCentOS7のインストールが開始されます。

「ソフトウェアの選択」はMinimalのISOイメージなので「最小限のインストール」のみです。

その他、「インストール先」と「ネットワークとホスト名」を設定して「インストールの開始」をクリックします。

インストールが完了したら「再起動」をクリックします。

再起動後、ゲストOSにログインしてCentOSのバージョンを確認します。
cat /etc/redhat-release

以上でゲストOSのインストールが完了しました。
仮想マシンの起動・停止のコマンド
KVMでは、virshコマンドを使って仮想マシンを操作します。以下に起動・停止に関する主なコマンドを記します。
※ ドメインとは、CPU、メモリ、仮想ディスク、仮想マシンを実行するネットワークなど一連のリソースを含む仮想マシンの構成を指します。
virsh list --all
定義されているドメインの一覧を表示します。--allオプションは、停止状態および動作中のドメインの一覧を表示します。

virsh start [ドメイン名]
[ドメイン名] の仮想マシンを起動します。

virsh shutdown [ドメイン名]
[ドメイン名] の仮想マシンをシャットダウンします。

virsh reboot [ドメイン名]
[ドメイン名] の仮想マシンを再起動します。

virsh suspend [ドメイン名]
[ドメイン名] の仮想マシンを一時停止します。

[ virsh list ]で、仮想マシンが一時停止中であることを確認できます。

virsh resume [ドメイン名]
一時停止中の [ドメイン名] の仮想マシンを再開します。

virsh destroy [ドメイン名]
[ドメイン名] の仮想マシンを強制停止します。
(物理マシンの電源を切る動作と同様です)

virt-viewer [ドメイン名]
[ドメイン名]で指定した起動中の仮想マシンの操作画面を開きます。

実行すると下記のように仮想マシンの操作画面が開きます。

コンテナの作成
コンテナ管理ソフトウェアとして一般的なDockerを使ってみることにします。
Dockerのセットアップ
以下の手順でDockerをセットアップします。ホストOSはCentOS7を使用します。以下の操作はrootユーザーで操作することを想定しています。
yumコマンドでdockerをインストールします。
yum install docker

rpmコマンドでdockerがインストールされたことを確認します。
rpm -q docker

また、下記のコマンドでdockerのバージョンを確認できます。
docker -v

dockerを起動します。
systemctl start docker

dockerが起動していることを確認します。
systemctl status docker

起動していれば、Active:active(running)と表示されます。
次回のLinux起動時にdockerが自動的に起動するように設定します。
systemctl enable docker

自動起動が有効になったことを確認します。「enabled」と表示が出ればdockerの自動起動が有効になっています。
systemctl is-enabled docker

以上でDockerのセットアップが完了しました。
OSイメージのダウンロードとコンテナの基本操作
コンテナはコンテナ用のOSイメージから作られます。次にDocker公式のリポジトリであるDockerHubからOSイメージをダウンロードします。ここではCentOSの最新版のイメージをダウンロードします。
docker pull centos:latest

取得したコンテナイメージを確認します。
docker images

REPOSITORYに「docker.io/centos」、TAGに「latest」と表示されていればイメージがダウンロードできています。
次に、イメージからコンテナを作成してbashを起動してログインします。
-itオプションで作成したコンテナへのコマンド入力と実行結果の出力ができるようになります。
docker run -it centos:latest /bin/bash

実行後、プロンプトのホスト名がコンテナIDに変化することでコンテナにログインしていることが分かります。
コンテナログイン後、コンテナのOSのバージョンを確認します。
CentOSの最新版のコンテナであることが分かります。
cat /etc/redhat-release

exit
[ exit ]を実行するとコンテナは停止してホストOSに操作が戻ります。

コンテナの起動・停止のコマンド
Dockerでは、dockerコマンドを使ってコンテナを操作します。以下にコンテナの起動・停止に関する主なコマンドを記します。
docker ps
起動中のコンテナ一覧を表示します。

docker ps -a
停止中も含めたコンテナ一覧を表示します。STATUSのExited(0)はコンテナが正常に停止したことを示します。

docker start [コンテナID]
停止中のコンテナを起動します。

[コンテナID]は全コンテナで一意となればよいので始めの2,3文字の入力でも実行可能です。以後のコマンドの[コンテナID]も同様です。

docker ps
で起動したことを確認します。STATUSにUpと表示されます。

docker stop [コンテナID]
起動中のコンテナを停止します。

docker restart [コンテナID]
起動中のコンテナを再起動します。

docker pause [コンテナID]
起動中のコンテナを一時的に停止します。[ docker ps ]のSTATUSはUp(Paused)となります。

docker unpause [コンテナID]
一時的に停止したコンテナを再開します。

docker kill [コンテナID]
起動中のコンテナを強制的に停止します。

強制終了したため[ docker ps -a ]のSTATUSはExited(137)となります。

docker attach [コンテナID]
/bin/bash実行中のコンテナにアタッチ(接続)します。

psコマンドを実行するとPID1で/bin/bashが実行中です。

この状態でexitすると、PID1のbashがexitされてコンテナは停止します。コンテナからデタッチ(切断)してホストOSに操作を切り替えるには、Ctrl+p、Ctrl+qを連続して押します。
すると、プロンプトがホストOSに切り替わります。[ docker ps ]で確認するとコンテナのSTATUSはUpであり、コンテナは起動中であることが分かります。

docker exec -it [コンテナID] /bin/bash
起動中のコンテナで新規にbashを起動してログインします。

psコマンドで確認するとPID1のbashとは別のbashが起動していることが分かります。

この状態でexitするとPID24のbashがexitされるためattachの場合と異なり、コンテナは停止しません。[ docker ps ]で確認するとSTATUSはUpであり、コンテナは起動中であることが分かります。

KVMの実行環境についての注意事項
Linux の仮想化機能である、KVM を学習するために、実機ではなく、WindowsのVMware Workstation PlayerやWindowsやMacのOracle VM VirtualBoxなどの仮想化ソフトウェアを利用される方が多いと思います。この場合、KVMの実行環境を構築する際には注意事項がありますので下記に記載します。
ハードウェアのCPUが仮想化支援機能をサポートしていること
KVMを実行するハードウェアのCPUは、Intelであれば「Intel VT-x」、AMDであれば「AMD-V」と呼ばれる仮想化支援機能をサポートしていることが必要です。この機能はIntelのCore iプロセッサーやAMDのCPUで実装されています。KVMが実行できない場合、仮想化支援機能がBIOSで無効にされている場合がありますので、お持ちのハードウェアのBIOS設定を確認してください。
仮想化ソフトウェアの仮想マシン設定の注意事項
仮想マシンの設定について
仮想化ソフトウェアの仮想マシンの設定は下記以上を推奨します。仮想マシン上にさらにKVMの仮想マシンを作成するので、ホストOSとなる仮想マシンの性能が低いとKVM上の仮想マシンの動作が極端に遅くなりますので、可能な限り下記以上のリソースを割り当ててください。
- CPU数 1
- メモリ 4GB
- ハードディスク 40GB
仮想化ソフトウェア上でCPUの仮想化支援機能を有効化
仮想化ソフトウェア上で、KVMの機能を試す場合、仮想化ソフトウェアのCPU仮想化支援機能が有効になっていないとKVMが動作しません。下記はVMware Workstation PlayerとOracle VM VirtualBoxのCPU仮想化支援機能の有効化設定となります。
VMware Workstation Playerの場合、仮想マシン設定のプロセッサー->仮想化エンジン->
「Intel VT-x/EPTまたはAMD-V/RVIを仮想化」にチェックを入れます。

Oracle VM VirtualBoxの場合、仮想マシン設定のシステム->プロセッサーの「ネステッドVT-x/AMD-Vを有効化」にチェックを入れます。Oracle VM VirtualBox はv6.0.0でAMDのCPUをサポート、v6.1.0以降でIntelの第5世代Core iプロセッサー以降をサポートしています。
※ただし、2020年3月時点の最新版のv6.14でも Intel Core i7第10世代でチェックできませんでした。チェックできない場合はVMware Workstation Playerで環境構築をしてみてださい。

以上で仮想化ソフトウェアの仮想マシン上でCPUの仮想化支援機能が有効となります。
執筆者紹介
・太田 俊哉
・竹本 季史
このドキュメントは、LinuCレベル1の学習用の教材から抜粋して作成されたものです。教材全体は以下のPDFファイルをご覧ください。
LinuCレベル1学習教材