I first learned about libvirt
and QEMU
three years ago when I wrote a guide on how to virtualize macOS on a Linux system. Today I will be showing the opposite, virtualizing Linux on macOS using the same tools. I was surprised that with so many software developers using MacBooks everyday, nobody has created a guide on how to use libvirt
and QEMU
with macOS.
Why is libvirt
and QEMU
better? First of all, it's free and open-source. Unlike Parallels Desktop and VMWare Fusion, you won't need to pay for expensive subscriptions or manage licenses. There does exist an open-source alternative (from Oracle!) called VirtualBox, which works pretty well. However, VirtualBox does not support macOS's Hypervisor.Framework, a virtualization API created to limit kernel modification. This means the installer will ask for admin access to install kernel extensions, a feature Apple is now phasing out for security reasons. QEMU
on the other hand has had support for Hypervisor.Framework since 2018. Just say no to kexts!
Furthermore, like many developers, I like to run VMs headless, i.e. without a desktop GUI, so that I can SSH into them. Running VMs in the background seems like a simple feature, but it requires a lot of complex configuration for both VirtualBox and VMWare Fusion. And Parallels wants you buy the Pro Edition to gain access. Market segmentation at its finest... With libvirt
, VMs start headless. Plus, when you shutdown macOS, it sends a shutdown signal to your VMs as well.
Homebrew Docker Virtualbox (But not only VirtualBox) Installation Install Virtualbox from Oracle website Install the docker-virtualbox via Homebrew Configure the docker-virtualbox requirements Configure the environment Initialize the docker machine Start the docker-virtualbox service Verify installation Additional information Known issues. $ brew cask install virtualbox Now install Vagrant either from the website or use homebrew for installing it. $ brew cask install vagrant Vagrant-Manager helps you manage all your virtual machines in one place directly from the menubar. $ brew cask install vagrant-manager Usage.
To be clear, this method doesn't support USB Passthrough, GPU Passthrough, or bridge networking. But if you just need to test, for example, node.js or nginx on a Linux VM, then this method is great.
Installing libvirt and QEMU
- First, install homebrew, which is a package manager for macOS.
- Run
brew install qemu gcc libvirt
. - Since macOS doesn't support QEMU security features, we need to disable them:
- Finally start the libvirt service, with
brew services start libvirt
. It will start after boot as well.
Installing Ubuntu Server 20.04
There are two ways to access the virtual display of the VM, either using a VNC client or the virt-viewer program. I recommend RealVNC Viewer. The VNC client is responsive and quick to install, but if you have multiple VMs you need to manually manage the different ports. With virt-viewer, you get a popup with all the VMs currently running, but it is laggy and takes an eternity to install. virt-viewer can be installed through homebrew. The rest of this guide uses VNC.
Create a
vms
folder in your home directory, and generate a disk image. Change50g
to the size of your prefered disk:Download the Ubuntu Server 20.04 Install Image and my libvirt XML template and place the .iso and .xml files in the same folder.
Modify the following elements in the
ubuntu.xml
file to match your your VM preferences and file paths. Save, then runvirsh define ubuntu.xml
followed byvirsh start ubuntu
.Start RealVNC Viewer and connect to
localhost
. Click theCtrl+Alt+Del
button to reboot the machine, and quickly pressEsc
to get into the boot menu. Press the number that matches the Ubuntu Server image.Install Ubuntu Server normally, making sure to enable the SSH server. Once it restarts you can connect to the VM from your terminal by running
ssh -p 2222 user@localhost
.To send a shutdown signal to your VM, run
virsh shutdown ubuntu
. To force shutdown, runvirsh destroy ubuntu
.To forward a port, e.g. port 443 from the VM to port 8443 locally, run the following:
ssh -p 2222 -L8443:localhost:443 user@localhost
Multiple VMs
If you want to create multiple VMs, create an XML file for each machine with a unique UUID, VM name, and VNC port. Also, change the hostfwd
argument so that each VM exposes a different port for SSH, e.g. 2223
instead of 2222
. After you have defined them all, you can get a list of the VMs that are currently running with virsh list
.
References:
Note: More discussion on Hacker News
What is Docker?
Docker is the next step on long IT containerization way. What does it mean? Years ago, you could run each application/process in particular container, that application couldn’t go outside the container which it was run. It was very safe but difficult to manage and not sharable. So you couldn’t easy share your container to other machine or to other developers to reuse for example by open source community.
So, that solution was a little bit complicated and worked only on Linux. Today we have Docker, which allows you to run containers on all operation systems. What is important, this tool is not only modern but also easy to manage and easy to share to others developers.
[toc]
Other ways to install it
In this post, I want to show you how to install Docker by using brew
which installation process I wrote last time. For me, it’s the easiest and safest way. But there are a few other possibilities to install it on Mac OS.
Docker.com – first method
First what you have to do is to go to Docker website and just download and run the .dmg file.
This is probably the easiest way, but unfortunately not the best. Using native install method you don’t have to install VirtualBox to run Linux, but sharing files between your Mac OS and systems in containers are really slowly. I can recommend that solution only if you want to test something or your project doesn’t use a framework with a lot of files.
Docker Toolbox – second method
It’s an app provided by Docker Company for Mac OS and Windows. The special feature in this toolbox is the requirement for VirtualBox, which will be a supervisor to run Linux. So, Docker is available as another machine in Docker environment. This toolbox contains also docker-compose
(more below) and Kinematic, which allow you to manage your container by using GUI than a command line.
Install
I guess you have installed brew
if not just follow this page and do everything that I’ve described.
If you are ready, open your terminal and type something like this:
If you have done it that you’ve received notice that docker-machine-driver-xhyve
has to run as root
, so you have to execute that commands:
Both commands will ask you for a password. Don’t worry to type it in a command line.
If everything goes ok then you can create your first docker machine, just type this command:
This command, as you suppose, creates a docker machine, using the xhyve driver.--xhyve-experimental-nfs-share
– this flag allows you to share each file in your /Users/
folder between Mac OS and Linux run on Docker.
Because you can have a lot docker machine, you can type this command in your terminal:
It registers a few variables, which allow you to use default docker machine without typing “default” each time.
Useful tools
Probably, you’ve noticed that with docker you installed also docker-machine
and docker-compose
. These tools are not required but they are the strength of docker.
docker-machine
Install Virtualbox With Brew
This tool allows you to prepare a lot of docker machines on your Mac OS, so you can have a lot of containers on many Linux distributions. You can dump all available commands just by typing docker-machine --help
but most likely you will use three of them:
I guess I don’t have to describe what exactly this commands do. It’s so obvious. One thing you need to know, if something goes wrong, just try to restart your docker machine.
docker-compose
Brew Install Virtualbox Version
The main goal of docker: you can write like this “one process = one container”, but each app requires a lot process it could be a PHP, HTTP server, some database etc. Of course, you can run containers for each process manually, which is not a big deal with 3 containers, but trust me it escalates very fast, so you need an easy tool to manage your container and to manage the dependencies because one container can require access to another container. For example, PHP app needs information from a database, but it doesn’t need access to HTTP server. Of course, and HTTP server requires access to PHP.
To work with docker-compose
you need to create an YAML file called docker-composer.yml
where you describe which container you want to create and how they are linked between each other.
That file can look like this:
As you can see, you are creating two containers, first, contains MySQL database and second one – a WordPress instance. This example is flattened, in normal case you should split WordPress instance to three another containers: PHP, HTTP server and one for WordPress files.
There is also created one volume, which contains files of MySQL database. This solution prevents loosing data when you turn off your Mac, or just reset docker-machine or this particular container.
Download Virtualbox Guest Additions Mac
If you want to read something more about parameters available in docker-compose
file, you can just go to docker documentation.
docker-compose
, as well as other tools, provides a lot of commands available from a terminal, the number one is:
This command runs all containers defined in your docker-compose file. If it is needed – rebuild and remove old unused containers.
How to use
Everything that you need is in the section above. You can manage of course each particular container directly from command line using command docker
. But it’s just wasting a time.
Access by domain
Probably you want to access to your container by your web browser using some domains. You need to know what is IP of your docker machine and you can check it using command line just typing this:
You see IP and then use that IP in your /etc/hosts
file.
Potential problems
Because you are trying to run Linux environment on Mac OS you can some across a lot strange problems if you want to use it in common work. Fortunately, you just need to follow some rules to enjoy work with docker.
Sharing files
If you installed a docker as described above you can share only files from your /Users/
folder. You can debug what is sharable directly on your docker machine, which can receive access directly from command line, like this:
Now, you are logged on your Linux and can browse to /
and check is there /Users/
folder which contains files from your Mac OS. If you don’t see your files, just try to reinstall Docker and xhyve.
Speed of I/O process
Because docker needs transfer files between your Mac OS and Linux using the NFS it’s always more slowly then operation directly on your disk. So, if you want to boost up your application you have to remember to share only needed files. if you are backend develop you don’t share frontend javascript libraries, just put in into inside container.
Don’t forget to ignore cache and logs files!
Access via domain/IP
Restarting Mac OS or docker-machine
sometimes restarts also IP of the docker machine. If you can’t connect to your docker just check the current IP using this command:
If it doesn’t work, you have to update domains in your /etc/hosts
file.