Virtual develop environment with xhyve
Install Ubuntu on xhyve
Prepare the kernel and initrd
Because xhyve does not support BIOS or EFI booter. We need to pass the kernel and ramdisk file to xhyve manually.
Since OS X does not recognize the file system of Ubuntu ISO. We need a little hack to mount it.
Create a cloned ISO file named /tmp/tmp.iso of Ubuntu ISO disk.
$ dd if=/dev/zero bs=2k count=1 of=/tmp/tmp.iso
$ dd if=ubuntu.iso bs=2k skip=1 >> /tmp/tmp.iso
Now we can mount the ISO file to copy the necessary files:
$ hdiutil attach /tmp/tmp.iso
The ISO file now mounted at "Ubuntu-Server 14" volume.
$ cp /Volumes/Ubuntu-Server\ 14/install/vmlinuz .
$ cp /Volumes/Ubuntu-Server\ 14/install/initrd.gz .
Create virtual hard disk image
Create a virtual hard disk image so you can install your Linux distro on it. In this post, we create a 3GB disk named hdd.img
$ dd if=/dev/zero of=hdd.img bs=1g count=3
Create start up script for Ubuntu installation
Now, we create a new bash script to init and start up a virtual machine with xhyve, that use our hdd.img as a virtual hard disk and ubuntu.iso as a virtual CD. Then install Ubuntu to the virtual hard disk.
up.sh
#!/bin/sh
KERNEL="vmlinuz"
INITRD="initrd.gz"
CMDLINE="earlyprintk=serial console=ttyS0 acpi=off"
MEM="-m 1G"
NET="-s 2:0,virtio-net"
IMG_CD="-s 3,ahci-cd,ubuntu.iso"
IMG_HDD="-s 4,virtio-blk,hdd.img"
PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
LPC_DEV="-l com1,stdio"
xhyve $MEM $PCI_DEV $LPC_DEV $NET $IMG_CD $IMG_HDD -f kexec,$KERNEL,$INITRD,"$CMDLINE"
Don't forget to chmod the script file, so you can execute it:
$ chmod +x up.sh
Start your virtual machine and install Ubuntu in text mode installer:
$ sudo ./up.sh
You have to run with sudo because virtio-net required root permission.
At the very end of the installation, don't forget to choose "Install the GRUB boot loader to the master boot record"
When you reach "Installation complete" screen, select "Go back" and choose "Execute a shell" to config copy installed kernel and initrd to Mac. Enter this to VM:
$ cd /target
$ sbin/ifconfig
$ tar c boot | nc -l -p 1234
Then back to Mac, enter this:
$ nc [IP] 1234 | tar x
As [IP] is the IP address you saw in VM ifconfig command.
Now, exit shell mode in VM
$ exit
And select "Finish the installation" to finishing up your Ubuntu Guest.
The Linux kernel from your virtual disk has been copied to your Mac's boot folder.
Modify start up script to boot Ubuntu from virtual hard disk
Now, modify the up.sh script to make it boot from installed Ubuntu in virtual hard disk instead of CD image.
up.sh
#!/bin/sh
KERNEL="boot/vmlinuz-3.16.0-30-generic"
INITRD="boot/initrd.img-3.16.0-30-generic"
CMDLINE="earlyprintk=serial console=ttyS0 acpi=off root=/dev/vda1 ro"
MEM="-m 1G"
NET="-s 2:0,virtio-net"
IMG_HDD="-s 4,virtio-blk,hdd.img"
PCI_DEV="-s 0:0,hostbridge -s 31,lpc"
LPC_DEV="-l com1,stdio"
xhyve $MEM $PCI_DEV $LPC_DEV $NET $IMG_HDD -f kexec,$KERNEL$INITRD,"$CMDLINE"
Now, start your virtual machine with:
$ sudo ./up
To shutdown the VM and go back to Mac terminal, enter:
$ sudo halt
Now your virtual machine is ready! Time to go to next step: Setting up develop environment.
Our target is to build something like Vagrant, which allow you create a virtual environment that linked to the folder on Host. So we can do anything with that virtual environment without damaging Host machine.
Setup dev environment on your Ubuntu Guest
It depends on which development environment you want to setup, maybe you want to install LAMP, or MEAN, or Ruby on Rails.
Synching shared folder from Host to Guest
To share a folder from host OS to guest OS, you have to setup NFS server on host and mount it in guest OS.
Setup NFS Server on Host
On Mac OS X, you have to create file /etc/exports to config which folder you want to share via NFS Server.
$ sudo touch /etc/exports
Then put the shared folder path in that file with the following syntax:
<Folder path> -mapall=501
Don't forget to use sudo when editing your exports config:
$ sudo vi /etc/exports
Folder path is the full path to your shared folder. Mapall parameter tell NFS Server that which user has permission to access that folder. In this case, 501 is your current (and default) user ID.
To see your user ID, enter:
$ id
Example /etc/exports file:
/Users/huy/Shared -mapall=501
Now, run the NFS Server with the following command:
$ sudo nfsd enable
If you already have NFS Server started up, you will want to restart it to make the new config available:
$ sudo nfsd restart
Now, you have your folder shared and will be visible with the Guest OS.
To check if it is available or not, run this command:
$ showmount -e
This will list all exported (shared) folder you have configured on Host.
Mount the folder on Guest
Before mounting NFS server on Guest OS, we have to install a NFS client package first.
Run this command on Guest:
$ sudo apt-get install rpcbind nfs-commond
Now you will be able to mount any folder from NFS Server (Host) by enter the following command:
$ sudo mount -o nolock -t nfs <host-ip>:/<folder-path> <target-parth>
For example, this command will mount /Users/huy/Shared folder from host, which has IP 192.168.64.1 to ~/Shared folder in Guest OS.
$ sudo mount -o nolock -t nfs 192.168.64.1:/Users/huy/Shared ~/Shared
Now, you have your virtual machine linked with a real folder on your Mac host.
In the next section, we will see how to use this develop environment in your real life projects.
Using virtual dev environment
In this section, we will use our dev environment to run a simple HTTP server with Python to serve a simple web page.
Prepare the dev folder on host
On host machine, create a project folder, let's say:
/Users/huy/Code/helloPy/
Export this to /etc/exports file:
$ sudo vi /etc/exports
/etc/exports
...
/Users/huy/Code/helloPy/ -mapalls=501
And restart the NFS Server:
$ sudo nfsd restart
Mount and run HTTP server on Guest
On Guest VM, mount the project folder to somewhere, with the following command:
$ sudo mount -o nolock -t nfs 192.168.64.1:/Users/huy/Code/helloPy/ ~/Code/helloPy
Then, move to that folder and run the HTTP server:
$ cd ~/Code/helloPy
$ python -m SimpleHTTPServer
The server will run at port 8000 on Guest OS.
To get Guest's IP, run this command:
$ ifconfig
For example, the Guest VM has IP: 192.168.64.2
We can access the web server from Host machine by entering this address: http://192.168.64.2:8000/
Coding from Host and sync to Guest's HTTP server
You can use your favorite editor (such as Sublime, Atom, WebStorm,...) and modify the code, then refresh the web page you can see the result.
That's how we use it!
From now, you can create as much server as you want, running as many stack as you can without messing up your Host machine.