Thursday, February 13, 2020

Running Linux VMs in MacOS

Recent versions of MacOS come with the hypervisor framework which makes virtualization possible.  Not necessarily easy, but possible.  Here are the steps I took to get a raw CentOS8 VM running on my system:

1. Install Multipass from Canonical.  This is geared towards running Ubuntu images, so if that's all you're after, you're done!  I use the hyperkit executable it includes to launch my CentOS image rather than trying to compile hyperkit or xhyve myself.
  https://multipass.run/
Note: The version of hyperkit that comes with Multipass cannot boot kernels newer than 4.16 at the time of writing.  Once Ubuntu 20.04 comes out, I'm hoping that will change, which will allow us to use it on CentOS8 kernels as well.  Until then, this cannot be used to install CentOS8.

2. Download your Linux install iso.  I downloaded the NetInstall iso from http://mirror.ash.fastserv.com/centos/7.7.1908/isos/x86_64/

3. While you're waiting on the download, create your sparse virtual disk.
I usually create a 16G sparse file for that.  16G is 16777216 kibibytes.
  dd of=centos7.img bs=1024 count=1 seek=16777215 < /dev/zero
To see that this doesn't actually consume 16G of disk, use the -sl option s for ls, which should show 8 512-byte sectors are allocated. You can also use mdls to see the physical disk size, which should show a single 4k block is allocated.
4. Mount the install image.  This is a little complicated.  Because this is a bootable image, the first few sectors with the MBR need to be blanked out before hdiutil recognizes the ISO9660 partitions it contains.  However, we'll need the MBR later when we go to actually install from it.  Fortunately, via APFS, we have a way to create the modified image without taking up twice the disk space.  This uses the clonefile API call via the 'cp -c' option so changes are copy-on-write (COW).
  ln -s ~/Downloads/CentOS-7-x86_64-NetInstall-1908.iso netinst.iso
  cp -c netinst.iso tmp.iso
  dd if=/dev/zero of=tmp.iso bs=2048 count=1 conv=notrunc
  hdiutil attach tmp.iso
Make note of the mount point it displays and the path of its device file for use in the next step

5. Copy the installer kernel and initrd and clean up.  You may have to poke around in the mounted filesystem for the right location.  For the NetInst install disk, it was in the isolinux directory.
  cp /Volumes/CentOS\ 7\ x86_64/isolinux/{vmlinuz,initrd.img} .
  hdiutil eject /dev/disk2
  rm tmp.iso

6. Launch the installer. 
  sudo "/Library/Application Support/com.canonical.multipass/bin/hyperkit" -A -c 1 -m 2G -s 0,hostbridge -s 1,lpc -l com1,stdio -s 3,virtio-net,eth0 -s 4,ahci-cd,netinst.iso -s 2,virtio-blk,centos7.img -f "kexec,vmlinuz,initrd.img,earlyprintk=serial console=ttyS0"


- setup network first, take note of DHCP-assigned gateway (eg. 192.168.64.1)
- use installation source of http://mirror.centos.org/centos/7/os/x86_64/
- I find it easiest to set the install destination as a standard partition, YMMV
- Do not reboot when prompted after the system is installed

7. Drop to a shell before reboot to save your kernel/initrd files.  In Terminal.app, toggle Edit / Use Option as Meta Key, then use Option-Tab to switch between 5 virtual terminals, one of which is a root shell.  Copy the system's installed kernel/initrd to host (from root shell in installer environment).
  scp /mnt/sysimage/boot/vmlinuz* /mnt/sysimage/boot/initramfs* youruser@192.168.64.1:your/path

8. Complete install.  Option-Tab back to the installer prompt and reboot to complete the installation.  Uncheck Use Option as Meta Key in Terminal.app before you forget...

9. Using the vmlinuz-? and initramfs-? files you copied right before completing the install, boot into your new system.
  sudo "/Library/Application Support/com.canonical.multipass/bin/hyperkit" -A -c 1 -m 2G -s 0,hostbridge -s 1,lpc -l com1,stdio -s 3,virtio-net,eth0 -s 2,virtio-blk,centos7.img -f "kexec,vmlinuz-3.10.0-1062.el7.x86_64,initramfs-3.10.0-1062.el7.x86_64.img,earlyprintk=serial console=ttyS0 root=/dev/vda3"

10. Whenever you update the kernel, remember to copy the updated vmlinuz and initramfs files onto the host to use on the next boot.