Vine Linux Magazine
ループバックマウントとchrootで作るなんちゃって仮想マシン
1台のPCで複数のOSを使い分けるソリューションとして、KVM や VMWare, VirtualBoxのような仮想マシンは今や常識となっています。 しかし、Linuxの上で別のLinux環境を実現するのであればchrootを使っても簡易仮想マシンの様な環境を作ることができます。 Vine Linuxでは、vbootstrap (Vine Linux の基本システムを作成するためのスクリプト)や debootstrap (Debian GNU/Linux bootstrapper)、rinse (Fedora や CentOS 等の chroot 環境を構築するツール)などの便利なパッケージが用意されており、容易に他ディストリビューションをVine Linuxの上で飼うことができます。 ですがここでは、既存のOSがインストール済みのディスクをそのまま活かして、Vine Linux 5.2の上にchrootを使ったなんちゃって仮想マシンのLinux環境を実現する方法を紹介していきます。
- ディスクのイメージをループバックマウントする方法
- dd でダンプしたディスクのイメージをマウントする
- VMWare の VMDK ファイル形式ディスクをマウントする
- chrootを使ったなんちゃって仮想マシン環境を構築する方法
chrootとVMWare Playerのベンチマーク比較
本題に入る前にまず、chrootを使った場合のパフォーマンス面での利点をみていきます。
chrootの中のプロセスはホストのkernel上で直接実行されます。そのため、VMWare Playerを初めとする仮想マシン環境と較べると次のようなメリットがあります。
- パフォーマンス・ペナルティがない
- VMWareの上限である8CPU以上のSMP環境が使える
ここでは、試しにVine Linux 5.2 (x86 32bit) をインストールしたPC上にVMWare Playerをインストールして、VMWare Player上のVine Linux 4.2 (i386) と、chrootの上に構築した Vine Linux 4.2 (i386) の環境での性能を比較してみました。
VMWare Player と chroot 環境でベンチマーク比較:BeeCrypt Benchmark
まずベンチマークプログラムにBeeCrypt Benchmarkを使って、次のそれぞれの環境で性能を比較してみました。
- VMWare
- Vine Linux 5.2にインストールしたVMWare Player 3.1.3上のVine Linux 4.2環境で実行
- chroot
- Vine Linux 5.2の上でchrootを使って構築したVine Linux 4.2環境で実行
- 5.2 native
- Vine Linux 5.2の上でそのまま実行
総じてchroot上でのベンチマーク結果はVMWare Playerよりも高速で、Vine Linux 5.2の上での実行結果と遜色がないパフォーマンスを示しています。BeeCryptのベンチマークは演算が中心となっており、ディスクやメモリアクセスの性能差がでにくい傾向にあるのですが、それでも約 5%程度の差が出ました。
VMWare Player と chroot 環境でベンチマーク比較:カーネルビルド
先ほどと同じくVMWare Player上の Vine Linux 4.2環境と、Vine Linux 5.2のchroot上に構築したVine Linux 4.2環境で、それぞれカーネルビルドに掛かった時間を比較した結果が次のグラフです。
積み重ねグラフはsysとuser時間を、折れ線グラフはreal時間を表しており、4コアのマシン上でビルドしていたためにsysとuser時間の合計よりもreal時間が大幅に短くなるケースが見られます。なお、それぞれ 6回実行しています。特にreal時間にはばらつきが大きいのでどちらが高速かを一概には言えない面もありますが、全体的にchroot環境の方がsys時間が短く、高速であることが見て取れます。
このように、chroot上で構築したなんちゃって仮想マシンはパフォーマンスの面では一般的な仮想マシンより優位性があるとわかると思います。
事例 1:古い Vine Linux 4.2 の環境を Vine Linux 5.2 にお引っ越し
Vine Linux 5.2をお使いの方が多いと思います。 しかし、どうしても以前使っていたVine Linux 4.2の環境で使っていた特定のアプリケーションがVine Linux 5.2で使えないからなかなか移行できないという方もおられるかと思います。 また、メインではVine Linux 5.2を使っているけど、一部の商用アプリケーションを使用するために別にRed Had ELやSLESのマシンを用意している方もおられるかもしれません。 ここでは、仮想マシンを使用することなくVine Linux 5.2の上で既存のVine Linux 4.2の実行環境を構築する方法を紹介します。
次の手順で進めていきます。
- 古いマシンのディスクをVine Linux 5.2上にマウントしてアクセスできるようにする
- chrootコマンドを使って、古いマシンのディスクを"/"としてアクセスできるようにする
- 一般ユーザーがsshでリモート接続できる設定
dd したディスクイメージをループバックマウント
まず、旧マシンのディスクをVine Linux 5.2の環境からアクセスできるようにしておきます。 ここでは、古いマシンのディスクが /dev/hdX に繋がっているものと想定しています。
# dd if=/dev/hdX of=/opt/Vine42.dd.img
とddコマンドを使って、ディスクのイメージを丸ごとファイルにダンプし、この以前のディスクの環境をVine Linux 5.2の上で使えるようにします。 なお、ここではいくつかのコマンドを説明する目的もあるため、若干無駄な操作も入っています。 「初めからルートパーティションだけddすればいいじゃん」などといった野暮なつっこみは厳に御容赦願います。。。
でも、このままループバックマウントのオプション"-o loop"を使ってディスクのイメージをマウントすることはできません。
# mkdir /opt/Vine42 # mount -o loop /opt/Vine42.dd.img /opt/Vine42 mount: ファイルシステムタイプを指定する必要があります
ここでは、パーティションの情報を確認し、オフセットを指定しながらディスクのイメージをループバックマウントします。
# fdisk -lu /opt/Vine42.dd.img 設定する必要があります シリンダ数. あなたは特別機能メニューからこれを行なうことができます Disk /opt/Vine42.dd.img: 0 MB, 0 bytes 255 heads, 63 sectors/track, 0 cylinders, total 0 sectors Units = セクタ数 of 1 * 512 = 512 bytes Disk identifier: 0x000a0970 デバイス Boot Start End Blocks Id System /opt/Vine42.dd.img1 * 63 208844 104391 83 Linux /opt/Vine42.dd.img2 208845 15727634 7759395 83 Linux /opt/Vine42.dd.img3 15727635 16771859 522112+ 82 Linux swap / Solaris 領域 3 は異なった物理/論理終点になっています: 物理=(1023, 254, 63) 論理=(1043, 254, 63)
Startセクタ * 512バイト目がパーティションの始まりになるので、1番目のパーティションは 63*512 = 32,256バイト目からのオフセットを指定することでマウントできます。
# mkdir /opt/Vine42 # mount -o loop,offset=`expr 63 \* 512` /opt/Vine42.dd.img /opt/Vine42 $ ls /opt/Vine42/ System.map@ initrd-2.6.16-0vl76.27.img vmlinuz@ System.map-2.6.16-0vl76.27 initrd.img@ vmlinuz-2.6.16-0vl76.27 System.map.old@ initrd.old.img@ vmlinuz.old@ config-2.6.16-0vl76.27 kernel.h grub/ lost+found/
こっちは /boot パーティションですね。 一旦アンマウントして、/ に対応する 2番目のセクタをマウント。 ついでに、必要はありませんが/bootもマウントします。
# umount /opt/Vine42 # umount /opt/Vine42 # mount -o loop,offset=`expr 208845 \* 512` /opt/Vine42.dd.img /opt/Vine42 # mount -o loop,offset=`expr 63 \* 512` /opt/Vine42.dd.img /opt/Vine42/boot $ df ファイルシステム 1K-ブロック 使用 空き 使用% マウント位置 /dev/sda3 38456340 26437676 10065160 73% / none 2021060 0 2021060 0% /dev/shm /dev/loop0 7637400 1928112 5321320 27% /opt/Vine42 /dev/loop1 101086 8908 86959 10% /opt/Vine42/boot
これで Vine Linux 4.2 のディスクを Vine Linux 5.2 からアクセスできるようになりました。
ちなみに、ここでは従来環境のディスクをdd でディスクイメージのファイルに落としていましたが、ディスクをそのまま mount しても同じことは可能です。 この場合は、古いディスクを繋ぐ前にあらかじめ e2label コマンドで "/" や "/boot" といったラベルを消しておきましょう。
# e2label /dev/hda1 "" # e2label /dev/hda2 ""
そうしなければ、古いVine Linux 4.2のディスクを繋いだときに、そっちが "/" となって起動することがあります。 grubがVine Linux 5.2のカーネルをロードしたのに、"/"としてVine Linux 4.2のディスクが参照され、大量のワーニングを吐きながらVine Linux 4.2が起動する姿を見るとやるせない気分になります。
chrootを使って / のパスを変更
マウントはできましたが、このままではライブラリの依存関係を満たせないので Vine Linux 4.2 のバイナリはほとんどの場合で実行できません。
$ /opt/Vine42/usr/bin/gnome-calculator /opt/Vine42/usr/bin/gnome-calculator: error while loading shared libraries: libgnomeui-2.so.0: cannot open shared object file: No such file or directory $ ldd /opt/Vine42/usr/bin/gnome-calculator linux-gate.so.1 => (0xffffe000) libgnomeui-2.so.0 => not found libbonoboui-2.so.0 => not found
これは、Vine Linux 4.2のバイナリを実行するのに必要なライブラリ群が/opt/Vine42/usr/lib 以下に配置されている一方、ライブラリは /usr/lib 以下が参照されるため必要なライブラリをリンクできないのが原因です。そこで chroot を使って、/opt/Vine42/usr/lib が /usr/lib として参照できるようパスを変更します。
# chroot /opt/Vine42
これで、/opt/Vine42 が / としてアクセスできるようになります。 試しに、ldd してみるとライブラリの依存関係が満たされていることが確認できるでしょう。
# ldd /usr/bin/gnome-calculator linux-gate.so.1 => (0xffffe000) libgnomeui-2.so.0 => /usr/lib/libgnomeui-2.so.0 (0xf7660000) libbonoboui-2.so.0 => /usr/lib/libbonoboui-2.so.0 (0xf7600000)
なんちゃって仮想マシンとして使うための初期設定
chrootを使って、Vine Linux 4.2のバイナリが実行できるようになりました。しかし、chrootを実行するにはroot権が必要なほか、何かと不便が多いのであたかも仮想マシンにsshログインするかのように使えるよういくつかの設定をします。
まず、古い mtab が残っていると問題になることがあるので、一旦空っぽにしておきます。
# echo > /etc/mtab
次に、デバイスファイルがほとんど無いので、必要そうなものをいくつか作ります。
# ls /dev/ console null # MAKEDEV /dev/null /dev/random /dev/urandom /dev/ptmx # mkdir /dev/pts # mount /dev/pts # mount -n -t proc /proc /proc # mount -n -t sysfs /sys /sys # mkdir /dev/shm # mount /dev/shm
先の 3行の手続きは一度だけ必要な初期設定です。後の4回のmountコマンドは、ホストPCを再起動する度に必要となる設定です。
sshd を動かしてログイン
あとはsshdを動かせば、ログインできるようになります。
ただし、22番ポートはホストの Vine Linux 5.2 環境で使われているハズですので、ポート番号を適当に変えた上で sshd を起動します。
# vim /etc/ssh/sshd_config # diff /etc/ssh/sshd_config.orig /etc/ssh/sshd_config 13c13 < #Port 22 --- > Port 20022 # /etc/init.d/sshd start | nkf -uw sshdを起動中: [ OK ]
ちなみに、Vine Linux 4.2 は Vine Linux 5.2とはデフォルトのロケールが異なります。 (5.2はja_JP.UTF-8、4.2はja_JP.eucJP) そのために文字化けすることがあると思います。それぞれ適当に対応してください。
このほか、dbus も動いていないと何かと不便が多いようですので、dbusも起動しておきます。
# /etc/init.d/messagebus start
これで準備は完了です。chroot したターミナルはもう CTRL+d で閉じて構いません。
それではホストのVine Linuxから chroot上のVine Linux 4.2に一般ユーザーとしてSSHログインしてみましょう。この際、sshのポート番号を変えているので -p オプションで明示的にポート番号を指定することを忘れないで下さい。
$ ssh -p 20022 vine@localhost vine@localhost's password: Last login: Sun Dec 12 00:21:43 2010 from localhost.localdomain $ gnome-calculator &
今度は、ちゃんと電卓が起動できたと思います。きっと他の商用アプリケーションも動かせるでしょう。
なお、/etc/resolv.confが空っぽだったり正しくない値が書かれている場合に、DNSによる名前解決が出来ないことがあります。Host環境の設定をそのまま cp するので良いでしょう。
$ sudo cp -a /etc/resolv.conf /opt/Vine42/etc/resolv.conf
事例 2:Debianベースの ARM 開発環境を Vine Linux 5.2 で使う
先の事例では、既存のHDDにインストールしたVine Linux 4.2を Vine Linux 5.2上のchrootで使う事例を紹介しましたが、既存の環境がVMWare上にあった場合でも同様のことが可能です。
ここでは、VMWareのディスクイメージをループバックマウントして、先と同じくchrootのなんちゃって仮想マシンに仕立て上げる方法を紹介します。
VMWareのディスクイメージを入手
ちょっとAndroidをGingerbreadに更新したいなぁなんて思うことは誰でもあると思います。(いや、ないとは思いますが。。) そんなときに、クロス開発環境から作り始めるといろんなこだわりもあったりしてそれだけで半日遊んでしまいます。で、僕は今日いったい何をやっていたんだろう?などと後悔するわけです。閑話休題。
お手軽にARMのクロス開発環境がほしいと思ったときに便利なのが、株式会社アットマークテクノから公開されているATDEです。 VMWareのイメージをダウンロードしてきてそのまま使えますし、お手持ちのdebian の環境にインストールしても使えます。 でも、VMWare Playerは諸般の事情で使えないとか、やっぱりVineをメインで使いたいと思ったときに ATDEの環境をchrootの上で使えると便利です。 ここでは、ATDEのVMWareディスクイメージを例題としてVine Linux 5.2にマウントしてのchrootで使ってみます。
まず初めにATDEのサイトから VMWare イメージ (atde3-20100309.zip [696.69 MB]) をダウンロードし、zipアーカイブを展開します。
$ wget http://armadillo.atmark-techno.com/files/downloads/atde/atde3-20100309.zip $ sudo unzip atde3-20100309.zip -d /tmp/ Archive: atde3-20100309.zip creating: /tmp/atde3-20100309/ inflating: /tmp/atde3-20100309/atde3-s005.vmdk inflating: /tmp/atde3-20100309/atde3-s007.vmdk inflating: /tmp/atde3-20100309/atde3.vmx inflating: /tmp/atde3-20100309/atde3-s009.vmdk inflating: /tmp/atde3-20100309/atde3.vmxf inflating: /tmp/atde3-20100309/atde3.nvram extracting: /tmp/atde3-20100309/atde3.vmsd inflating: /tmp/atde3-20100309/atde3-s002.vmdk inflating: /tmp/atde3-20100309/atde3.vmdk inflating: /tmp/atde3-20100309/atde3-s001.vmdk inflating: /tmp/atde3-20100309/atde3-s003.vmdk inflating: /tmp/atde3-20100309/atde3-s004.vmdk inflating: /tmp/atde3-20100309/atde3-s006.vmdk inflating: /tmp/atde3-20100309/atde3-s008.vmdk
分割されたvmdkファイルをディスクのイメージに変換
vmdk をループバックマウントできるようにできるように、ディスクのファイル形式をqemu-imgでコマンドで変換します。 もしqemu-imgがインストールされていない場合にはapt-getインストールします。
$ sudo apt-get install qemu $ cd /tmp/atde3-20100309 $ sudo qemu-img convert atde3-s00[1-9].vmdk -O bin /opt/atde3-20100309.img (VMDK) image open: flags=0x2 filename=atde3-s001.vmdk (VMDK) image open: flags=0x2 filename=atde3-s002.vmdk (VMDK) image open: flags=0x2 filename=atde3-s003.vmdk (VMDK) image open: flags=0x2 filename=atde3-s004.vmdk (VMDK) image open: flags=0x2 filename=atde3-s005.vmdk (VMDK) image open: flags=0x2 filename=atde3-s006.vmdk (VMDK) image open: flags=0x2 filename=atde3-s007.vmdk (VMDK) image open: flags=0x2 filename=atde3-s008.vmdk (VMDK) image open: flags=0x2 filename=atde3-s009.vmdk $ fdisk -lu /opt/atde3-20100309.img 設定する必要があります シリンダ数. あなたは特別機能メニューからこれを行なうことができます Disk /opt/atde3-20100309.img: 0 MB, 0 bytes 255 heads, 63 sectors/track, 0 cylinders, total 0 sectors Units = セクタ数 of 1 * 512 = 512 bytes Disk identifier: 0x0008bb4c デバイス Boot Start End Blocks Id System /opt/atde3-20100309.img1 * 63 498014 248976 83 Linux /opt/atde3-20100309.img2 498015 33543719 16522852+ 8e Linux LVM 領域 2 は異なった物理/論理終点になっています: 物理=(1023, 254, 63) 論理=(2087, 254, 63)
LVMが使われているディスクイメージをループバックマウント
ディスクは参照できる形になりました。
でも面倒なことにLVMが使われているので、mount offset オプションを使ってマウントできません。(たぶん)
そこでまず、kpartxを使って各パーティションのデバイスマップを作ります。
$ sudo /sbin/kpartx -av /opt/atde3-20100309.img add map loop2p1 : 0 497952 linear /dev/loop2 63 add map loop2p2 : 0 33045705 linear /dev/loop2 498015 $ ls /dev/mapper/ control loop2p1 loop2p2
これでディスクイメージの各物理パーティションに対応したデバイスマップができました。fdiskで見えていたパーティションはそれぞれ、/dev/mapper/loop2p1 /dev/mapper/loop2p2 として参照できるようになっています。
次にLVM のマウントです。各コマンドについては適宜manなどで調べてください。詳細は割愛します。
$ sudo /sbin/pvscan PV /dev/dm-1 VG atde3 lvm2 [15.75 GB / 0 free] Total: 1 [15.75 GB] / in use: 1 [15.75 GB] / in no VG: 0 [0 ] $ sudo /sbin/lvscan inactive '/dev/atde3/root' [14.70 GB] inherit inactive '/dev/atde3/swap_1' [1.06 GB] inherit $ sudo /sbin/vgchange -ay 2 logical volume(s) in volume group "atde3" now active $ sudo /sbin/lvscan ACTIVE '/dev/atde3/root' [14.70 GB] inherit ACTIVE '/dev/atde3/swap_1' [1.06 GB] inherit
LVMのパーティションに対応するデバイスファイルができましたので、あとは普通にマウントできます。
$ sudo mkdir /opt/atde3-20100309 $ sudo mount -o loop /dev/atde3/root /opt/atde3-20100309 $ sudo mount -o loop /dev/mapper/loop0p1 /opt/atde3-20100309/boot
マウント後の初期設定
後の手順は事例1 と同様に、sshdを動かしててリモートログインできるように設定します。
後で使うので /etc/resolv.conf を ATDE側にコピーした上でchrootします。
$ sudo cp -a /etc/resolv.conf /opt/atde3-20100309/etc/ $ sudo chroot /opt/atde3-20100309
デバイスファイルはだいたい揃っているので、MAKDEV と mkdir は不要です。
# echo > /etc/mtab # mount /dev/pts # mount -n -t proc /proc /proc # mount -n -t sysfs /sys /sys # mount /dev/shm
sshdがインストールされていないのを追加すると、あとは事例1 と同様にsshログインできるようになります。
# apt-get install openssh-server # vim /etc/ssh/sshd_config # /etc/init.d/ssh start # exit $ ssh -p 20022 atmark@localhost atmark@localhost's password: atmark (初期パスワードはatmark) $ whoami atmark
試しにAndroid kernelをビルド
Armadillo-500FX用のビルド方法をまとめられているsolaさんのblog に沿ってATDEのクロスコンパイラを使ってkernelをビルドしてみました。
$ mkdir ~/bin $ curl http://android.git.kernel.org/repo > ~/bin/repo $ chmod +x ~/bin/repo $ export PATH=/home/atmark/bin:$PATH $ mkdir ~/work $ cd ~/work $ git clone git://github.com/sola-dolphin1/OHA-Android-2.3_r1.0.git Initialized empty Git repository in /home/atmark/work/OHA-Android-2.3_r1.0/.git/ remote: Counting objects: 191730, done. remote: Compressing objects: 100% (133820/133820), done. remote: Total 191730 (delta 84118), reused 158374 (delta 50901) Receiving objects: 100% (191730/191730), 1019.48 MiB | 2956 KiB/s, done. Resolving deltas: 100% (84118/84118), done. Checking out files: 100% (249342/249342), done. $ export ANDROID=/home/atmark/work/OHA-Android-2.3_r1.0 $ cd $ANDROID/kernel/armadillo500fx/ $ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- armadillo500fx_dev_android_defconfig HOSTCC scripts/basic/fixdep HOSTCC scripts/basic/docproc HOSTCC scripts/kconfig/conf.o HOSTCC scripts/kconfig/kxgettext.o SHIPPED scripts/kconfig/zconf.tab.c SHIPPED scripts/kconfig/lex.zconf.c SHIPPED scripts/kconfig/zconf.hash.c HOSTCC scripts/kconfig/zconf.tab.o HOSTLD scripts/kconfig/conf # # configuration written to .config # $ make ARCH=arm CROSS_COMPILE=/usr/bin/arm-linux-gnueabi- -j4 scripts/kconfig/conf -s arch/arm/Kconfig CHK include/linux/version.h (中略) AS .tmp_kallsyms2.o LD vmlinux SYSMAP System.map SYSMAP .tmp_System.map OBJCOPY arch/arm/boot/Image Kernel: arch/arm/boot/Image is ready AS arch/arm/boot/compressed/head.o GZIP arch/arm/boot/compressed/piggy.gz CC arch/arm/boot/compressed/misc.o Building modules, stage 2. MODPOST 1 modules CC drivers/scsi/scsi_wait_scan.mod.o LD [M] drivers/scsi/scsi_wait_scan.ko AS arch/arm/boot/compressed/piggy.o LD arch/arm/boot/compressed/vmlinux OBJCOPY arch/arm/boot/zImage Kernel: arch/arm/boot/zImage is ready
このように、ARM用のLinux Kernelをビルド出来る環境が簡単に実現できました。
ここではDebianベースのATDEを例に取りましたが、他のLinuxでも基本的にここで紹介した方法でchroot上で使えるようにできると思います。VMWareのディスクイメージは他にも様々なところで公開されていますので、いろいろ試してみて下さい。
おわりに
ここでは、既存のHDDイメージやVMWareのディスクイメージをループバックマウントして、仮想マシンのように使う事例を紹介しました。
chrootは使い方次第で様々な活用が可能です。今後もchrootを使ってVine Linuxのより幅広い活用事例を紹介していきます。読者の皆様から「こういった内容を詳しく知りたい」や「こんな問題があるけどよい解決方法は?」などのご要望、ご質問があれば前向きにテーマとして取り上げたいと思います。皆様のご意見、ご感想をお待ちしております。