I have been developing software for many years now, and have always defaulted to Apple hardware, based on their UNIX-style OS and the terminal applications / CLI. During the course of time, I have experimented with getting a productive development setup on a Windows machine, but usually this has been frustrating and I have almost immediately gone back to the Mac.
Recently, Microsoft have started to focus more heavily on software development, hence the introduction of class-leading tools such as Visual Studio Code (which is now my default code editor). More recently than that, they have been working with Canonical on developing the Windows Subsystem For Linux (WSL) which brings a true linux kernel into the Windows operating system. This has been game-changing for Windows developers, as they no longer need to hack around in PowerShell, and can access to a native Linux toolset on their Windows machine.
A problem I have grappled with for a long time now (as a freelance software engineer) has been keeping clean, unpolluted environments to use for each project I work on. On the Mac, I have tried these:
- Creating virtual machines in VirtualBox and working exclusively on them (very clunky and involves a lot of setup).
- Creating virtual machines and using Visual Studio Code Remote to SSH into them (less clunky, but still requires a lot of setup).
- Using Docker (too much abstraction, difficult to work with).
- Creating seperate user accounts in MacOS for each project (hogs memory, causes the fans to run in overdrive, and no ability to work between projects without switching users).
None of the above solutions have really been ideal, and I have noticed how simple this has become in Windows through WSL (and now WSL2). You can spin up a WSL instance, do the configuration through a real Linux session, and then remote into the instance tightly with Visual Studio Code. It just worked. Through WSL2 I was able to create isolated instances for each project, and work in an unpolluted environment.
It turns out that the same guys that worked on WSL with Microsoft (Canonical, the developers of Ubuntu) have created a similar tool that runs on MacOS, Windows and Linux, Multipass. Multipass enables you to spin up Ubuntu Server instances, configure them, and work exclusively in Visual Studio Code using Remote SSH. This is how I set it up.
Firstly, I used
homebrew to install Multipass on MacOS by issuing
brew cask install multipass . Multipass comes with a useful system tray applet that enables you to quickly see which instances are running and start and stop them. For a quick start, click on the Multipass applet and start the
primary instance and shell into it. You will be greeted by a blank Ubuntu server instance with the familiar bash command prompt. Now let’s look at how we can create and configure our own virtual machines.
Before we get started, it is important to understand that by default, Multipass creates instances that are somewhat limited in terms of resources. When using the default instance settings with NodeJS, I found that it would quickly hit memory and disk ceilings and crash the instances. Not good! Hence I have provided some instructions to get this right from the outset, because at this stage, you cannot resize the Virtual Machine after creation.
In the terminal, issue the following command:
multipass launch --disk 10G --mem 4G --cpus 2 --name MyInstance
This will instruct multipass to create a virtual machine instance based upon the current LTS branch of Ubuntu (20.04) and configure it with 10GB of disk space, 4GB of memory and two CPU cores, which is plenty for running NodeJS quickly and effectively. From the command line again, you can also issue the following to grab a terminal:
multipass shell MyInstance
Once inside the VM, there are a few things that I like to configure. Firstly, the ubiquitous
sudo apt update && sudo apt upgrade should be issued to update the VM. Then I tend to install the default NodeJS package with
sudo apt install npm . At this point, you get a flavour of Node10, however you can get a more recent version of Node from NodeSource.
After this, I enable password authentication, as I hate messing around with SSH keys by issuing
sudo nano /etc/ssh/sshd_config and changing
PasswordAuthentication no to
PasswordAuthentication yes . I then configure the password for the default user
sudo passwd ubuntu . Finally I restart
sudo systemctl restart sshd .
To finish configuring, I add a small amount of swap space to my instance, to ensure that no out-of-memory errors occur. I do this by issuing the following command:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
This is generally where I stop configuring the VM as I tend to use Node, but if you are working with a different development setup, set it up usual with what works for the project that you are working on.
Before I move on to VS Code, I write down the IP address of the instance so that I can
ssh into it later. I run
ip route list and copy it. I then quickly test it in the MacOS terminal using
ssh ubuntu@[IP address] and ensure I can log in.
Once I am happy with the above, I head into Visual Studio Code and ensure that the Remote SSH (official extension from Microsoft) extension is installed. This provides a new tab in the sidebar, which enables you to set up a new SSH remote connection. Simply use the same command you typed in MacOS terminal before to connect, and provide the password you set for the default ubuntu user earlier.
Using the Visual Studio Code terminal, you can
git clone your projects over, and work with them in the code editor directly.
In summary, for me, Multipass provides a similar workflow to WSL2 + VS Code on a Windows machine. The low-configuration ability to isolate code into seperate virtual machines, and run a clean setup is what I have been searching for. Improvements? I would love to see the ability to resize and reallocate resources to VM’s following creation, and to move / archive certain virtual machines (easily) to other directories / drives. However, great work Canonical and I can’t wait to see where this is heading!