Have you ever wanted a development machine in the cloud? Sometimes I might want:
- a “freshly squeezed” and often disposable environment for a task that uses a particular toolchain.
- to run something that has higher CPU, I/O, or bandwidth requirements than I have available, or want to use, locally, or something that must remain running despite intermittent connectivity.
- a backup of my primary development machine, that can have me up and running in seconds to minutes in case of a hardware failure.
- an always on machine that can be accessed via multiple devices, from a laptop to a mobile device, or perhaps even by multiple people.
My set of “desert island developer tools” include Visual Studio Code, bash via its Integrated Terminal, Google Chrome, and Docker. With these tools I can have almost complete parity across my primary MacBook Pro (macOS) laptop and my secondary Surface Go which dual boots Ubuntu and Windows 10 with Windows Subsystem for Linux (WSL).
So what is the easiest way to get parity between my developer machine and one in the cloud? For my macOS/Linux/Containers toolchain, I would typically have run a Linux (Ubuntu) Virtual Machine. However, the lack of seamless Remote Desktop (RDP) options on Linux for GUI apps like Code and Chrome is a drawback, especially on low bandwidth connections.
Azure’s v3 Series Virtual Machines also make it possible to use nested-virtualization and therefore Docker Desktop for Windows, which uses Hyper-V, to run Linux Containers on a Windows VM in the cloud.
Combining these two gives us the best of both worlds. A completely cross platform development environment with trivial remote access.
This is also a great option for people who would like to kick the tires of Windows Subsystem for Linux (WSL) without having to run Windows locally on a VM, dual-booted, or on a spare machine. WSL isn’t just for people whose daily driver is a Windows machine.
Here is how we can use the Azure CLI to create a Virtual Machine in Azure running Windows Server 2019, and PowerShell to quickly install Google Chrome, VS Code, Windows Subsystem for Linux, Ubuntu 18.04, Hyper-V, and Docker.
Create a VM in Azure
RESOURCE_GROUP='190300-win-1' LOCATION='eastus' PASSWORD=$(openssl rand -hex 6)'A1!' # optional: # mkdir -p _/ && echo -n $PASSWORD > _/PASSWORD.txt az group create -n $RESOURCE_GROUP -l $LOCATION IMAGE='Win2019Datacenter' az vm create \ --resource-group $RESOURCE_GROUP \ --name windows1 \ --size Standard_D2s_v3 \ --image $IMAGE \ --admin-username azureuser \ --admin-password $PASSWORD # optional: show vm public ip az vm show --show-details \ --resource-group $RESOURCE_GROUP \ --name windows1 | jq -r .publicIps
If we prefer to use Windows 10, we could have used the following image, which gives us the option to install our preferred Linux distribution via the Windows Store, as well as join the VM to Azure Active Directory, use Multi-factor Authentication for Remote Desktop, and more.
# optional: # az vm image list --all --offer Windows-10 IMAGE='MicrosoftWindowsDesktop:Windows-10:rs5-pron:17763.316.69'
However, we’ll use Windows Server 2019 and continue on to use Powershell to install the tools we need.
Install Chrome, Code, WSL, Ubuntu
# stop server manager from starting up automatically Get-ScheduledTask -TaskName ServerManager | Disable-ScheduledTask -Verbose # chrome Start-BitsTransfer -source https://dl.google.com/chrome/install/latest/chrome_installer.exe -destination chrome_installer.exe .\chrome-installer.exe # vs code Start-BitsTransfer -source https://go.microsoft.com/fwlink/?Linkid=852155 -destination vscode-insider.exe .\vscode-insider.exe # wsl # https://docs.microsoft.com/en-us/windows/wsl/install-on-server Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux # ubuntu 18.04 # https://docs.microsoft.com/en-us/windows/wsl/install-manual Start-BitsTransfer -source https://aka.ms/wsl-ubuntu-1804 -destination Ubuntu.appx Rename-Item Ubuntu.appx Ubuntu.zip Expand-Archive Ubuntu.zip Ubuntu/ .\Ubuntu\ubuntu1804.exe # in powershell: # bash.exe # <enter username and password> # in vs code: # Ctrl + Shift + P > Terminal: Select Default Shell # WSL Bash
Enable Hyper-V and Install Docker
# https://docs.microsoft.com/en-us/azure/virtual-machines/windows/nested-virtualization Install-WindowsFeature -Name Hyper-V -IncludeManagementTools -Restart # <restart vm and log back in via remote desktop> # https://docs.docker.com/docker-for-windows/install/ Start-BitsTransfer -source https://download.docker.com/win/stable/Docker%20for%20Windows%20Installer.exe -destination docker.exe .\docker.exe
Helpful aliases and other tweaks
Below we’ll make an alias that will run docker.exe every time we run
docker from within WSL, alias code-insiders to
c, and re-alias
ls to remove the colorizaton.
vim ~/.bash_aliases alias docker='docker.exe' alias c='code-insiders' alias ls='ls' # :wq
We can also set
dom in vs code settings (see: https://code.visualstudio.com/docs/editor/integrated-terminal#_changing-how-the-terminal-is-rendered)
Create our first Docker Container via WSL, PowerShell, or cmd:
Here we see how we can run a Linux Docker Container, using Docker for Windows, from WSL, Powershell, or cmd.
# wsl docker run --rm -v 'c:\users\azureuser\me\':/pwd/ -it ubuntu bash # powershell docker run --rm -v "$((get-location).path):/pwd/" -it ubuntu bash # cmd docker run --rm -v %cd%:/pwd/ -it ubuntu bash
Note that inside WSL we are passing the Windows path for a volume mount to docker (which has been aliased to docker.exe). There isn’t a good way of easily passing the Windows path from inside WSL.
In a future post we’ll look at automating the installation process (similar to cloud-init on Linux), and creating our own Virtual Machine images so that our favorite environment is only an
az vm create away.