with a virtual machine (VM) instance. Rather than simply install a
new VM and reapply software packages and configuration, the need was to
retain the existing installation. To do so, we effectively cloned the
physical host into a VM, which is what the following details. Of note,
while I'm calling this a "manual, offline p2v (physical to virtual)",
the details below could be easily used to clone to another physical host.
Our setup details are:
PHYSICAL HOST: humboldt VIRTUAL HOST: VM name is "hydrix" OS: CentOS 5.6 Linux (RHEL variant) PROMPTS: [phys sh-3.2# |virt sh-3.2# ] where phys = physical host and virt = virtual host NOTE: parts of this write up depend upon 'kudzu', which has been removed from RHEL 6Before getting started, the end result will be that VM "hydrix" will
contain the host "humboldt". The VM was named "hydrix" simply for
identifiable differentiation in the details that follow. Additionally,
the following was performed migrating between like hardware (CPU
architecture, allocated memory, presented disk devices, etc.) and using
a stock kernel. As a result, "your mileage may vary."
Starting off, on humboldt, we've taken down the host and booted from a
CDROM and opting for "linux rescue" at the boot prompt:
- To install or upgrade in graphical mode, press the <ENTER> key. - To install or upgrade in text mod, type: linux text <ENTER>. - Use the function keys listed below for more information. [F1-Main] [F2-Options] [F3-General] [F4-Kernel] [F5-Rescue] boot: linux rescueIn the following screens select Language option, keyboard type, network
startup [Yes | No] (select No), whether to mount root rw or ro [Continue |
Read-Only | Skip] (select Continue), etc. Following this, our filesystems
(FS) are mounted for us and we are dropped to a shell:
Your system is mounted under the /mnt/sysimage directory. When finished please exit from the shell and your system will reboot. phys sh-3.2#From the shell, we start information gathering on our physical host.
We need to determine approximately how much space will be required for our
filesystems (df). Since we might care about the actual disk partitioning
(fdisk), we can grab that too. Additionally, we check on the FS labels
for our partitions and the layout in "fstab":
phys sh-3.2# /usr/bin/df -h Filesystem Size Used Avail Use% Mounted on /dev 502M 0 502M 0% /dev /tmp/loop0 109M 109M 0 100% /mnt/runtime /dev/sda1 5.9G 1.3G 4.3G 23% /mnt/sysimage /dev/sda3 988M 47M 891M 5% /mnt/sysimage/var /dev 502M 0 502M 0% /mnt/sysimage/dev phys sh-3.2# /usr/sbin/fdisk -l /dev/sda Disk /dev/sda: 8589 MB, 8589934592 bytes 255 heads, 63 sectors/track, 1044 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id Sytem /dev/sda1 * 1 783 6289416 83 Linux /dev/sda2 784 914 1052257+ 82 Linux swap / Solaris /dev/sda3 915 1044 1044225 83 Linux sh-3.2# /usr/sbin/tune2fs -l /dev/sda1 | /usr/bin/grep 'name:' Filesystem volume name: / sh-3.2# /usr/sbin/tune2fs -l /dev/sda3 | /usr/bin/grep 'name:' Filesystem volume name: /var sh-3.2# /usr/bin/cat /mnt/sysimage/etc/fstab LABEL=/ / ext3 defaults 1 1 LABEL=/var /var ext3 defaults 1 2 tmpfs /dev/shm tmpfs defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 sysfs /sys sysfs defaults 0 0 proc /proc proc defaults 0 0 LABEL=SWAP-sda2 swap swap defaults 0 0 phys sh-3.2# /usr/bin/dmesg | /usr/bin/grep eth <6>e1000: eth0: e1000_probe: Intel(R) PRO/1000 Netowrk Connection <6>e1000: eth1: e1000_probe: Intel(R) PRO/1000 Netowrk Connection phys sh-3.2#On your host with the hypervisor, create a VM, allocating CPUs, memory,
network interfaces, disk devices, etc. Then, boot the VM ("hydrix"
in our case) from a Linux CD/DVDROM or ISO image. As before, enter
"linux rescue" at the boot prompt as seen below:
- To install or upgrade in graphical mode, press the <ENTER> key. - To install or upgrade in text mod, type: linux text <ENTER>. - Use the function keys listed below for more information. [F1-Main] [F2-Options] [F3-General] [F4-Kernel] [F5-Rescue] boot: linux rescueIn the following screens select Language option, keyboard type, network
startup [Yes | No] (select No), whether to mount root rw or ro [Continue
| Read-Only | Skip] (select Skip), etc. Now we are dropped into a shell
from which we can identify and, using 'fdisk', start laying out our disk
partitions for the VM:
When finished please exist from the shell and your system will reboot. virt sh-3.2# /usr/sbin/fdisk -l Disk /dev/sda: 8589 MB, 8589934592 bytes 255 heads, 63 sectors/track, 1044 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk /dev/sda doesn't contain a valid partition table virt sh-3.2# /usr/sbin/fdisk /dev/sda Device contains neither a valid DOS partition table, nor Sun, SGI or OSF disklabel Building a new DOS disklabel. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won't be recoverable. The number of cylinders for this disk is set to 1044. There is nothing wrong with that, but this is larger than 1024, and could in certain setups cause problems with: 1) software that runs at boot time (e.g., old versions of LILO) 2) booting and partitioning software from other OSs (e.g., DOS FDISK, OS/2 FDISK) Warning: invalid flag 0x0000 of partition table 4 will be corrected by w(rite) Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-1044, default 1): Using default value 1 Last cylinder or +size or +sizeM or +sizeK (1-1044, default 1044): +5120M Command (m for help): n <snip...> Command (m for help): t Partition number (1-4): 2 Hex code (type L to list codes): 82 Changed system type of partition 2 to 82 (Linux swap / Solaris) Command (m for help): a Partition number (1-4): 1 Command (m for help): p Disk /dev/sda: 8589 MB, 8589934592 bytes 255 heads, 63 sectors/track, 1044 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id Sytem /dev/sda1 * 1 623 5004216 83 Linux /dev/sda2 624 914 2337457+ 82 Linux swap / Solaris /dev/sda3 915 1044 1044225 83 Linux Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. Syncing disks.In the above, we created partitions 1-3 and re-typed partition 2 to
a swap type. We also set partition 1 as bootable. Of note, I didn't
used the exact same allocation as seen in the 'fdisk' output from the
physical host. This is to illustrate that you have some flexibility in
partition sizing as long as you account for the currently used space on
the physical host. With our partitions created, we create filesystems
(mke2fs) on "sda[1|3]", labelling them in the process, setting up "sda2"
as swap space (mkswap), and finally check our new FS with 'fsck':
virt sh-3.2# /usr/sbin/mke2fs -j -L '/' /dev/sda1 mke2fs 1.39 (29-May-2006) Filesystem label=/ OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 626496 inodes, 1251054 blocks 62552 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=1283457024 39 block groups 32768 blocks per group, 32768 fragments per group 16064 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376, 294912, 819200, 884736 Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 37 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. virt sh-3.2# /usr/sbin/mke2fs -j -L '/var' /dev/sda3 mke2fs 1.39 (29-May-2006) Filesystem label=/var OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 130560 inodes, 261056 blocks 13052 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=268435456 8 block groups 32768 blocks per group, 32768 fragments per group 16320 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Writing inode tables: done Creating journal (32768 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 21 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. virt sh-3.2# /usr/sbin/tune2fs -l /dev/sda1 | /usr/bin/grep 'name:' Filesystem volume name: / virt sh-3.2# /usr/sbin/tune2fs -l /dev/sda3 | /usr/bin/grep 'name:' Filesystem volume name: /var virt sh-3.2# /usr/sbin/mkswap /dev/sda2 Setting up swapsapce version 1, size = 2393550 kb virt sh-3.2# /usr/sbin/fsck -y /dev/sda1 fsck 1.39 (29-May-2006) WARNING: couldn't open /etc/fstab: No such file or directory e2fsck 1.39 (29-May-2006) /: clean, 11/626496 files, 54920/1251054 blocks virt sh-3.2# /usr/sbin/fsck -y /dev/sda3 fsck 1.39 (29-May-2006) WARNING: couldn't open /etc/fstab: No such file or directory e2fsck 1.39 (29-May-2006) /var: clean, 11/130560 files, 8529/261056 blocks virt sh-3.2#With our FS created and checked, we mount "sda1" to "/a" in preparation
for our data migration from the physical host. We also configure eth1
with an IP address and bring it online. (eth1 was chosen because in
creating our VM, we attached and configured that interface to the same
VLAN as the physical host resides.) Finally, we change directory to "/a",
have 'netcat" (nc) listen on port 1970, and pipe it's output to 'restore':
virt sh-3.2# /usr/bin/mkdir /a virt sh-3.2# /usr/bin/mount -t ext3 -o rw /dev/sda1 /a virt sh-3.2# /usr/bin/df -h /a Filesystem Size Used Avail Use% Mounted on /dev/sda1 4.7G 138M 4.4G 4% /a virt sh-3.2# /usr/sbin/ifconfig eth1 192.168.56.162 netmask 255.255.255.0 up virt sh-3.2# /usr/sbin/ifconfig eth1 | /usr/bin/egrep 'eth1|inet addr|Metric' eth1 Link encap:Ethernet HWaddr 08:00:27:47:51:21 inet addr:192.168.56.162 Bcast:192.168.56.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 virt sh-3.2# cd /a ; /usr/bin/nc -l -p 1970 | /usr/sbin/restore rf -Back on our physical host, humboldt, we configure its network interface
(which also happens to be "eth1") with an IP addr and bring it up. Next,
we use 'dump' to backup "/dev/sda1" (our root FS), and using 'netcat'
we send the backup to our VM which is listening for it on port 1970:
phys sh-3.2# /usr/sbin/ifconfig eth1 192.168.56.125 netmask 255.255.255.0 up phys sh-3.2# /usr/sbin/ifconfig eth1 | /usr/bin/egrep 'eth1|inet addr|Metric' eth1 Link encap:Ethernet HWaddr 08:00:27:77:9b:b3 inet addr:192.168.56.125 Bcast:192.168.56.255 Mask:255.255.255.0 UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 phys sh-3.2# /usr/sbin/dump 0f - /dev/sda1 | /usr/bin/nc 192.168.56.162 1970 DUMP: Can't open /etc/fstab for dump table information: No such file or diredctory DUMP: WARNING: no file `/etc/dumpdates' DUMP: Date of this level 0 dump: Sat Dec 3 17:10:40 2011 DUMP: Dumping /dev/sda1 (/mnt/sysimage) to standard output DUMP: Label: / DUMP: Writing 10 Kilobyte records DUMP: mapping (Pass I) [regular files] DUMP: mapping (Pass II) [directories] DUMP: estimated 1163050 blocks. DUMP: Volume 1 started with block 1 at: Sat Dec 3 17:10:43 2011 DUMP: dumping (Pass III) [directories] DUMP: dumping (Pass IV) [regular files] DUMP: Volume 1 completed at: Sat Dec 3 17:12:12 2011 DUMP: Volume 1 1361500 blocks (1329.59MB) DUMP: Volume 1 took 0:01:29 DUMP: Volume 1 transfer rate: 15297 kB/s DUMP: 1361500 blocks (1329.59MB) DUMP: finished in 89 seconds, throughput 15297 kBytes/sec DUMP: Date of this level 0 dump: Sat Dec 3 17:10:40 2011 DUMP: Date this dump completed: Sat Dec 3 17:12:12 2011 DUMP: Average transfer rate: 15297 kB/s DUMP: DUMP IS DONE phys sh-3.2#We still see the normal 'dump' output on the physical host as seen above.
The initial 'dump' errors can be ignored since we are doing this from
"rescue mode" from the CDROM, thus those files wouldn't exist there.
On our VM, once 'dump' completes on the physical host, 'netcat' stops
listening on port 1970 and closes the port. A 'df' of "/a" shows the same
used space as on the physical host and if one were inclined to do so, a
further detailed check of data should be identical. After this, we mount
"sda3" to "/a/var" and repeat the process seen above. To differentiate
the steps, port 2038 is used this time:
## output seen after executing '/usr/bin/nc -l -p 1970 | /usr/sbin/restore rf -' /usr/sbin/restore: ./lost+found: File exists virt sh-3.2# /usr/bin/df -h /a Filesystem Size Used Avail Use% Mounted on /dev/sda1 4.7G 1.3G 3.3G 28% /a virt sh-3.2# /usr/bin/mount -t ext3 -o rw /dev/sda3 /a/var virt sh-3.2# /usr/bin/df -h /a/var Filesystem Size Used Avail Use% Mounted on /dev/sda3 1004M 10M 936M 2% /a/var virt sh-3.2# cd /a/var virt sh-3.2# /usr/bin/nc -l -p 2038 | /usr/sbin/restore rf -Run of 'dump' on the physical host:
phys sh-3.2# /usr/sbin/dump 0f - /dev/sda3 | /usr/bin/nc 192.168.56.162 2038 DUMP: Can't open /etc/fstab for dump table information: No such file or diredctory DUMP: WARNING: no file `/etc/dumpdates' DUMP: Date of this level 0 dump: Sat Dec 3 17:24:05 2011 DUMP: Dumping /dev/sda3 (/mnt/sysimage/var) to standard output DUMP: Label: /var DUMP: Writing 10 Kilobyte records DUMP: mapping (Pass I) [regular files] DUMP: mapping (Pass II) [directories] DUMP: estimated 29707 blocks. DUMP: Volume 1 started with block 1 at: Sat Dec 3 17:24:06 2011 DUMP: dumping (Pass III) [directories] DUMP: dumping (Pass IV) [regular files] DUMP: Volume 1 completed at: Sat Dec 3 17:24:08 2011 DUMP: Volume 1 33730 blocks (32.94MB) DUMP: Volume 1 took 0:00:02 DUMP: Volume 1 transfer rate: 16865 kB/s DUMP: 33730 blocks (32.94MB) DUMP: finished in 2 seconds, throughput 16865 kBytes/sec DUMP: Date of this level 0 dump: Sat Dec 3 17:24:05 2011 DUMP: Date this dump completed: Sat Dec 3 17:24:08 2011 DUMP: Average transfer rate: 16865 kB/s DUMP: DUMP IS DONE phys sh-3.2#Once the dump completes on our physical host, assuming our data is good
on the VM, we can shutdown the physical host using 'halt' as we won't
be needing it any further:
phys sh-3.2# /bin/halt Running halt... Terminated phys sh-3.2# sending termination signals...done sending kill signals...done disabling swap... /dev/sda2 unmounting filesystems... /mnt/runtime done <snip...>Back on the VM, hydrix, we go back through our check of "/a/var".
## output seen after executing '/usr/bin/nc -l -p 2038 | /usr/sbin/restore rf -' /usr/sbin/restore: ./lost+found: File exists virt sh-3.2# /usr/bin/df -h /a/var Filesystem Size Used Avail Use% Mounted on /dev/sda3 1004M 47M 907M 5% /a/var virt sh-3.2#At this point, we have to setup the MBR so we'll launch into 'grub'.
Once there, we have 'grub' find the boot disk (hd0,0) and install itself
to the MBR with the appropriate configuration, then exiting 'grub':
virt sh-3.2# /usr/sbin/grub Probing devices to guess BIOS drives. This may take a long time. GNU GRUB version 0.97 (640K lower / 3072K upper memory) [ Minimal BASH-like line editing is supported. For the first word, TAB lists possible command completions. Anywhere else TAB lists the possible completions of a device/filename.] grub> find /boot/grub/stage1 (hd0,0) grub> root (hd0,0) Filesystem type is ext2fs, partition type 0x83 grub> setup (hd0) Checking if "/boot/grub/stage1" exists... yes Checking if "/boot/grub/stage2" exists... yes Checking if "/boot/grub/e2fs_stage1_5" exists... yes Running "embed /boot/grub/e2fs_stage1_5 (hd0)"... 15 sectors are embedded. succeeded Running "install /boot/grub/stage1 (hd0) (hd0)1+15 p (hd0,0)/boot/grub/stage3 /boot/grub/grub.conf"... succeeded Done. grub> quit quit virt sh-3.2#Our last steps prior to reboot are to remove the "restoresymtable"
files, mount "/a/sys", 'chroot' to "/a" to backup and recreate (mkinitrd)
our initial RAM disk image (initrd):
virt sh-3.2# /usr/bin/rm /a/restoresymtable /a/var/restoresymtable virt sh-3.2# /usr/bin/mount -t sysfs -o rw /tmp/sysfs /a/sys # /tmp/sysfs will not exist, just go with it, after mount, /a/sys will contain data virt sh-3.2# /usr/sbin/chroot /a virt sh-3.2# /bin/mv /boot/initrd-2.6.18-238.el5.img /boot/old-initrd-2.6.18-238.el5.img-old virt sh-3.2# /sbin/mkinitrd /boot/initrd-2.6.18-238.el5.img 2.6.18-238.el5 virt sh-3.2# exit exit virt sh-3.2#After exiting the "chroot environment", again type exit to reboot the
system (don't forget to remove the CD/DVDROM/ISO image after the host
shuts down through the reboot):
virt sh-3.2# exit exit sending termination signals...done sending kill signals...done disabling swap... unmounting filesystems... /mnt/runtime done <snip...> rebooting systemOnce past the BIOS post, we should get a "grub" menu similar to that
below. Select the appropriate entry and hit 'e'; we'll need to set
bootup to "single user":
GNU GRUB version 0.97 (639K lower / 1047488K upper memory) CentOS 5.6 (2.6.18 238.el5) <================== Use the <up> and <down> keys to select which entry is highlighted. Press enter to boot the selected OS, 'e' to edit the commands before booting, 'a' to modify the kernel arguments before booting, or 'c' for a command-line. The highlighted entry will be booted automatically in 5 seconds.The "grub" screen should refresh to similar to the following:
GNU GRUB version 0.97 (639K lower / 1047488K upper memory) root (hd0,0) kernel /boot/vmlinuz-2.6.18-238.el5 ro root=LABEL=/ initrd /boot/initrd-2.6.18-238.el5.img Use the <up> and <down> keys to select which entry is highlighted. Press 'b' to boot, 'e' to edit the selected command in the boot sequence, 'c' for a command-line, 'o' to open a new line after ('O' for before) the selected line, 'd' to remove the selected line, or escape to go back to the main menu.Select the "kernel" entry, hit 'e', and update the line from this:
kernel /boot/vmlinuz-2.6.18-238.el5 ro root=LABEL=/to this:
kernel /boot/vmlinuz-2.6.18-238.el5 ro root=LABEL=/ -sAfter the modification, hit 'enter' then 'b', at which point the screen
clears to bootup:
root (hd0,0) Filesystem type is ext2fs, partition type 0x83 kernel /boot/vmlinuz-2.6.18-238.el5 ro root=LABEL=/ [Linux-bzImage, setup=0x1e00, size=0x1fd63c] initrd /boot/initrd-2.6.18-238.el5.img [Linux-initrd @ 0x37d60000, 0x28f833 bytes] <snip...> Mounting local filesystems: [ OK ] Enabling local filesystem quotas: [ OK ] Enabling /etc/fstab swaps: [ OK ] virt sh-3.2#The reason for booting to "single user" mode is to validate that our
newly migrated system has correct data for our network interfaces.
A quick check of "hwconf" shows two Intel GigE NICs (e1000), however
probing our interfaces with 'kudzu' shows one Intel GigE NIC (e1000)
and one AMD 79c970 NIC (pcnet32). Additionally, both HWaddrs have
changed for "eth0" and "eth1":
virt sh-3.2# /bin/grep -A3 eth /etc/sysconfig/hwconf device: eth0 driver: e1000 desc: "Intel Corporation 82540EM Gigabit Ethernet Controller" network.hwaddr: 08:00:27:9c:16:2b -- device: eth1 driver: e1000 desc: "Intel Corporation 82540EM Gigabit Ethernet Controller" network.hwaddr: 08:00:27:77:9b:b3 virt sh-3.2# /sbin/kudzu -c network -p | /bin/grep -A3 eth device: eth0 driver: e1000 desc: "Intel Corporation 82540EM Gigabit Ethernet Controller" network.hwaddr: 08:00:27:76:96:81 -- device: eth1 driver: pcnet32 desc: "Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE]" network.hwaddr: 08:00:27:47:51:21 virt sh-3.2#So that our network configuration will be retained and our interfaces
brought up as they were on the physical host, we need to update "hwconf"
to be reflective of the output from 'kudzu' above. We also need to
update the "HWADDR" key in the individual "ifcfg-eth#" files:
virt sh-3.2# /bin/vi /etc/sysconfig/hwconf <snip> virt sh-3.2# /bin/grep -A3 eth /etc/sysconfig/hwconf device: eth0 driver: e1000 desc: "Intel Corporation 82540EM Gigabit Ethernet Controller" network.hwaddr: 08:00:27:76:96:81 -- device: eth1 driver: pcnet32 desc: "Advanced Micro Devices [AMD] 79c970 [PCnet32 LANCE]" network.hwaddr: 08:00:27:47:51:21 virt sh-3.2# /bin/vi /etc/sysconfig/network-scripts/ifcfg-eth* <snip...> virt sh-3.2# /bin/egrep -h 'DEVICE|HWADDR' /etc/sysconfig/network-scripts/ifcfg-eth* DEVICE=eth0 HWADDR=08:00:27:76:96:81 DEVICE=eth1 HWADDR=08:00:27:47:51:21 virt sh-3.2#Assuming you have no further changes that you'd like to make, our work
is now complete. Exit the single user shell for the system to finish
coming up to the default runlevel. Your host has now been functionally
migrated into a VM:
virt sh-3.2# exit logout INIT: Entering runlevel: 3 Entering non-interactive startup [ OK ] Starting background readahead: [ OK ] Checking for hardware changes [ OK ] Bringing up loopback interface: [ OK ] Bringing up interface eth1: [ OK ] <snip...> #screen clears to console login: CentOS release 5.6 (Final) Kernel 2.6.18-238.el5 on an x86_64 humboldt login: _