Quick summary

The command line tool debootstrap allows you to install a Debian based Linux system while keeping running an already installed Linux system, which need not be from the Debian family.

So you can install a new system, while the current system is running.
Why would you want to do that?

  • Maybe you installed a new hard disk in your server and want to move the OS to this disk with minimum downtime.
  • Or you would like to dry run a critical update without risking to break your installed system. Therefore you clone your current system to a separate disk.
  • Or maybe just because you can.

Training with Virtualbox

The reason why I went down this path was because I wanted to reconfigure the four disks in one of our servers into a different RAID configuration. But before laying my hands on our real server, I examined the whole procedure with a Debian Squeeze virtual machine on Virtualbox. The different aha! effects on the way made me write this article.

I generated a new disk image and attached it to the VM, partitioned it with one primary  partition (/dev/sdb1) for the root system and a logical partition (/dev/sdb5) for swap. So my virtual machine had two disks with four partitions: /dev/sda1, /dev/sda5, /dev/sdb1, /deb/sdb5. First steps are to install the disk, partition and format it and to turn on swap. Then mount the new disk to a mountpoint. /mnt/debinst for example.

  1. hostname:~# mount
  2. /dev/sda1 on / type ext3 (rw,errors=remount-ro)
  3. tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
  4. proc on /proc type proc (rw,noexec,nosuid,nodev)
  5. sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
  6. udev on /dev type tmpfs (rw,mode=0755)
  7. tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
  8. devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
  9. hostname:~#
  10. hostname:~# ls /dev/disk/by-uuid
  11. insgesamt 0
  12. lrwxrwxrwx 1 root root 10 15. Nov 2010  4051fed5-17fe-493c-af96-cc3df5cd6229 -> ../../sdb1
  13. lrwxrwxrwx 1 root root 10 15. Nov 2010  409a1d6b-a668-4b96-9ae9-22975e5debb4 -> ../../sda1
  14. lrwxrwxrwx 1 root root 10 15. Nov 2010  6dc8fa2f-744c-47a9-b64f-05e8c9c318c2 -> ../../sda5
  15. lrwxrwxrwx 1 root root 10 15. Nov 2010  8eaf21d0-c7b4-45cf-9e59-35187eac7939 -> ../../sdb5
  16. hostname:~#
  17. hostname:~# mkfs.ext4 /dev/sdb1
  18. mke2fs 1.41.12 (17-May-2010)
  19. [ mkfs output ]
  20. hostname:~# mkswap /dev/sdb5
  21. hostname:~# sync; sync; sync
  22. hostname:~# swapon /dev/sdb5
  23. hostname:~# mkdir /mnt/debinst/
  24. hostname:~# mount /dev/sdb1 /mnt/debinst
  25. hostname:~#

After that I installed debootstrap. On a Debian based system this can simply be done with aptitude or apt-get:

  1. hostname:~#
  2. hostname:~# aptitude install debootstrap
  3. hostname:~#

For other Linux derivates see the article mentioned above.

Using debootstrap to install a minimal system into a directory

debootstrap can download the required files directly from the net and will install a minimal Debian system into a directory. Substitute ARCH with the required architecture, choosing from alpha, amd64, arm, armel, hppa, i386, ia64, m68k, mips, mipsel, powerpc, s390, or sparc. You can use a mirror that is closer to your location of course.

  1. hostname:~#
  2. hostname:~# debootstrap  --arch ARCH squeeze  /mnt/debinst http://ftp.de.debian.org/debian
  3. hostname:~#

After that I changerooted into the directory and continued configuring the new system.

  1. hostname:~#
  2. hostname:~# LANG=C chroot /mnt/debinst /bin/bash
  3. hostname:~# <- Note that this probably looks
  4. hostname:~# just like your normal root prompt

To make it less likely to confuse the new system with the already running system I changed the prompt by editing my .bashrc in the chrooted system and exported PS1 with something I could easily recognize. I added the following lines which include one of my favourite bash magic snippets with the PWD function. This prompt always displays the last two directory levels, no matter how deep you are into the rabbit hole.

  1. function PWD {
  2. tmp=${PWD%/*/*};
  3. [ ${#tmp} -gt 0 -a "$tmp" != "$PWD" ] &&
  4. echo ${PWD:${#tmp}+1} || echo $PWD;
  5. }
  6. export PS1="\[\033[0;31m\]CHROOTED:\[\033[0;31m\]\$(PWD 3)\[\033[0m\]::>~ ";

Creating device nodes

Section D.3.4.1. of the cited article is a bit sparse on the topic. It recommends using MAKEDEV or leaving it to udev, but does not go into the details. For me there are two possibilities, a quick and dirty one and a cleaner solution which I prefer.
The problem is that you can not yet boot into the new system, upon which udev would populate your /dev section with the required device nodes. In order to easily install grub and stuff you need these devices now, without a reboot.

If you take the quick and dirty approach with MAKEDEV, the tool will complain that udev is obviously in use and will abort. You can trick MAKEDEV by temporarily moving /dev/.udev aside and moving it back later:

  1. CHROOTED:~::>~ cd /dev
  2. CHROOTED:/dev::>~ mv .udev .udev-begone
  3. CHROOTED:/dev::>~ MAKEDEV generic
  4. [lot of stuff happening]
  5. CHROOTED:/dev::>~ mv .udev-begone .udev

This way you will end up with a lot of static device nodes, old school style, while actually using the dynamic udev mechanism which is meant to generate the device nodes upon system startup. This will probably work fine, but might be a source for confusion and problems if you plan on using this system for a while.

A cleaner way is to get udev to generate the device nodes without a reboot. udev relies on information from sysfs and proc, so these have to be mounted first. Restarting the udev demon will populate the device section with some device nodes. If the disk nodes don’t show up, use the udevadm tool.

  1. CHROOTED:/dev::>~ ls /sys/ # these two
  2. CHROOTED:/dev::>~ ls /proc/ # come up empty
  3. CHROOTED:/dev::>~ mount -t sysfs sysfs /sys
  4. CHROOTED:/dev::>~ mount -t proc proc /proc
  5. CHROOTED:/dev::>~ /etc/init.d/udev restart
  6. CHROOTED:/dev::>~ ls /dev/disk
  7. ls: cannot access /dev/disk: No such file or directory
  8. CHROOTED:/dev::>~
  9. CHROOTED:/dev::>~ udevadm test /sys/block/sda
  10. [ lot of stuff rushes by ]
  11. CHROOTED:/dev::>~ ls /dev/disk
  12. by-id by-path
  13. CHROOTED:/dev::>~ ls /dev/sda*
  14. /dev/sda
  15. CHROOTED:/dev::>~
  16. CHROOTED:/dev::>~ udevadm trigger
  17. CHROOTED:/dev::>~ ls /dev/sda*
  18. brw-rw---- 1 root disk 8, 0 Nov 17 16:15 /dev/sda
  19. brw-rw---- 1 root disk 8, 1 Nov 17 16:15 /dev/sda1
  20. brw-rw---- 1 root disk 8, 2 Nov 17 16:15 /dev/sda2
  21. brw-rw---- 1 root disk 8, 5 Nov 17 16:15 /dev/sda5
  22. CHROOTED:/dev::>~
  23. [ rinse and repeat for sdb ]

If all this fails you can also simply copy the /dev/disk directory from the host to the chrooted environment.

  1. hostname:~#
  2. hostname:~# cd /dev; cp -a disk /mnt/debinst/dev
  3. hostname:~#

Follow the original article

Editing the fstab as well as reconfiguring tzdata, locales and console-data and all the other steps described in the original article worked just fine.
Copy /etc/network/interfaces and any other required configuration file to the new system. Or take a peek and follow the “migrating data” section of this article.

Install a kernel

As described in the original article.

If you are already running a Debian based system you can easily recreate all the packages you have installed in the new system. This will of course include a kernel and grub.

Debian allows to save the installed package list and the package configurations to a file and to install and configure the packages from this list, allowing you to clone whatever software packages you have installed.
The tools are aptitude-create-state-bundle and
aptitude-run-state-bundle.

Create the package and configuration state on the running host:

  1. hostname:~#
  2. hostname:~# aptitude-create-state-bundle /mnt/debinst/var/backups/aptitude_state
  3. hostname:~#

By using this file the packages can be reproduced in the chrooted system.
The packages file and bzip2 need to be pre-installed for the restore.

  1. CHROOTED:~::>~
  2. CHROOTED:~::>~ aptitude install file bzip2
  3. [ aptitude does its job ]
  4. CHROOTED:~::>~ aptitude-run-state-bundle /var/backups/aptitude_state
  5. CHROOTED:~::>~ aptitude update
  6. CHROOTED:~::>~ aptitude install
  7. [ stuff rushes by and configuration panels pop up. for example the grub config ]
  8. CHROOTED:~::>~

Note that it is not easily possible to sort of upgrade your operating system on the fly like this. Taking the package state and replaying it on the fresh system will only work when your are on the same major release. If you host is on Lenny and your fresh system on Squeeze, then aptitude-run-state will choke a lot an will eventually abort, leaving you with a mess.

If you wish to transfer your packages with this method, it is recommended to install the same major release with debootstrap, transfer the package state and perform a dist-upgrade after that.

BTW, a nice overview over the apt and dpkg system state files can be found here.

If your curently running system is not Debian based, you’ll have to find a way to recreate your packages. YMMV.

Installing grub

The last step also installed the grub package and came up with a configuration panel. It was not be able to completely determine the disk devices and asked where grub should be installed. I installed grub onto /dev/sdb.

It is a good idea to check /boot/grub/grub.cfg and take a close look at the disk IDs that are used, since you might be swapping the hard drives or changing the RAID configuration, resulting in a change of the sda and sbd naming schema. UUIDs will stay the same, no matter whether the disk is primary master oder secondary slave. Using UUIDs reduces confusion.

If you find any occurrance of /dev/sda or /dev/sdb, you might want to change that into the respective UUIDs. Note that grub.cfg is being generated by update-grub, so your changes will be lost. But that is okay, since everything should be fine with the disk device symlinks by udev once you boot into the new system.

If you want to keep the current disk, but would like to boot from the fresh system, you can run update-grub on the host. It will recognize the new system on the fresh disk and will generate a grub entry for this system as well. Again, check whether UUIDs are being used in /boot/grub/grub.cfg and correct if neccessary.

Migrating data

This step obviously depends a lot on what software you have installed and how this data needs to be transferred. Using rsync -avR might be a good idea. Good candidates for directories that should be copied are /home, /var/www, /var/mail, /var/spool, /srv, /etc, /usr/local/bin, but as said, this really depends on what you have installed on your machine. Be aware that trailing slashes are significant with rsync and that rsync -avR /sourcedir /targetdir is different from rsync -avR /sourcedir/ /targetdir. Also when telling rsync to do deletes on the target it is recommended to --dry-run and check whether it is doing the right thing.

I have the habit of versioning my config files with rcs. The Revision Control System is pretty simple and only works locally on single files. No remote distributed mumbo jumbo. Simply mkdir a RCS directory and ci -l file.conf to make a revision. I am using two scripts to manage my versioned files and to make backups of those.

If you copy the backup over to the chrooted directory /mnt/debinst/var/backups/rcs and unpack into your chrooted system, you can easily recall your configurations and settings.

If you do not migrate the user accounts and leave /etc/passwd the way debootstrap set it up, then you should set the root password of your chrooted system, otherwise you will not be able to log into the new system.

Reboot

Before the first reboot into the new system it might be a good idea to deactivate certain services. For example if you are using fetchmail, I would deactivate that via /etc/defaults/fetchmail.

Just in case.
“In case of what?”, you ask?
JUST IN CASE!

Chances are you forgot something or some stupid error makes you want to repeat the whole procedure from scratch. If your system processed some real life data after the first experimental boot, you might have a tough time repairing this.
The reason why you chose debootstrap over the default debian installer was the required uptime of a real life system, right?
Be careful. Think twice. Don’t hurry.

Now it is time to reboot into your fresh and shiny new system. If you kept the old disk, you should select the additional grub entry the update-grub script entered into your grub.cfg. Carefully watch the boot process for failures. These are pointers to chunks of data and configurations which have not been migrated correctly.

I deliberately swapped the two disk images from primary slave to primary master and vice versa simply to make sure the grub installation on the new system really works (compare with above):

  1. CHROOTED:~::>~ ls -l /dev/disk/by-uuid/
  2. insgesamt 0
  3. lrwxrwxrwx 1 root root 10 18. Nov 2010 409a1d6b-a668-4b96-9ae9-22975e5debb4 -> ../../sdb1
  4. lrwxrwxrwx 1 root root 10 18. Nov 2010 6dc8fa2f-744c-47a9-b64f-05e8c9c318c2 -> ../../sdb5
  5. lrwxrwxrwx 1 root root 10 18. Nov 2010 8eaf21d0-c7b4-45cf-9e59-35187eac7939 -> ../../sda5
  6. lrwxrwxrwx 1 root root 10 18. Nov 2010 a246d75a-d8e4-41c7-984c-0e4d3bead43f -> ../../sda1
  7. CHROOTED:~::>~

Cleanup

After the new system is running, it is a good idea to invoke aptitude update and aptitude safe-upgrade to make the APCI work.

If neccessary, mount the old disk read only and copy the files and data you were missing.

Copy the root directory, change the hostname and your prompt, cleanup.

  1. CHROOTED:~::>~ mkdir /mnt/oldsystem
  2. CHROOTED:~::>~ mount -o ro /dev/sdb1 /mnt/oldsystem
  3. CHROOTED:~::>~

Comments, corrections and additions are welcome.


KOMMENTARE / WERDEN MODERIERT

Return to Top

Installing a Debian based Linux with debootstrap

AKTUELLES

9. February 2012

generic (feed #3)
08:20 via Twitter