KVM virt-cloneによる仮想マシンの複製 – その2


こんにちは、ADN事業部のt_oookaです。

前回は、virt-installコマンドで仮想マシンを作成し、virt-cloneコマンドにて
仮想マシンの複製を行う方法について記載しました。

今回は、複製する操作をもう少し効率化する方法について触れてみたいと
思います。

libguestfs」を使用する

virt-cloneコマンドにより複製を実行する都度、複製を行った仮想マシンへ
コンソール接続を行うのは、複製する仮想マシンが多くなるとちょっとした
作業になるので、この部分の効率化を行います。

libguestfs」パッケージのインストール

# yum install libguestfs libguestfs-tools libguestfs-tools-c

「virt-edit」で複製した仮想マシンの設定を直接変更する

最初に、前回と同様に「virt-clone」コマンドにより仮想マシンの複製を
行います。

複製元のゲストを「centos63」、複製するゲストを「guest02」とします。

# virt-clone --original centos63 --name guest02 --file /var/lib/libvirt/images/guest02
Allocating 'guest02' | 5.0 GB 00:26

Clone 'guest02' created successfully.

※ この時点では、複製を行った「guest02」は起動させず、停止状態にしておきます。

# virsh list --all
Id Name State
----------------------------------------------------
- centos63 shut off
- guest01 shut off
- guest02 shut off

「virt-clone」コマンド実行後、複製を行ったゲストに対して変更を行う
ファイルは、今回の場合は以下の通りです。

  • /etc/hosts
  • /etc/sysconfig/network
  • /etc/sysconfig/network-scripts/ifcfg-eth0
  • /etc/udev/rules.d/70-persistent-net.rules

前回は、複製を行ったゲストを起動し、コンソール接続を行い
上記の設定ファイルの変更を行いました。
今回は、ホスト側から複製を行ったゲストの設定を直接変更を
行うため、複製を行ったゲストの起動及びゲストへのコンソール
接続は行いません。

ホスト名の変更

まずは、複製を行ったゲスト(guest02)の/etc/hostsを編集します。

# virt-edit -d guest02 /etc/hosts

「d」オプションで対象のゲストを指定し、続く引数で編集を行うファイルのパスを
指定します。

・編集前

127.0.0.1 centos63.example.com localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 centos63.example.com localhost localhost.localdomain localhost6 localhost6.localdomain6

・編集後

127.0.0.1 guest02.example.com localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 guest02.example.com localhost localhost.localdomain localhost6 localhost6.localdomain6

編集を保存後、一応編集後のファイルの内容を確認しておきます。
「virt-cat」コマンドを使用します。

# virt-cat -d guest02 /etc/hosts

※ 上記の「編集後」の内容が表示されることを確認します。

続いて、/etc/sysconfig/networkを編集します。

# virt-edit -d guest02 /etc/sysconfig/network

・編集前

NETWORKING=yes
HOSTNAME=centos63.example.com

・編集後

NETWORKING=yes
HOSTNAME=guest02.example.com

ネットワーク設定の変更

ホスト名の変更と同様に「virt-edit」コマンドを使用してファイルの編集を行えばよいのですが、
ネットワーク設定の場合は、複製を行ったゲストのインタフェースのMACアドレスを事前に確認
しておく必要があります。
※ virt-cloneコマンドにてMACアドレスを指定した場合は不要です。

# virsh domiflist guest02
Interface Type Source Model MAC
-------------------------------------------------------
- bridge virbr0 virtio '52:54:00:ca:17:e2'

MAC欄に表示された値が複製を行ったゲスト(guest02)のインタフェースのMACアドレスと
なります。

一応、複製元のMACアドレスも確認しておきます。

# virsh domiflist centos63
Interface Type Source Model MAC
-------------------------------------------------------
- bridge virbr0 virtio '52:54:00:3e:43:37'

また、uuidもあらかじめ「uuidgen」コマンドで準備しておきます。

# uuidgen
b6c7e5d8-a3f1-4d8d-b7b9-1daddfe4ba80

MACアドレスの確認及びuuidの準備が行えたため、複製を行ったゲスト(guest02)の
ネットワーク設定を変更していきます。

# virt-edit -d guest02 /etc/sysconfig/network-scripts/ifcfg-eth0

・編集前

DEVICE="eth0"
BOOTPROTO="static"
HWADDR="52:54:00:3E:43:37"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
UUID="35000132-d23b-48fe-a06e-59ba9b692690"
IPADDR=192.168.122.2
NETMASK=255.255.255.0

・編集後

DEVICE="eth0"
BOOTPROTO="static"
HWADDR="52:54:00:ca:17:e2"
NM_CONTROLLED="no"
ONBOOT="yes"
TYPE="Ethernet"
UUID="b6c7e5d8-a3f1-4d8d-b7b9-1daddfe4ba80"
IPADDR=192.168.122.3
NETMASK=255.255.255.0

HWADDRを上記で確認したMACアドレスへ変更します。
また、UUIDも上記で生成したuuidに変更します。
IPアドレスとして「192.168.122.3」をアサインします。

同様に/etc/udev/rules.d/70-persistent-net.rulesも編集します。

# virt-edit -d guest02 /etc/udev/rules.d/70-persistent-net.rules

・編集前

# This file was automatically generated by the /lib/udev/write_net_rules
# program, run by the persistent-net-generator.rules rules file.
#
# You can modify it, as long as you keep each rule on a single
# line, and change only the value of the NAME= key.

# PCI device 0x1af4:0x1000 (virtio-pci)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="52:54:00:3e:43:37", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

・編集後

# This file was automatically generated by the /lib/udev/write_net_rules
# program, run by the persistent-net-generator.rules rules file.
#
# You can modify it, as long as you keep each rule on a single
# line, and change only the value of the NAME= key.

# PCI device 0x1af4:0x1000 (virtio-pci)
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="52:54:00:ca:17:e2", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

ATTR{address}==”"を上記で確認したMACアドレスへ変更します。

複製したゲストの動作確認

複製したゲスト(guest02)を起動します。

# virsh start guest02

複製したゲストの状態を確認します。

# virsh list --all
 Id    Name                           State
----------------------------------------------------
 47    guest_02                       running
 -     centos63                       shut off
 -     guest01                        shut off

複製したゲスト(guest02)へコンソール接続します。

# virsh console guest02
Connected to domain guest02
Escape character is ^]

CentOS release 6.3 (Final)
Kernel 2.6.32-279.19.1.el6.x86_64 on an x86_64

guest02.example.com login:

※ 以降は、ゲストでの操作となります。

ホスト名の確認

# hostname
guest02.example.com

ネットワーク設定の確認

# ifconfig

スクリプトによる仮想マシン複製の自動化

上記までで、複製の操作自体はホスト側で行えるように
なりました。

ゲスト側での操作がなくなり、ある程度効率化できたように
思います。

とはいえ、やはり最終的にはスクリプトで。。。
ということで、自動化してみます。

コピー元は、テンプレート用途の「centos63」とします。
前回、IPアドレスとして「192.168.122.2」をアサインして
いますので、その前提でスクリプトを作成しています。

・clone-guest.sh

#!/bin/sh

work_dir=/tmp/clone-guest

cmd_awk=/bin/awk
cmd_cat=/bin/cat
cmd_cut=/bin/cut
cmd_grep=/bin/grep
cmd_mkdir=/bin/mkdir
cmd_sed=/bin/sed
cmd_uuidgen=/usr/bin/uuidgen
cmd_virsh=/usr/bin/virsh
cmd_virt_cat=/usr/bin/virt-cat
cmd_virt_clone=/usr/bin/virt-clone
cmd_virt_copy_in=/usr/bin/virt-copy-in

original_domain_name=centos63
original_fqdn=${original_domain_name}.example.com
original_ipaddr=192.168.122.2
source_bridge=virbr0
clone_domain_name=$1
clone_fqdn=${clone_domain_name}.example.com
clone_ipaddr=$2

domain_image_dir=/var/lib/libvirt/images
clone_domain_image_path=$domain_image_dir/$clone_domain_name

# --------------------------------------------------
# pre process.
# --------------------------------------------------

if [ "$clone_domain_name" = "" -o "$clone_ipaddr" = "" ] ; then
echo "Usage clone-guest.sh <domain_name> <ipaddr>"
exit 0
fi

[ ! -e $work_dir ] && $cmd_mkdir -p $work_dir

# --------------------------------------------------
# main process.
# --------------------------------------------------
$cmd_virt_clone                                               \
  --original $original_domain_name                            \
  --name $clone_domain_name                                   \
  --file $clone_domain_image_path

# ----- /etc/hosts -----
$cmd_virt_cat -d $original_domain_name /etc/hosts             \
  > $work_dir/hosts.org
$cmd_cat $work_dir/hosts.org                                  \
  | $cmd_sed "s/$original_fqdn/$clone_fqdn/"                  \
  > $work_dir/hosts
$cmd_virt_copy_in -d $clone_domain_name $work_dir/hosts /etc/

# ----- /etc/sysconfig/network ------
$cmd_virt_cat -d $original_domain_name /etc/sysconfig/network \
  > $work_dir/network.org
$cmd_cat $work_dir/network.org                                \
  | $cmd_sed "s/$original_fqdn/$clone_fqdn/"                  \
  > $work_dir/network

# ----- /etc/sysconfig/network-scripts/ifcfg-eth0 ------
original_mac_addr=$(                                          \
$cmd_virsh domiflist $original_domain_name                    \
| $cmd_grep $source_bridge                                    \
| $cmd_awk '{print $5}'                                       \
)
clone_mac_addr=$(                                             \
$cmd_virsh domiflist $clone_domain_name                       \
| $cmd_grep $source_bridge                                    \
| $cmd_awk '{print $5}'                                       \
)

original_nic_uuid=$(                                          \
$cmd_cat $work_dir/ifcfg-eth0.org                             \
| $cmd_grep -i uuid                                           \
| $cmd_cut -d'=' -f2                                          \
| $cmd_sed 's/"//g'                                           \
)
clone_nic_uuid=$($cmd_uuidgen)

$cmd_virt_cat -d $original_domain_name                        \
  /etc/sysconfig/network-scripts/ifcfg-eth0                   \
  > $work_dir/ifcfg-eth0.org
$cmd_cat $work_dir/ifcfg-eth0.org                             \
| $cmd_sed -e "s/$original_mac_addr/$clone_mac_addr/i"        \
-e "s/$original_nic_uuid/$clone_nic_uuid/i"                   \
-e "s/$original_ipaddr/$clone_ipaddr/i"                       \
> $work_dir/ifcfg-eth0
$cmd_virt_copy_in -d $clone_domain_name                       \
  $work_dir/ifcfg-eth0                                        \
  /etc/sysconfig/network-scripts/

# ----- /etc/udev/rules.d/70-persistent-net.rules -----
$cmd_virt_cat -d $original_domain_name                        \
  /etc/udev/rules.d/70-persistent-net.rules                   \
  > $work_dir/70-persistent-net.rules.org
$cmd_cat $work_dir/70-persistent-net.rules.org                \
  | $cmd_sed "s/$original_mac_addr/$clone_mac_addr/i"         \
  > $work_dir/70-persistent-net.rules
$cmd_virt_copy_in -d $clone_domain_name                       \
  $work_dir/70-persistent-net.rules                           \
  /etc/udev/rules.d/

使用方法は、以下の通りです。

# /bin/sh clone-guest.sh <domain_name> <ipaddr>

ドメイン名「guest03」とし、IPアドレス「192.168.122.4」をアサインする場合は、

# /bin/sh clone-guest.sh guest03 192.168.122.4

となります。

libguestfs」には、今回触れた以外にもコマンドが含まれていますので、
関心のある方はその他のコマンドにも触れてみてください。

上記のスクリプトではかなり制限があるのも事実ですので、より多くのケースに
対応できる自動化のスクリプトを作成することができると思います。

Add a Comment

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


*