Linux Install Memo

サーバー管理者によるLinux関連ソフトのインストールメモ

Home » □VineLinuxなゲストOSをKVM上で大量にコピーする

□VineLinuxなゲストOSをKVM上で大量にコピーする

まずはゲストOSのマスターとなるVineLinuxをインストールというか用意します。

virt-install \
–connect qemu:///system \
–name=vinemaster \
–ram=1024 \
–file=/vps/images/vinemaster.img \
–file-size=20 \
–vcpus=2 \
–os-type=linux \
–os-variant=generic26 \
–network bridge=br0 \
–accelerate \
–hvm \
–cdrom=/usr/src/package/Vine61rc1-DVD-x86_64.iso \
–graphics vnc,port=5900,listen=0.0.0.0,keymap=ja,password=hogehoge

で、自分の場合には/vps/以下にゲストOS情報をおいておくので、こんな感じでコピー&シンボリックリンクします。

mv /etc/libvirt/qemu/vinemaster.xml /vps/conf/
ln -s /vps/conf/vinemaster.xml /etc/libvirt/qemu/autostart/vinemaster.xml
ln -s /vps/conf/vinemaster.xml /etc/libvirt/qemu/vinemaster.xml

さらに、要らないCD-ROM情報は消しましょう。:-)

emacs /vps/conf/vinemaster.xml

>     <disk type=’block’ device=’cdrom’>
>       <driver name=’qemu’ type=’raw’/>
>       <target dev=’hdc’ bus=’ide’/>
>       <readonly/>
>       <address type=’drive’ controller=’0′ bus=’1′ unit=’0’/>
>     </disk>

このVineLinuxのマスターを作る際のポイントとしては、

・HDDのパーティションは、LVMを使わないこと(コピーの際に支障が出る)
・固定IPで設定しておく。(仮に192.168.73.200としておく)

で、初期状態のVineLinuxをコピーしてみましょう。

http://www-06.ibm.com/jp/domino01/mkt/cnpages7.nsf/page/default-0004E0BB/

を参考に、virt-cloneでコピーして、かつVineLinuxの設定を書き換える
スクリプトにkvmclone.plを改造してみました。

#!/usr/bin/perl
#
#   kvmclone.pl for RHEL5.x & RHEL6.0 KVM
#   vinecopy.pl for VineLinux6.x KVM T.Kabu/FVG-ON.NET
#
#   2009/12/22 ver1.0
#   2011/02/02 ver1.1 add LANG=C
#   2011/04/23 ver1.2 support for RHEL6.0
#   2012/07/19 ver1.3 support for VineLinux6.1RC1
#

use strict;
use vars qw( $opt_t $opt_o $opt_n $opt_i $opt_m $opt_g $opt_s $opt_h $opt_a $opt_p $opt_w);
use Getopt::Std;

$ENV{'LANG'} = "C";

# --------------------------------
# オプションチェック
# --------------------------------
sub chkopts
{
    # それぞれのオプション取得
    getopts('ahs:t:o:n:i:k:g:b:c:m:p:w:');

    # 一つでもかけているなら、ヘルプ表示モードに
    $opt_h = 1 unless ( $opt_t && $opt_o && $opt_n && $opt_i && $opt_m &&
                        $opt_g && $opt_s && $opt_p && $opt_w );

    # ヘルプ表示
    if ($opt_h)
    {
        print < Exec: $_[ 0 ]\n";
    system($_[ 0 ]);
}

# --------------------------------
# ゲストOSチェック
# --------------------------------
sub chkvm
{
    # もしコピー対象のゲストOSがシャットダウンしていなかったら
    if (system("virsh dominfo $opt_o | grep -E \"^State: +shut off\$\" > /dev/null 2>&1"))
    {
        # シャットダウンしてからにしてね、とメッセージ表示
        print "Domain $opt_o is running, shutdown first.\n\n";
        # 終わり
        exit 1;
    }
}

# --------------------------------
# ゲストOSイメージコピー
# --------------------------------
sub clonfiles
{
    # ローカル変数定義
    my ( $old_mac, $mac, $loopdev, $s );
    my @dpart;
    my $tmpmnt = "/tmp/tmpmnt$$";

    # まずは virt-clone でゲストOSイメージのコピー
    # virt-clone --prompt --original vinemaster --name guest001 --file /vps/images/guest001.img --nonsparse
    # と、こんな感じ
    print( "\nCloning disk image file of $opt_o to $opt_t...\n" );
    log_cmd( "virt-clone --prompt --original $opt_o --name $opt_n --file $opt_t --nonsparse" );

    # 続いて、コピー元のゲストOSの設定ファイルから、MACアドレスを取得
    $_ = `grep \"mac address\" /etc/libvirt/qemu/${opt_o}.xml`;
    $_ =~ m/address=\'(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)\'/; $old_mac = $1;

    # 続いて、新しいゲストOSの設定ファイルから、新規に割り当てられたMACアドレスを取得
    $_ = `grep \"mac address\" /etc/libvirt/qemu/${opt_n}.xml`;
    $_ =~ m/address=\'(\w\w:\w\w:\w\w:\w\w:\w\w:\w\w)\'/; $mac = $1;

    # 新しいゲストOSの設定ファイルを開いて
    open(IN, "< /etc/libvirt/qemu/${opt_n}.xml");     open(OUT, "> /etc/libvirt/qemu/${opt_n}.xml_new");
    # VNCのポート番号を新しいものに書き換え
    while ()
    {
        $_ =~ s/\r\n$/\n/;
        $_ =~ s/type=\'vnc\' port=\'5900\'/type=\'vnc\' port=\'$opt_p\' passwd=\'$opt_w\'/;
        print OUT $_;
    }
    # ファイルを閉じて
    close OUT;
    close IN;
    # ファイルを入れ替え
    log_cmd("mv -f /etc/libvirt/qemu/${opt_n}.xml_new /etc/libvirt/qemu/${opt_n}.xml");
    print "\nNew XML config file....\n";
    print "---------------------------\n";
    system("cat /etc/libvirt/qemu/${opt_n}.xml");
    print "---------------------------\n";

    # 新しいゲストOSイメージをマウントして、設定を書き換えちゃいます
    print "\nModifying network information in the new disk image...\n\n";
    print "Now trying to find root partition...\n";
    # ループバックデバイスを検索
    $loopdev = `losetup -f`; chomp $loopdev;
    # 新しいゲストOSイメージにリンク
    log_cmd("losetup $loopdev $opt_t");
    # ゲストOSイメージのパーティション情報を取得
    $s = `kpartx -av $loopdev`; @dpart = split( /\n/, $s );

    # 作業用ディレクトリを作成
    log_cmd("mkdir -p $tmpmnt");
    # 先ほど取得したパーティションごとにマウントして、/etc/sysconfigを探す
    foreach $s ( @dpart )
    {
        # パーティション名を取得
        $s = $1 if ($s =~ m/add map (\w+) /);
        # そのパーティション(シンボリックリンク)が正常になるまで待つ 2013.10.07 T.Kabu
        while( !(-l "/dev/mapper/$s") ) {};
        # そのパーティションをマウント
        log_cmd("mount -t ext4 /dev/mapper/$s $tmpmnt");
        # マウントしたパーティションに /etc/sysconfig があるなら
        if (-d "$tmpmnt/etc/sysconfig")
        {
            # 見つけた!!
            print "\nFound root partition on $s\n";
            # 実際の書き換え処理に行く
            goto OUT;
        }
        # ないなら
        else
        {
            # アンマウントして次に行く
            log_cmd("umount $tmpmnt");
        }
    }

    # 見つからなかったらループバックデバイスと作業用ディレクトリを掃除して終わり
    print "Failed to find root partition.\n";
    log_cmd("kpartx -d $loopdev; losetup -d $loopdev; rmdir $tmpmnt");
    exit 1;

# 実際の書き換え処理はここから
OUT:
    # もし /etc/udev/rules.d/70-persistent-net.rules があるなら
    if (-f "$tmpmnt/etc/udev/rules.d/70-persistent-net.rules")
    {
        # /etc/udev/rules.d/70-persistent-net.rulesファイルを開いて
        open(IN, "< $tmpmnt/etc/udev/rules.d/70-persistent-net.rules");         open(OUT, "> $tmpmnt/etc/udev/rules.d/70-persistent-net.rules_new");
        # MACアドレスを新しいものに書き換え
        while ()
        {
            $_ =~ s/\r\n$/\n/;
            $_ =~ s/==\"$old_mac\"/==\"$mac\"/;
            print OUT $_;
        }
        # ファイルを閉じて
        close OUT;
        close IN;
        # ファイルを入れ替え
        log_cmd("mv -f $tmpmnt/etc/udev/rules.d/70-persistent-net.rules_new $tmpmnt/etc/udev/rules.d/70-persistent-net.rules");
        print "\nNew mac address in udev file....\n";
        print "---------------------------\n";
        system("grep \"address\" $tmpmnt/etc/udev/rules.d/70-persistent-net.rules");
        print "---------------------------\n";
    }

    # /etc/sysconfig/network を開いて
    open(IN, "< $tmpmnt/etc/sysconfig/network");     open(OUT, "> $tmpmnt/etc/sysconfig/network_new");
    # MACアドレスを新しいものに書き換え
    while ()
    {
        $_ =~ s/\r\n$/\n/;
        $_ =~ s/HOSTNAME\s*=\s*[\"\w-]+/HOSTNAME=$opt_s/;
        $_ =~ s/GATEWAY\s*=\s*[\"\d\.]+/GATEWAY=$opt_g/;
        print OUT $_;
    }
    # ファイルを閉じて
    close OUT;
    close IN;
    # ファイルを入れ替え
    log_cmd("mv -f $tmpmnt/etc/sysconfig/network_new $tmpmnt/etc/sysconfig/network");
    print "\nNew network config file....\n";
    print "---------------------------\n";
    system("cat $tmpmnt/etc/sysconfig/network");
    print "---------------------------\n";

    # /etc/sysconfig/network-scripts/ifcfg-eth0 を開いて
    open(IN, "< $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0" );     open(OUT, "> $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0_new");
    # MACアドレスとか色々と新しいものに書き換え
    while ()
    {
        $_ =~ s/\r\n$/\n/;
        $_ =~ s/HWADDR\s*=\s*[\"\w:]+/HWADDR=$mac/;
        $_ =~ s/IPADDR\s*=\s*[\"\d\.]+/IPADDR=$opt_i/;
        $_ =~ s/NETMASK\s*=\s*[\"\d\.]+/NETMASK=$opt_m/;
        $_ =~ s/GATEWAY\s*=\s*[\"\d\.]+/GATEWAY=$opt_g/;
        print OUT $_;
    }
    # ファイルを閉じて
    close OUT;
    close IN;
    # ファイルを入れ替え
    log_cmd("mv -f $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0_new $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0");
    print "\nNew interface eth0 config file....\n";
    print "---------------------------\n";
    system("cat $tmpmnt/etc/sysconfig/network-scripts/ifcfg-eth0");
    print "---------------------------\n";

    # パーティションをアンマウントして
    log_cmd("umount $tmpmnt");
    # あとを掃除
    log_cmd("kpartx -d $loopdev; losetup -d $loopdev; rmdir $tmpmnt");
}

# --------------------------------
# MAIN
# --------------------------------
# ----------------
# オプションチェック
# ----------------
chkopts();

# ----------------
# ゲストOSチェック
# ----------------
chkvm();

# ----------------
# ゲストOSイメージコピー
# ----------------
clonfiles();

# もし新しいゲストOSの起動オプションがついていたら
if ($opt_a)
{
    print "\nActivate new vm $opt_n\n";
    log_cmd ( "virsh start $opt_n" );
}

print "Done.\n";

exit 0;

 

というスクリプトで大量コピーできます。笑

では試しにやって見ましょう。

・ゲストOS名は、guest001
・ゲストOSイメージは、/vps/images/guest001.img に置く
・ホスト名も、guest001
・IPアドレスは、192.168.73.201
・ネットマスクは、255.255.255.0
・ゲートウェイは、192.168.73.1
・VNCポート番号は、5901
・VNCの際のパスワードは、svrkcho001

と言う条件でコピーします。

./vinecopy.pl \
  -o vinemaster \
  -n guest001 \
  -t /vps/images/guest001.img \
  -s guest001 \
  -i 192.168.73.201 \
  -m 255.255.255.0 \
  -g 192.168.73.1 \
  -p 5901 \
  -w svrkcho001

として実行して複製を作ったあとで、マスター同様に/vps/以下に設定ファイルも置きたいので、マスターと同様に

mv /etc/libvirt/qemu/guest001.xml /vps/conf/
ln -s /vps/conf/guest001.xml /etc/libvirt/qemu/autostart/guest001.xml
ln -s /vps/conf/guest001.xml /etc/libvirt/qemu/guest001.xml

としました。
ちなみに./vinecopy.plの実行結果はこんな感じ。

>
> Cloning disk image file of vinemaster to /vps/images/guest001.img…
> ===> Exec: virt-clone –prompt –original vinemaster –name guest001 –file /vps/images/guest001.img –nonsparse
> Cloning vinemaster.img                                                                                         |  20 GB     00:59
>
> Clone ‘guest001′ created successfully.
> ===> Exec: mv -f /etc/libvirt/qemu/guest001.xml_new /etc/libvirt/qemu/guest001.xml
>
> New XML config file….
> —————————
> <!–
> WARNING: THIS IS AN AUTO-GENERATED FILE. CHANGES TO IT ARE LIKELY TO BE
> OVERWRITTEN AND LOST. Changes to this xml configuration should be made using:
>   virsh edit guest001
> or other application using the libvirt API.
> –>
>
> <domain type=’kvm’>
>   <name>guest001</name>
> (長いんで途中省略)
> </domain>
> —————————
>
> Modifying network information in the new disk image…
>
> Now trying to find root partition…
> ===> Exec: losetup /dev/loop0 /vps/images/guest001.img
> ===> Exec: mkdir -p /tmp/tmpmnt5715
> ===> Exec: mount -t ext4 /dev/mapper/loop0p1 /tmp/tmpmnt5715
> ===> Exec: umount /tmp/tmpmnt5715
> ===> Exec: mount -t ext4 /dev/mapper/loop0p2 /tmp/tmpmnt5715
>
> Found root partition on loop0p2
> ===> Exec: mv -f /tmp/tmpmnt5715/etc/udev/rules.d/70-persistent-net.rules_new /tmp/tmpmnt5715/etc/udev/rules.d/70-persistent-net.rules
>
> New mac address in udev file….
> —————————
> SUBSYSTEM==”net”, ACTION==”add”, DRIVERS==”?*”, ATTR{address}==”00:16:3e:9a:5c:d8″, ATTR{type}==”1″, KERNEL==”eth*”, NAME=”eth0″
> —————————
> ===> Exec: mv -f /tmp/tmpmnt5715/etc/sysconfig/network_new /tmp/tmpmnt5715/etc/sysconfig/network
>
> New network config file….
> —————————
> NETWORKING=yes
> HOSTNAME=guest001.fvg-on.net
> GATEWAY=192.168.73.1
> —————————
> ===> Exec: mv -f /tmp/tmpmnt5715/etc/sysconfig/network-scripts/ifcfg-eth0_new /tmp/tmpmnt5715/etc/sysconfig/network-scripts/ifcfg-eth0
>
> New interface eth0 config file….
> —————————
> # Realtek Semiconductor Co., Ltd. RTL-8139/8139C/8139C+
> DEVICE=eth0
> BOOTPROTO=static
> BROADCAST=192.168.73.255
> HWADDR=00:16:3e:9a:5c:d8
> IPADDR=192.168.73.201
> NETMASK=255.255.255.0
> NETWORK=192.168.73.0
> ONBOOT=yes
> TYPE=Ethernet
> DNS1=210.197.72.20
> DNS2=210.197.72.21
> DNS3=210.197.72.22
> NM_CONTROLLED=yes
> —————————
> ===> Exec: umount /tmp/tmpmnt5715
> ===> Exec: kpartx -d /dev/loop0; losetup -d /dev/loop0; rmdir /tmp/tmpmnt5715
> Done.

あとは virtsh create /vps/conf/guest001.xml

とすれば立ち上がるはずですので、VNCでみてたりping打ったりしましょう。

ちなみにIPアドレスとMACアドレスでのフィルターについては書いてありませんが、まぁ追加するだけですからそれも自動化するとラクですね。:-)

 

Name of author

Name: admin

One thought on “□VineLinuxなゲストOSをKVM上で大量にコピーする

  • ホスト側のCentOSをyum updateしたら、mountがすんなり出来ず?にスクリプトを使ってもうまくコピーが出来なくなりました。さらに、マウントしたとしてもシンボリックリンクの生成に時間が係る場合がありましたので、スクリプトに修正をかけました。

コメントを残す

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