Nathan's Blog

January 25, 2011

Bare Metal Linux Cloning

Filed under: Linux,Red Hat — Tags: , , , — nathan @ 11:58 am

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,

boot:

type:

linux rescue

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.

Step 1:

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:

step 2:

[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

Step 3:

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

Step 4:

Now we need to format our partitions:

First boot:

sh-3.2# mke2fs -j /dev/cciss/c0d0p1

Now root:

sh-3.2# mke2fs -j /dev/mainvolgroup/rootvol

Now swap:

sh-3.2# mkswap /dev/mainvolgroup/swapvol

Step 5:

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

Step 6

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

Step 7

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 160.129.6.22" > /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

Step 8

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

Step 9

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

Step 10:

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.

Step 11

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.

Step 12

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

For example:

[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.

Step 13

Final Cleanup

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

Step 14

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

Summary
Article Name
Linux cloning procedure in a nutshell
Description
Instructions on how to do a bare-metal clone from one red hat linux machine to another using a rescue CD.
Author

No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

You must be logged in to post a comment.

Powered by WordPress

contact