Services

Resources

Company

Vagrant, UTM, Virtualization, ARM, Hypervisor

Dec 2, 2024 | 5 min read

Using UTM and Vagrant to Spin Up Dev Environments on Apple Silicon Macs

Using UTM and Vagrant to Spin Up Dev Environments on Apple Silicon Macs

SRE @One2N

Vagrant, UTM, Virtualization, ARM, Hypervisor

Dec 2, 2024 | 5 min read

Using UTM and Vagrant to Spin Up Dev Environments on Apple Silicon Macs

SRE @One2N

Vagrant, UTM, Virtualization, ARM, Hypervisor

Dec 2, 2024 | 5 min read

Using UTM and Vagrant to Spin Up Dev Environments on Apple Silicon Macs

SRE @One2N

Learn how to set up a local development environment on M-series Macs using Vagrant and UTM, overcoming VirtualBox limitations and enabling seamless virtualization, containerization, and internetworking. This guide provides a step-by-step approach to integrating UTM with Vagrant for a production-like setup.

rev: Spandan Ghosh

The Importance of Local Development

Setting up a local development environment is crucial for any serious developer. It allows you to create a production-like setup right on your machine, often without needing an internet connection. We call this Airplane Mode Development here at One2N, and it's a game-changer for shipping code faster.

Enter Vagrant

Vagrant, from Hashicorp, has been a trusted tool for over a decade, helping engineers spin up quick, portable, and reproducible virtual machines. It's declarative, ensuring consistency in provisioning resources, and it's super fast. You can start up, suspend, resume, and destroy your workloads in just a few seconds.

The Challenge with Apple Silicon

For the problem we are trying to address, Let’s consider our primary development device to be a Mac with M-Series Apple Silicon (I am running an M3). Vagrant provides support for major Type-2 hypervisors in the market (Hyper-V, VirtualBox, VMware Fusion and Docker). However,

Two major blockers arise, when you start setting things up on localhost on it.

  1. Vagrant relies majorly on VirtualBox (by popular choice).

  2. VirtualBox officially no longer supports M-series apple products.

We’ve personally observed VMs crashing and getting stuck in boot phases while trying to work our way with a Vagrant + Virtualbox combination on a M3 device. So we set out on the hunt, for a Mac friendly or native hypervisor to run a decent local development setup on their machine, and expect it to serve the bare minimum capabilities - virtualization, containerisation, persistence and internetworking.

Hypervisors Supported by Vagrant Officially - and Observations + Decisions

Enter UTM: A Native Hypervisor for MacOS

UTM is a 3rd Party - MacOS native QEMU/hypervisor that leverages Apple's Hypervisor virtualization framework. It allows you to run ARM64 operating systems on Apple Silicon at near-native speeds and also supports lower performance emulation for running x86/x64 on Apple Silicon and ARM64 on Intel Macs

Integrating UTM with Vagrant

While UTM is not officially supported by Vagrant, a community-driven plugin has been developed to bridge this gap. Naveen Raj has created the vagrant_utm plugin, which enables Vagrant to control, provision, and destroy VMs using UTM's APIs. This plugin is a crucial step in making UTM work seamlessly with Vagrant

Setting Up Your Environment

Here’s a step-by-step guide to get you started:

Step 1: Install Vagrant and UTM

First, ensure you have Vagrant and UTM installed on your Mac.

## Install Vagrant - 
brew tap hashicorp/tap
brew install hashicorp/tap/hashicorp-vagrant

## Install UTM -  
brew install --cask utm

## Install Vagrant UTM Plugin - 

Step 2 - Clone my Github Repository - It’s more than just a Hello World App!

The application is a realistic setup, of perhaps what your local application and dependency stack looks like,

git

We have a Flask Application, Nginx Routing, Docker Containers, MySQL Container and so on as you’ve observed in the above diagram.

Step 3: Set Up Environment Variables

Create an environment file for your MySQL and Flask API.

# .env file for MySQL and Flask API
MYSQL_ROOT_PASSWORD=<password>
MYSQL_DATABASE=<name-your-db-here>
DB_URL=mysql://root:<password>@${DB_HOST}:3306/<name-your-db-here>

NOTE - Remember to rename your env file from (.env -> env) so that UTM can mount it as a visible file.

Step 4: Run Vagrant

Bring up your Vagrant environment.

NOTE - When you do this, UTM will raise a pop-up, and your terminal will ask for permissions for a y/N situation. - Approve the download of the Ubuntu-VM image into UTM and wait for the download to complete. - Once completed, manually mount the project folder in UTM’s "Shared Directory" section. - Remember to rename your env file from (.env -> env) so that UTM can mount it as a visible file.

If you follow this sequentially, you'll see the following trail -

#Expected Output 
    default: 66b98279bfb9 Pull complete
    default: nginx Pulled
    default: Container mysql_container  Running
    default: Container flask_api2  Running
    default: Container flask_api1  Running
    default: Container nginx_container  Creating
    default: Container nginx_container  Created
    default: Container nginx_container  Starting
    default: Container nginx_container  Started
    default: API Services, NGINX, and MySQL deployed successfully

Access Your VM

Once the VM is up, you can log into it using:

vagrant ssh

Deploying an Experimental Application using Vagrant and UTM

Demo of Vagrant running on Apple Silicon Macs via UTM

This approach establishes UTM as a dependable hypervisor for M-series devices by demonstrating its capabilities in the following technical domains:

  1. Containerization within a Virtualized Environment: Running a Docker Compose setup inside the VM without issues.

  2. Advanced Internetworking: Enabling seamless network communication between the host (laptop), the UTM virtual machine, and Docker networks operating within the VM.

  3. Networked File System Integration: Supporting shared directory mounts on the VM, leveraging workarounds where necessary for compatibility.

Gotchas to Watch Out For When Using This Vagrant File:

  1. UTM Pop-Up and Permission Prompt

    • Don’t miss the UTM pop-up to confirm the VM setup.

    • Your terminal will prompt for a y/N confirmation to download the VM image. Say y or the setup will halt.

  2. Downloading the VM Image

    • Ensure a stable internet connection and sufficient disk space. A failed download means starting over.

  3. Manual Steps in UTM

    • After the VM image downloads, manually mount the project folder in UTM’s "Shared Directory" section.

    • Set the sharing mode to "virtFS" for smooth file access, or your files won’t appear.

    • If the VM doesn’t boot right away, check and configure boot options or firmware manually, especially for non-standard setups.

  4. Hidden Files Aren’t Your Friend

    • UTM skips hidden files during mounting. Rename .env to env so the VM can see it.

  5. Port Forwarding Traps

    • Ensure port 8080 on your host is free. If it’s in use, NGINX forwarding will fail.

    • Verify everything works by testing http://localhost:8080 once the VM is up.

Vagrant File used in Setup

Vagrant.configure("2") do |config|
  config.vm.box = "ubuntu/jammy64"

  # Set VM properties for UTM
  config.vm.provider "utm" do |u|
    u.utm_file_url = "<https://github.com/naveenrajm7/utm-box/releases/download/debian-11/debian_vagrant_utm.zip>"
    u.name = "ubuntu_vm"
    u.memory = "2048"   # 4GB memory
    u.cpus = 4          # 4 CPUs
    u.directory_share_mode = "virtFS"
    #u.directory_share_mode = "webDAV"  # Use webDAV for manual directory sharing
  end

  # Provisioning all requirements using a shell script
  config.vm.provision "shell", path: "provision.sh"

  # Forward port 8080 from the VM to the host for NGINX access
  config.vm.network "forwarded_port", guest: 8080, host: 8080

We are not the first!

The issue about Virtualbox withdrawing support for Apple Silicon has been highlighted in multiple forums as early as 2021, and the sources below are compiled. Going through these, should most definitely get you up and running.

Articles

  • 1st article - Linux VMs on an M1-based Mac with VScode and UTM

  • 2nd article - Finding a working VM alternative when VirtualBox no longer works

Discussion Threads

Share

Jump to Section

Also Checkout

Also Checkout

Also Checkout

Subscribe for more such content

Stay updated with the latest insights and best practices in software engineering and site reliability engineering by subscribing to our content.

Subscribe for more such content

Stay updated with the latest insights and best practices in software engineering and site reliability engineering by subscribing to our content.

Subscribe for more such content

Stay updated with the latest insights and best practices in software engineering and site reliability engineering by subscribing to our content.

Subscribe for more such content

Stay updated with the latest insights and best practices in software engineering and site reliability engineering by subscribing to our content.