Using Multipass with cloud-init
I upgraded my MacBook Pro to macOS Big Sur last week. Even though most of the applications worked fine, I encountered a few compatibility issues, which are expected for a new OS release. One of those issues was Docker not playing nice with VirtualBox. So I uninstalled VirtualBox and updated Docker. Before reinstalling VirtualBox, I thought maybe it would be a good idea to check what else is out there for creating development VMs on macOS. And that’s how I stumbled upon Multipass, Canonical’s take on quickly creating Ubuntu VMs on macOS, Windows and Linux.
There were a couple of things that I found interesting about Multipass. First, it uses the native hypervisor in macOS, and second, it can take cloud-init YAML files to configure the VMs.
So I installed Multipass using Homebrew:
% brew install multipass
After the installation, I noticed that there was a UI tool also installed with it. I launched it and selected Shell from the menu. It downloaded the latest Ubuntu 20.04 LTS, created the default “primary” VM and dropped into the shell — within seconds. The whole process was lightweight and quick.
It took me some time to get familiar with the command line options of Multipass, and after playing around with creating and deleting some test VM’s (including one with X11 forwarding over SSH to launch GUI Linux applications in macOS), I started looking into the cloud-init integration to make the entire process of creating and deleting a custom development VM as simple as possible.
My key requirements for a development VM were:
- SSH into the VM using the SSH public key authentication
- Upgrade all packages
- Install avahi-daemon to enable mDNS, so that I could use vmname.local instead of IP address to connect to the VM
- A minor convenience — create an alias for future manual updates
These requirements translated into this cloud-config.yaml cloud-init file:
#cloud-config
users:
- default
- name: ubuntu
gecos: Ubuntu
sudo: ALL=(ALL) NOPASSWD:ALL
groups: users, admin
shell: /bin/bash
ssh_import_id: None
lock_passwd: true
ssh_authorized_keys:
- <SSH public key from macOS>
package_update: true
package_upgrade: true
packages:
- avahi-daemon
write_files:
- content: |
# custom
alias update='sudo apt update && sudo apt upgrade && sudo apt dist-upgrade && sudo apt autoremove && sudo apt auto-clean'
path: /etc/skel/.bashrc
append: true
Then I created mkvm script to create the VM and SSH into it:
#!/bin/zshVM_NAME=$1/usr/local/bin/multipass launch -n $VM_NAME --cloud-init ./cloud-config.yaml
/usr/bin/ssh ubuntu@$VM_NAME.local
And rmvm script to delete the VM and remove it from known hosts:
#!/bin/zshVM_NAME=$1/usr/local/bin/multipass delete $VM_NAME
/usr/local/bin/multipass purge
/usr/bin/ssh-keygen -R $VM_NAME.local
And now I am all set to create and delete VMs with a single command:
% ./mkvm bilal-dev
% ./rmvm bilal-dev
It is great to have a lightweight tool to quickly create Ubuntu VMs on macOS. Multipass does the basics — it doesn’t have features like “snapshots”, and “suspend” doesn’t work with the native macOS hypervisor right now. But it is very fast, and the cloud-init integration is awesome. Multipass can also be used with VirtualBox as the hypervisor (which also enables suspend). Overall, it is a very promising tool for developer productivity.