KVMに基づく仮想化に関する一連の記事の続き。 以前の記事では、ツール 、ホストマシンのセットアップ、および仮想マシンの作成について説明しました 。 今日は、仮想マシンイメージの作成とクローン作成について説明します。
この問題に関する調査により、憂鬱な結果が得られました。ネットワーク内の仮想マシンのイメージの作成に関する情報を見つけることは非常に難しく、品質と完全性に違いはありません。
最小限のシステムで仮想マシンのイメージを取得するには、その中のいくつかのファイルを変更するだけで正常に機能するシステムを取得できますが、Debianの場合は若干の難点があります。
既存のシステムに基づいて新しい仮想マシンを作成するには、次の変更を行う必要があります。
- ホスト名を変更する
- ホストファイルを修正
- DNS設定を変更する
- SSHホストキーを置き換えます
- ルートパスワードを変更する
libguestfsライブラリは、私にとって素晴らしい発見であることが判明しました。これにより、対話的に、およびプリコンパイルされたスクリプトに従って、ディスクの管理と仮想マシンファイルの管理が可能になります。
このライブラリは、悪名高いRed Hat社のRichard Jonesによって作成されました。 MSファミリーからゲストオペレーティングシステムをインストールする際に、ファイルシステム(ext2から始まり、WindowsでNTFS、FreeBSDでUFS-一般に、カーネルが動作可能なすべてのファイルシステム)、システムイメージ、LVMパーティションで作業できます。 Windows-レジストリを編集します(hivexライブラリを使用)。 一般に、ユーティリティは非常に機能が豊富で非常に柔軟です。 そして最も重要なことは、それを使用するために管理(ルート)権限を必要としないことです。
画像を探索する
それでは、仕事に取り掛かりましょう。
ゲストシステムのイメージを操作する主なツールはguestfishです。
インタラクティブモードでいくつかの操作を行ってみましょう。
$ guestfish
><fs> add-drive debian_5_i386.img
><fs> run
><fs> list-filesystems
/dev/vda1: ext3
><fs> mount-vfs rw ext3 /dev/vda1 /
><fs> cat /etc/fstab
# /etc/fstab: static file system information.
#
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
/dev/vda1 / ext3 errors=remount-ro 0 1
/dev/hdc /media/cdrom0 udf,iso9660 user,noauto 0 0
これは非常にクールです-必要なすべての操作は、非インタラクティブモードで実行できます(プリコンパイルされたシナリオに従って)。 システム内のホスト、ホスト名、インターフェースファイルを編集するスクリプトの例を示します。
$ guestfish <<EOF
add-drive debian_guest.img
run
mount-vfs rw ext3 /dev/vda1 /
upload -<<END /etc/hosts
127.0.0.1 localhost.localdomain localhost debian_guest.local debian_guest
10.10.10.100 debian_guest.local
END
upload -<<END /etc/resolv.conf
nameserver 8.8.8.8
END
upload -<<END /etc/hostname
debian_guest.local
END
upload -<<END /etc/network/interfaces
auto lo
iface lo inet loopback
allow-hotplug eth0
iface eth0 inet static
address 10.10.10.100
gateway 10.10.10.10
netmask 255.255.255.0
network 10.10.10.0
broadcast 10.10.10.255
END
EOF
このコンテキストでは、 heredocを使用すると非常に便利でした。
(ところで、ライブラリについて質問がある場合、著者自身がirc.freenode.netのIRCチャネル#libguestfsで非常に迅速に回答します。とにかく、この男は非常に興味深いです。)
安全な地獄
名前が示すように、私はかなり長い間この問題に悩まされていました。Debian/ Ubuntuでは、削除されたときの自動キー再生成はまったくありません。 私が使用しようとした他のシステムでは、これで問題ありませんが、debベースのオペレーティングシステムではこれは問題です。
私はこれが好きでした:
$ guestfish
><fs> add-drive debian_guest.img
><fs> run
><fs> mount-vfs rw ext3 /dev/vda1 /
><fs> download /etc/init.d/ssh /home/username/debian_5_etc_init_ssh
次の変更が行われました。
--- /home/username/debian_5_etc_init_ssh 2012-12-21 00:00:00.000000000 +0000
+++ /home/username/debian_5_etc_init_ssh_fixed 2012-12-21 00:00:00.000000000 +0000
@@ -32,6 +32,10 @@
([ "$previous" ] && [ "$runlevel" ]) || [ "$runlevel" = S ]
}
+check_ssh_host_key() {
+ if [ ! -e /etc/ssh/ssh_host_key ] ; then
+ echo "Generating Hostkey..."
+ /usr/bin/ssh-keygen -t rsa1 -f /etc/ssh/ssh_host_key -N '' || return 1
+ fi
+ if [ ! -e /etc/ssh/ssh_host_dsa_key ] ; then
+ echo "Generating DSA-Hostkey..."
+ /usr/bin/ssh-keygen -d -f /etc/ssh/ssh_host_dsa_key -N '' || return 1
+ fi
+ if [ ! -e /etc/ssh/ssh_host_rsa_key ] ; then
+ echo "Generating RSA-Hostkey..."
+ /usr/bin/ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N '' || return 1
+ fi
+}
+
check_for_no_start() {
# forget it if we're trying to start, and /etc/ssh/sshd_not_to_be_run exists
if [ -e /etc/ssh/sshd_not_to_be_run ]; then
@@ -75,6 +79,7 @@
case "$1" in
start)
+ check_ssh_host_key
check_privsep_dir
check_for_no_start
check_dev_null
@@ -106,6 +111,7 @@
;;
restart)
+ check_ssh_host_key
check_privsep_dir
check_config
log_daemon_msg "Restarting OpenBSD Secure Shell server" "sshd"
注意、パッチは機能していません。必要な変更の例として示されています。
また、Debian / Ubuntuの2つのバージョンについて、すでに変更されたsshファイルを使用して同様のファイルを作成しました。 その後、単純に仮想マシンにダウンロードできます。
><fs> upload /home/username/debian_5_etc_init_ssh_fixed /etc/init.d/ssh
キーを削除して、自動的に生成されるようにします。
><fs> glob rm /etc/ssh_host_*_key*
マスクによる削除は機能しません。 このメソッドはAPIに実装されていないため、globプレフィックスを使用すると、マスクをファイルのリストに展開できます。
FreeBSDとCentOSの場合、キーを単に削除するだけで十分で、起動時に生成されます。
ユーザー識別
まず、Linux / FreeBSDでのユーザー情報の保存方法を説明する価値があります。 少し退屈になりますが、まだ何をしているかを理解する必要があります。 少なくとも、シャドウファイルに関する情報だけで十分です。
ユーザー認証に必要なものはすべて、ファイル/ etc / passwdおよび/ etc / shadow(FreeBSDの/etc/master.passwd)に保存されています。
/ etc / passwdファイルの構造を考慮してください
root:x:0:0:root:/root:/bin/bash
wikiからフィールドを使用する順序を引用します。
- 登録名またはログイン
- パスワードハッシュ(現在使用されていない、シャドウに隠されたパスワードが使用されます)
- ユーザーID
- デフォルトのグループID
- GECOS情報フィールド
- 初期(別名)ディレクトリ
- 登録シェル、またはシェル
構造/ etc / shadowを考慮してください
root:$1$APv1HQOB$HJQhYFq9JSnhusQ.1Ql10.:14977:0:99999:7:::
再びwikiから :
- ユーザー名
- パスワードハッシュ
- 最終パスワード変更日
- 何日後にパスワードを変更できるか
- 何日後にパスワードが期限切れになるか
- パスワードの有効期限が切れる何日前に、パスワードを変更するように促し始めます
- パスワードの有効期限が切れてから何日か、ユーザーアカウントをブロックする
- アカウントがブロックされる日付
- 予約フィールド
特に2番目のフィールド(パスワードハッシュ)を変更する必要があります。 次の3つの部分に分けることができます。
- 1-暗号化タイプmd5、2-SHA512(間違っている場合は修正してください)
- APv1HQOB-パスワードを暗号化するソルト
- HJQhYFq9JSnhusQ.1Ql10。 -ソルトを使用したパスワードのハッシュ。
ハッシュはコマンドによって生成されます:
$ mkpasswd --method=md5 --salt="APv1HQOB" "$password"
$1$APv1HQOB$HJQhYFq9JSnhusQ.1Ql10.
ファイル/ etc / shadowで置き換える必要があります。
8文字の長さのランダムなパスワードとソルトを生成し、出力し、ハッシュを生成し、目的のファイルに置き換える小さなスクリプトを作成しました。
#!/bin/bash
tempfile=`mktemp`
shadow="/etc/shadow"
salt=`pwdgen`
passwd=`pwdgen`
hash=`pwhash $salt $password`
hash_esc=`escape_hash $hash `
pwdgen() {
charspool=('a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' '0' '1' '2' '3' '4' '5' '6' '7' '8' '9' '0' 'A' 'B' 'C' 'D' 'E' 'F' 'G' 'H' 'I' 'J' 'K' 'L' 'M' 'N' 'O' 'P' 'Q' 'R' 'S' 'T' 'U' 'V' 'W' 'X' 'Y' 'Z');
len=${#charspool[*]}
for c in $(seq 8); do
echo -n ${charspool[$((RANDOM % len))]}
done
}
pwhash(){
salt=$1
password=$2
hash=`mkpasswd --method=md5 --salt=$salt $password`
echo $hash
}
# , sed $
escape_hash() {
echo $1 | sed -e 's/\//\\\//g' -e 's/\$/\\\$/g'
}
guestfish <<EOF
add-drive debian_guest.img
run
mount-vfs rw ext3 /dev/vda1 /
download /etc/shadow $tempfile
! sed 's/^root:[^:]\+:/root:$hash_esc:/' $tempfile > $tempfile.new
upload $tempfile.new $shadow
EOF
お気づきかもしれませんが、スクリプト内で外部コマンドを使用し、最初のセクションの内容をスクリプトで受け取ったハッシュに置き換えました。 これには外部演算子「 ! 」 が使用されます。guestfishを使用するプロセスを中断せずにいくつかの小さな操作を実行する必要がある場合は非常に便利です ( guestfishの起動にはまだ時間がかかるため)。
マスターイメージの準備
イメージは定期的に更新する必要があるため(イメージの重要な更新またはバグ修正の場合)、必要な操作を実行するマスターイメージを準備する必要があります。 展開のために、個別のスクリプトを使用してこれらのイメージを準備します。
画像から削除する必要があるもの:
- ログを消去
- システムにとどまる痕跡を削除する
- ダウンロードしたパッケージを削除します(DebianとUbuntuに関連します。それらはゴミです)
- ネットワークカードの設定でファイルを削除します
- キーを削除します。
その後、ファイルシステムのサイズを縮小し、パーティションを縮小し、イメージから余分な部分を削除する必要があります。
必要なアクションの最初の部分を実行する小さなコードを添付します。
guestfish <<EOF
add-drive debian_guest.img
run
mount-vfs rw ext3 /dev/vda1 /
upload /home/username/debian_5_etc_init_ssh_fixed /etc/init.d/ssh
-glob rm /etc/ssh/ssh_host_*
-glob rm /etc/udev/rules.d/70-persistent-net.rules
-glob rm /root/*
-glob rm /root/.*
-glob rm /var/log/*
-glob rm /var/cache/apt/archives/*deb
Eof
コマンドの前にある「-」フラグは、いずれかのコマンドが-1を返す場合に終了しないことを意味します。 これは、ファイルがなくても他のコマンドの実行が中断されないように、意図的に行われます。 したがって、さまざまなディストリビューション用にこのスクリプトをカスタマイズする必要はありませんが、可能です。
それでは、画像の縮小を始めましょう。
$ guestfish <<EOF
add-drive add-drive ${images}/${os}_${version}_${arch}.img
run
e2fsck-f /dev/vda1
resize2fs-M /dev/vda1
tune2fs /dev/vda1 | grep "Block count:" | sed -e 's/Block\ count:\ //g' -e 's/$/*4+2144/g' | bc > /tmp/block_count
EOF
$ foo=`cat /tmp/block_count`
$ guestfish <<EOF
allocate debian_guest_minimal.img ${foo}k
EOF
番号2144は、ブートローダーとパーティションテーブルのサイズです。
要するに、これの本質は次のとおりです。ファイルシステムを最小サイズに圧縮し、占有し始めた量(最小ブロック数)を計算し、ブロックサイズが4 KBであるため4を掛けてから、取得した値のイメージを作成します。
その後、 libguestfsユーティリティパッケージのvirt-resizeユーティリティを使用して、結果のファイルシステムを新しい小さなイメージに転送する必要があります。
$ virt-resize --shrink /dev/vda1 debian_guestl.img debian_guest_minimal.img
このメソッドの制限についてすぐに議論する必要があります。これは、resize2fsが動作するのはext2-4ファイルシステムのみです。 非標準のものについては、必要な機能を簡単に完成させることができます(ただし、前述したように 、libguestfsのアセンブルは非常に困難です)。 サンプルについては、 resize2fs-Mを実装するための私のパッチを見ることができます。
残念ながら、FreeBSDでは、すべてがはるかに複雑であり、仮想マシンの構成に別のディスクを追加してマウントする以外、問題の解決策はありません。
もちろん、オプションで、結果の画像をxzでパックする必要があります(これは長い時間ですが、結果には価値があります)。
$ xz -9 debian_guest.img
$ ls -lsha debian_guest.img.xz
107M -rw-r--r-- 1 username username 107M Dec 21 00:00 debian_guest.img.xz
イメージ展開
そのため、仮想マシンのイメージを取得しましたが、イメージは既製の作業システムではありません。 動作するシステムを取得するには、いくつかの操作を実行する必要があります。
- イメージをディスクに割り当てる
- ブートローダーとパーティションテーブルをコピーする
- テンプレートから仮想マシンイメージに情報を転送する
- ファイルシステムを展開する
- ルートパスワードを変更する
- ネットワーク設定を規定する
Linuxの場合、すべてが基本です。libguestfsにはOCamlで書かれた素晴らしいユーティリティがあります-virt -resize 、アイテム2から4は問題なく実行されます。
多くの理由により、「」「guestfish」にディスクサイズ変更を実装することはできません(mbrをguestfishにコピーすることはできません)。したがって、より機能的な手段を使用する必要があります。
$ guestfish <<EOF
allocate debian_guest_clone.img 10G
EOF
$ virt-resize --expand /dev/vda1 debian_guest.img debian_guest_clone.img
実際、仮想マシンイメージのクローン作成を実装するために知っておく必要があるのは、これだけです。
次の記事では、仮想マシンのリソースの制限について説明します。