Linux cloning procedure in a nutshell
By Nathan Johnson
Inspired in part by: http://www.ebruni.it/docs/clone_linux/t1.htm
Note: while these instructions are meant to clone one working machine onto a blank target, this could pretty easily be modified to be a bare metal backup / restore procedure by simply storing a tarball instead of using netcat to copy to a live system, and for the restore to just use the tarball as a source and write to netcat versus reading from a live system
Prerequisites: two machines with similar hardware / architecture. i.e., if source is 64 bit, dest must also be 64 bit. The closer the system architecures, the better.
Source Machine running RHEL (for the purposes of this)
RHEL installation DVD of same version as source machine (roughly)
Boot from RHEL DVD in rescue mode. When the DVD boots and it’s prompting you with the boot: prompt,
and hit enter.
It will then ask you language, go with defaults (English / US). When it asks if you want to start the network interfaces, say no. When it asks if you want to find a linux installation, select Skip. It will dump you back to a shell. I’m going to assume that the source uses LVM.
If the disk is already partitioned and LVM is already configured, skip to step 2.
Regardless of whether lvm is used, we must first run fdisk as linux cannot boot from an LVM volume. Use the following to get the device names of the available disks on the system:
sh-3.2# fdisk -l
Then pick one to do the install on. Start fdisk on this device. For the purposes of this example, the disk device will be /dev/cciss/c0d0
sh-3.2# fdisk /dev/cciss/c0d0
select ‘n’ to add a new partition, ‘p’ for primary, 1 for partition number, go with default for first cylinder (1), and +500M to select a 500M partition for boot (this can be 100M or even less if you want, but 500M gives a lot of wiggle room). Now with the boot partition created, make it active by selecting ‘a’ and select partition number ‘1’
select ‘n’ to add another partition, ‘p’ for primary, ‘2’ for partition number, go with default for first cylinder, and go with default for last (i.e., use the rest of the disk). This will be our LVM partition. Hit ‘t’ to change the system ID of this partition, select partition number of ‘2’, and select ‘8e’ as partition type for Linux LVM.
Hit ‘p’ and ensure that your layout. Here is an example of what we would have just configured above:
Disk /dev/cciss/c0d0: 293.5 GB, 293563949056 bytes 255 heads, 63 sectors/track, 35690 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Device Boot Start End Blocks Id System /dev/cciss/c0d0p1 * 1 64 514048+ 83 Linux /dev/cciss/c0d0p2 65 35690 286165845 8e Linux LVM
If all is well, hit ‘w’ to write the partition table to disk and exit.
At this point, we need to look at the logical volume layout on the source:
[root@fisma-lin-app-1 ~]# lvm lvdisplay --- Logical volume --- LV Name /dev/mainvolgroup/rootvol VG Name mainvolgroup LV UUID yL9jYW-b12C-A0kN-iSve-tySm-JVIZ-o8EhuY LV Write Access read/write LV Status available # open 1 LV Size 268.91 GB Current LE 8605 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:0 --- Logical volume --- LV Name /dev/mainvolgroup/swapvol VG Name mainvolgroup LV UUID JF37pZ-hTlc-crSm-wdC3-jqlG-VOuM-e033oS LV Write Access read/write LV Status available # open 1 LV Size 4.00 GB Current LE 128 Segments 1 Allocation inherit Read ahead sectors auto - currently set to 256 Block device 253:1
Here we see two logical volumes, rootvol of size 268GB and swapvol of size 4GB, inside the volume group named mainvolgroup. Now we need to recreate the names at least to be the same, even if the sizes differ, on the target machine
Create the physical volume on the target for the LVM partition we created with fdisk above:
sh-3.2# lvm pvcreate /dev/cciss/c0d0p2
Now create the volume group (mainvolgroup in this case) to live on the physical volume:
sh-3.2# lvm vgcreate mainvolgroup /dev/cciss/c0d0p2
Now create the logical volumes to live inside the volume group. In this example we’ll create a 4G partition called swapvol and then use the remaining free space for the root partition.
sh-3.2# lvm lvcreate -L 4G -n swapvol mainvolgroup sh-3.2# lvm lvcreate -l 100%FREE -n rootvol mainvolgroup
Skip ahead to Step 4
If you have skipped ahead because the disk has already been partitioned, you may need to enable the volume groups (they will be active already if you’ve carved up the disk to this point). Assuming the volume group is called mainvolgroup, you can activate this using:
sh-3.2# lvm vgchange -ay mainvolgroup
Now we need to format our partitions:
sh-3.2# mke2fs -j /dev/cciss/c0d0p1
sh-3.2# mke2fs -j /dev/mainvolgroup/rootvol
sh-3.2# mkswap /dev/mainvolgroup/swapvol
Now let’s create a mount point and mount the root vol on the target machine:
sh-3.2# mkdir /mnt/rhroot sh-3.2# mount /dev/mainvolgroup/rootvol /mnt/rhroot
Now we need to create some directories:
sh-3.2# cd /mnt/rhroot sh-3.2# mkdir proc sys media misc mnt net selinux srv boot tmp sh-3.2# chmod 1777 tmp
Mount our boot partition:
sh-3.2# mount /dev/cciss/c0d0p1 /mnt/rhroot/boot
Now we need to bring up a network interface.
sh-3.2# ifconfig eth0 10.200.99.10 netmask 255.255.255.128 sh-3.2# route add default gw 10.200.99.5 sh-3.2# echo "nameserver 188.8.131.52" > /etc/resolv.conf
(obviously substituting the ip address and netmask you need here, preferably something not already in use, as well as gateway address and dns servers)
note: if you have dhcp available, you could just do: “pump -i eth0” instead
You will also need to assign 127.0.0.1 to loopback, this is not automatically done on the RHEL rescue. This is only required if doing ssh tunnels.
sh-3.2# ifconfig lo 127.0.0.1 netmask 255.0.0.0
If you do not have a port that can be opened directly from source to dest, skip to Step 8 for configuring an ssh tunnel. Otherwise skip to step 9
if the source and dest are separated by a firewall and there is no convenient port available for netcat to use, ssh forwarding can be used as long as the source can ssh to dest, or as long as there is a box that both the source and dest can ssh into.
Using the first scenario:
from dest, hit Ctrl+Alt+F2 to get to the second VC and type:
ssh -Rlocalhost:6060:127.0.0.1:6060 user@dest
Switch back over to the First VC for the rest by hitting Ctrl+Alt+F1
Using the second scenario:
From source, open up a second shell and type: ssh -L6060:localhost:6060 user@somehost
from dest, hit Ctrl+Alt+F2 to get to the second VC and type: ssh -Rlocalhost:6060:127.0.0.1:6060 user@somehost
Switch back over to the First VC for the rest by hitting Ctrl+Alt+F1
It is useful to set the time on the destination machine. Unfortunately there is no ntp client on the RHEL rescue image, so you will have to set it manually with the date command as well as set the timezone. Keep in mind that the date command on the rescue CD gives the following time format:
MMDDhhmmCCYY.ss So to set the time to 11/11/2010 15:30:45 You would give date -s 111115302010.45
sh-3.2# export TZ=CST sh-3.2# date -s 111115302010.45
Copy the data
now, from the /mnt/rhroot directory of the source machine we need to start netcat to listen and pipe to tar:
sh-3.2# cd /mnt/rhroot sh-3.2# nc -l -p 6060 | tar xvp
where 6060 is some arbitrary port you want to listen on.
Now, from the source machine:
Create an excludes file, I’m going to name it ~/excludes, with the following entries:
/lost+found/ /media/ /misc /mnt /net /proc /selinux /srv /sys /tmp
tar cvOp --same-owner -X ~/excludes / | nc -w 5 10.200.99.10 6060
(the ip address will be localhost if you’re doing ssh forwarding)
Go get coffee.
Once copying has finished, we will bind mount some pseudo filesystems and chroot to our new environment (dest), and do a little cleanup
sh-3.2# mount -o bind /dev /mnt/rhroot/dev sh-3.2# mount -o bind /sys /mnt/rhroot/sys sh-3.2# mount -o bind /proc /mnt/rhroot/proc sh-3.2# mount -o bind /selinux /mnt/rhroot/selinux sh-3.2# chroot /mnt/rhroot sh-3.2# su - [root@localhost]# cp /proc/mounts /etc/mtab [root@localhost]# cd /dev [root@localhost]# ln -s mainvolgroup/rootvol root
Obviously adjust this last line to match the dev entry for the root filesystem, but this symlink must be present. Alternately you can use mknod to create a “real” dev entry.
So now we need to modify some boot config files (possibly) and finalize our configuration, leaving the disk ready to be booted.
a) Modify /etc/fstab , paying particular attention to the /boot partition as it may be different on dest than on source (don’t rely on LABEL, give a path to the device)
b) Modify the /boot/grub/menu.lst to ensure that it has the proper boot device set, and install the boot loader into the MBR
sh-3.2# grub-install /dev/cciss/c0d0
c) Modify the /etc/sysconfig/network-scripts/ifcfg-eth0 to give it a new IP address, make sure to remove the HWADDR line as it will actually clone the Mac address of the original (unless this is desired).
d) Modify /etc/sysconfig/network and update the hostname
e) Create initrd images for all of the kernels in /boot
[root@localhost]# ls -l /boot/vmlinuz* -rw-r--r-- 1 root root 1954780 Sep 17 04:11 /boot/vmlinuz-2.6.18-194.11.4.el5 -rw-r--r-- 1 root root 1955036 Sep 20 06:17 /boot/vmlinuz-2.6.18-194.17.1.el5 -rw-r--r-- 1 root root 1955356 Oct 29 13:26 /boot/vmlinuz-2.6.18-194.26.1.el5
So we could do the following:
[root@localhost]# mkinitrd -f /boot/initrd-2.6.18-194.26.1.el5.img 2.6.18-194.26.1.el5 [root@localhost]# mkinitrd -f /boot/initrd-2.6.18-194.17.1.el5.img 2.6.18-194.17.1.el5 [root@localhost]# mkinitrd -f /boot/initrd-2.6.18-194.11.4.el5.img 2.6.18-194.11.4.el5
the first argument is the initrd image, the second argument is the kernel version.
Now exit out of the su shell, exit again out of chroot, then unmount everything and reboot!
[root@localhost ]# exit sh-3.2# exit sh-3.2# cd / sh-3.2# umount /mnt/rhroot/proc sh-3.2# umount /mnt/rhroot/sys sh-3.2# umount /mnt/rhroot/selinux sh-3.2# umount /mnt/rhroot/dev sh-3.2# umount /mnt/rhroot/boot sh-3.2# umount /mnt/rhroot
If it says it’s still busy, make sure you didn’t forget any, type “mount” and see what’s still mounted under /mnt/rhroot
Boot system from hard disk
If all goes well, you can reboot from the hard drive and it should pull up your working clone.
You will need to join the domain again if you are using samba / winbind. You will need to re-run rhn_register and give it a new license