Preparing Virtual Machine files for export

Virtual machine export

This entry reports on step taken to transfer virtual machine (VM) running on FMF server to a new host.

Original setup

On FMF, the virtual machine runs with virsh manager under XEN virtualization.

Disk images

First prepare dd dumps of the disks. In our case, a single disk gets exported, that is /. The exact command was used by Feri, probably something like:

dd if=/dev/virtual-machines/med0/slash of=med0-root.raw bs=512K

The files are then zipped for easier copying:

gzip med0-root.raw

The whole process leaves us with a single file med0-root.raw.gz sized at approximately 7 GB.

Inserting master boot record (MBR)

There are two problems with using raw exported images from XEN. One is, that XEN is much smarter then other virtual machines, but much more tedious to use. The smarter part allows it to pick up the boot images directly from disk without the need for an MBR, acronym for a master boot record. Other virtualization software mimics behavior of non-virtual machines which rely on MBR to help it find operating system images. So we have to create an MBR. An excellent account of all listed procedures can be found Filippo.io[here].

To do that, the disk should have enough space at the begining to put MBR on. Our raw image doesn't have any additional space, so we have to create it by starting a new disk:

dd if=/dev/zero of=new.raw count=1 bs=1MiB

I followed Filippo's advice and checked for disk layout of my laptop:

# sudo fdisk /dev/sda
Command (m for help): p
Units: sectors of 1 * 512 = 512 bytes
[..]
Device      Boot    Start   End Sectors Size    Id  Type
/dev/sda1   *   2048    206847  204800  100M    7   HPFS/NTFS/exFAT
[..]

Command (m for help): q
#

It seems 2048 sectors of 512 bytes each or 1 MB is enough, which is what I have put in my dd command. Then we append the rest of the (unzipped) disk:

pv med0-root.raw >> new.raw

pv is a nifty command essentially identical to cat with a progress bar. After 10 minutes, our raw disk has now some unpartioned bytes at its head, and we have to repartition the image with fdisk:

# sudo fdisk new.raw

[..] 

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xd2df1593.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-62916607, default 2048):<Enter> 
Last sector, +sectors or +size{K,M,G,T,P} (2048-62916607, default 62916607):<Enter>

Created a new partition 1 of type 'Linux' and of size 47.5 GiB.

Command (m for help): a
Selected partition 1
The bootable flag on partition 1 is enabled now.

Command (m for help): p
Disk new.img: 30 GiB, 32213303296 bytes, 62916608 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xd2df1593

Device     Boot Start      End  Sectors  Size Id Type
new.raw   *     2048 62916607 62914560   30G 83 Linux


Command (m for help): w
The partition table has been altered.
Syncing disks.

To add a bootloader, we have to mount our disk to get access to the data. We will use the loop device:

# sudo kpartx -a -v new.raw
add map loop0p1 (253:0): 0 62914560 linear 7:0 2048
# mkdir merlin
# sudo mount /dev/mappar/loop0p1 merlin
# sudo grub-install --target=i386-pc --recheck --debug --boot-directory=merlin/boo /dev/loop0
Installing for i386-pc platform.
[..]
Installation finished. No error reported.

Grub2 does its own configuration, so we will need to chroot into our disk. For that we will also have to mount some services.

# sudo mount -t proc proc merlin/proc
# sudo mount -t sysfs sys merlin/sys
# sudo mount -o bind /dev merlin/dev
# sudo chroot merlin

Since /etc/resolv/conf might be very different than our host pc, we should make sure the nameservers are accessible, or we should add our own.

# sudo vi /etc/resolv.conf 
# sudo dpkg-query -l | grep grub2-common # if none is find, install
# sudo apt-get install grub2-common
# grub-mkconfig -o boot/grub/grub.cfg

The grub-mkconfig also found bootable sections on my /dev/sda hard drive. We can get rid of them later.

Some house-keeping tasks - check that disks that are not part of the VM transfer will not be mounted - do that by commenting out disks which are missing. In our case, /data partition will not be transfered, so we comment out that line from /etc/fstab. Also, since boot will depend on it, note the serial number of the disk that will be mounted as /:

# vi /etc/fstab
# <file system> <mount point> <type> <options> <dump> <pass>
UUID=2f2e0fb3-72e7-454e-ade2-56612df86b99 / xfs defaults 0 1
UUID=8fd49631-5a8d-467f-bbcf-93aa2a471175 none swap sw 0 0
# comment out data
#UUID=c3bd9b07-9073-48f8-9e20-478668c4511d /data xfs defaults 0 1

Also, to not swamp IP address, make sure that network is set to dhcp:

# vi /etc/network/interfaces
[..]
#Primary static address
auto eth0

#set to dhcp
iface eth0 inet dhcp
#Autoconfigured IPv6 interface
iface eth0 inet6 auto

The setup is done. Clean and exit

# exit
# sudo umount merlin/proc merlin/sys merlin/dev merlin
# kpartx -d -v new.raw
del devmap: loop0p1
loop deleted /dev/loop0
# rmdir merlin
# mv new.raw merlin.raw

Changing format of the raw disk

The second problem is that VirtualBox (and other user-friendly virtualization software) can't use raw disks directly. VirtualBox comes with a set of tools that make transition relatively painless. The fact is, however, that we need another space for another full disk.

To change to VDI format, we run:

# VBoxManage convertdd merlin.raw merlin.vdi --format vdi

VDI is a s short name for VirtualBox Disk Image. It is the format of files used to relay virtual disks for VirtualBox desktop virtualization manager. Since VirtualBox is open source, it runs everywhere and will be used as a translator of raw disk images to virtual machine packages that are easy to transport and reuse.

The last step is that VBoxManage will stamp merlin.vdi with a random identification number, UUID. To match the one set in /etc/fstab we have to correct it by hand:

# VBoxManage internalcommands sethduuid merlin.vdi 2f2e0fb3-72e7-454e-ade2-56612df86b99

Notice that the used number matches the one read from /etc/fstab.

Getting the swap disk

Create an empty space and format it as swap.

# dd if=/dev/zero of=swap.raw count=1 bs=2GiB
# cp swap.raw swap1.raw
# pv swap1.raw >> swap.raw
# pv swap1.raw >> swap.raw
# pv swap1.raw >> swap.raw
# sudo fdisk swap.raw
Welcome to fdisk (util-linux 2.27.1).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.


Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-16777183, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-16777183, default 16777183):

Created a new partition 1 of type 'Linux' and of size 8 GiB.

Command (m for help): t
Selected partition 1
Partition type (type L to list all types): 83
Changed type of partition 'Linux' to 'Linux'.

Command (m for help): p
Disk swap.raw: 8 GiB, 8589918208 bytes, 16777184 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xe9aa9bd9

Device     Boot Start      End  Sectors Size Id Type
swap.raw1        2048 16777183 16775136   8G 83 Linux

Command (m for help): w
The partition table has been altered.
Syncing disks.

Now we have to mount it to format it:

# sudo kpartx -a -v swap.raw
add map loop0p1 (253:0): 0 16775136 linear 7:0 2048
# sudo mkswap /dev/mapper/loop0p1 -U 8fd49631-5a8d-467f-bbcf-93aa2a471175 -L swap@merlin 
Setting up swapspace version 1, size = 8 GiB (8588865536 bytes)
LABEL=swap@merlin, UUID=8fd49631-5a8d-467f-bbcf-93aa2a471175
# sudo kpartx -d -v swap.raw
del devmap : loop0p1
loop deleted : /dev/loop0

Convert it to the vdi format for VirtualBox:

# VBoxManage convertdd swap.raw swap.vdi --format vdi
# VBoxManage internalcommands sethduuid swap.vdi 8fd49631-5a8d-467f-bbcf-93aa2a471175

Create a dummy data disk & partition

Create a small data partition for testing. Create it via

# dd if=/dev/null of=data.raw bs=10M seek=1024 count=0
# fdisk data.raw
Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1):
First sector (2048-20971519, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-20971519, default 20971519):

Created a new partition 1 of type 'Linux' and of size 10 GiB.

Command (m for help): w
The partition table has been altered.
Syncing disks.
# sudo kpartx -a -v data.raw
# sudo mkfs -t xfs -L data /dev/mapper/loop0p1
# sudo xfs_admin -U c3bd9b07-9073-48f8-9e20-478668c4511d /dev/mapper/loop0p1
# sudo kpartx -d -v data.raw
# VBoxManage convertdd data.raw data.vdi --format vdi

The same UUID as in /etc/fstab was created.

Configuring the VM

Now we are ready to run the virtual machine through VBox. When creating the machine, select "Use existing disk" when prompted for disk configuration and navigate to merlin.vdi. Then, before you start the machine, go to Storage part of the configuration and add swap.vdi. Start the machine.

Keep network settings at NAT, under Advanced/Port Forwarding add:

  • Name:http, Protocol: TCP, Host Port: 38080, Guest Port: 8080
  • Name:ssh, Protocol: TCP, Host Port: 3022, Guest Port: 22

Leave other variables blank.

Adding XPRA for X usage in bare server

Install xpra via apt:

# apt-get install xpra
# apt-get install libpulse-mainloop-glib0 libnss3 libasound2

Since Xorg is picky, go to xpra configuration file and modify link to executable to point to /usr/lib/xorg/Xorg rather than the default /usr/bin/Xorg which is in path:

# vi /etc/xpra/xpra.conf
[..]
# Selecting virtual X server:
xvfb =  /usr/lib/xorg/Xorg -noreset -nolisten tcp +extension GLX +extension RANDR +extension \
         RENDER -auth $XAUTHORITY -logfile \
         ${HOME}/.xpra/Xorg.${DISPLAY}.log -configdir \
         ${HOME}/.xpra/xorg.conf.d -config /etc/xpra/xorg.conf
[..]

Then one can start an application that requires X by stating:

xpra start :100 --start-child="your-command" --exit-with-children

Install DICOM server

Get Slicer. Unpack and link:

# cd software/install
# tar xvzf [..]/Slicer-X.Y.[..].tar.gz
# ln -s Slicer-X.Y.[..] Slicer

Get labkeySlicerPythonAPI and dicomServer as nixUser:

# cd ~/software/src
## if you have access to f9.ijs.si:
# git clone studen@f9pc22.ijs.si:~/public_html/git/serverDicom.git
## public access
# git clone https://www-f9.ijs.si/~studen/git/serverDicom.git
# git clone git@wiscigt.powertheword.com:andrej.studen/labkeySlicerPythonAPI.git

Run Slicer once as tomcat8 so that .ini files get created:

# export DISPLAY=:100; 
# xpra info $DISPLAY > ~/.xpra/temp.log || xpra start $DISPLAY; 
# /home/nixUser/software/install/Slicer/Slicer
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-tomcat8'
Switch to module:  "Welcome"
# Ctrl-C

Find the latest Slicer-NNNN.ini file in ~/.config/NA-MIC directory, edit Additional Paths variable:

# vi ~/.config/NA-MIC/Slicer-27952.ini
[..]
[Modules]
AdditionalPaths=/home/nixUser/software/src/labkeySlicerPythonAPI/labkeySlicerPythonExtension
IgnoreModules=@Invalid()
[..]

Add script startDicom.sh to ~tomcat8/bin:

#!/bin/bash

UHOME=/home/nixUser

DICOMSERVER=$UHOME/software/src/dicomServer
PYTHONPATH=$PYTHONPATH:$DICOMSERVER
SLICER=$UHOME/software/install/Slicer

DICOMDATABASE=/data0/dicom/database/server.sql
DISPLAYID=100

export DISPLAY=:$DISPLAYID
TEMP=~/.xpra/temp.log
#make sure xpra is running a virtual buffer at DISPLAY

xpra info $DISPLAY > $TEMP || xpra start $DISPLAY;

$SLICER/Slicer --no-main-window --python-script $DICOMSERVER/dicomServer.py $DICOMSERVER $DICOMDATABASE

Resizing the data disk

After resizing, sizes above 2TiB can be encountered, where dos/MBR partition table fails. First we switch from MBR to a more recent version of partioning table called GPT.

First we unmount the disk:

>>sudo umount /data

Status:

>> sudo fdisk /dev/sdc
Command (m for help): p
Disk /dev/sdc: 3 TiB, 3298534883328 bytes, 6442450944 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xaf352020

Device     Boot Start        End    Sectors Size Id Type
/dev/sdc1        2048 4273492457 4273490410   2T 83 Linux

We will have to delete the /dev/sdc partition and replace it with a gpt partition

Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.

The size of this disk is 3 TiB (3298534883328 bytes). DOS partition table format can not be used on drives for volumes larger than 2199023255040 bytes for 512-byte sectors. Use GUID partition table format (GPT).

Command (m for help): g

Created a new GPT disklabel (GUID: 81F2CA1E-E1D0-41F3-A42F-0F7360ABCE52).

Command (m for help): p
Disk /dev/sdc: 3 TiB, 3298534883328 bytes, 6442450944 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 81F2CA1E-E1D0-41F3-A42F-0F7360ABCE52

Command (m for help): n
Partition number (1-128, default 1):
First sector (2048-6442450910, default 2048):
Last sector, +sectors or +size{K,M,G,T,P} (2048-6442450910, default 6442450910):

Created a new partition 1 of type 'Linux filesystem' and of size 3 TiB.
Partition #1 contains a xfs signature.

Do you want to remove the signature? [Y]es/[N]o: N

Command (m for help): p

Disk /dev/sdc: 3 TiB, 3298534883328 bytes, 6442450944 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 81F2CA1E-E1D0-41F3-A42F-0F7360ABCE52

Device     Start        End    Sectors Size Type
/dev/sdc1   2048 6442450910 6442448863   3T Linux filesystem

Some complaining:

The partition table has been altered.
Calling ioctl() to re-read partition table.
Re-reading the partition table failed.: Device or resource busy

The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8).

Install parted if it is not already there and run

>>sudo partprobe

Command gives no output, but the disk sizes are changed:

Disk /dev/sdc: 3 TiB, 3298534883328 bytes, 6442450944 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 81F2CA1E-E1D0-41F3-A42F-0F7360ABCE52

Device     Start        End    Sectors Size Type
/dev/sdc1   2048 6442450910 6442448863   3T Linux filesystem

Now we can grow the XFS file system and we are done. It seems that /data mounted quitely during one of the previous command, since:

>> df -h
Filesystem      Size  Used Avail Use% Mounted on
udev            3.9G     0  3.9G   0% /dev
tmpfs           799M  8.7M  791M   2% /run
/dev/sda1        30G   18G   13G  57% /
tmpfs           4.0G  4.0K  4.0G   1% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
tmpfs           4.0G     0  4.0G   0% /sys/fs/cgroup
/dev/sdd1       100G   83G   18G  83% /data1
tmpfs           799M     0  799M   0% /run/user/1001
/dev/sdc1       2.0T  2.0T   75G  97% /data

Now we do:

>>sudo xfs_grow /data

which results in:

>>df -h
/dev/sdc1       3.0T  2.0T  1.1T  64% /data

links

social