Developing on OS X Inside Vagrant

OS X El Capitan installing in VirtualBox via Packer

I maintain an OS X tool for sandboxing the popular Homebrew package manager called brewdo. Because I need my MacBook to keep working day-to-day, I need a way to develop features and fixes in brewdo without risking my system’s integrity.

If brewdo targeted Linux, I could very easily use Vagrant to spin up a Linux system and develop it there. brewdo targets OS X, though. And although Apple gives permission to virtualize it, they don’t give permission to share copies of it.

But all is not lost. OS X on Vagrant is achievable, and without skirting Apple’s copyright.

1. Getting Started

I use (and have contributed VirtualBox support to) Tim Sutton‘s excellent osx-vm-templates project to build Vagrant boxes for OS X.

Tim recommends using VMware Fusion with the VMware Fusion provider. I personally use Vagrant’s built-in VirtualBox support, because it’s much cheaper (i.e. free) and brewdo is my only need for virtualized OS X. VirtualBox is serviceable, but not a great performer. Parallels is also an option.

You’ll also need Packer to build the boxes, and an installer .app from the Mac App Store for the version of OS X you want to Vagrantize. The rest of what you need (apart from Vagrant and your virtualization solution) is either in the osx-vm-templates repo or already on your Mac.

2. Building the Disk Image

The first thing you’ll need to do is prepare an installer disk image from the .app your downloaded from the Mac App Store. This is accomplished using the prepare_iso tool from osx-vm-templates. Give it the installer .app and an output directory, and it’ll give you an installer disk image ready for Packer:

$ sudo prepare_iso/prepare_iso.sh \
    /Applications/Install\ OS\ X\ El\ Capitan.app/ \
    packer/

Note that as of this writing, you need to do one additional thing if you’re a VirtualBox user: stop prepare_iso from enabling the Remote Management service, which is used with Apple Remote Desktop. If you leave it enabled, the resulting virtual machine will periodically freeze. This appears to be a VirtualBox bug.

Thankfully, disabling it is a piece of cake:

$ sudo prepare_iso/prepare_iso.sh \
    -D DISABLE_REMOTE_MANAGEMENT \
    /Applications/Install\ OS\ X\ El\ Capitan.app/ \
    packer/

When prepare_iso is done, take note of the output at the end—it’ll tell you what the filename of your new disk image is, which you’ll need for the next step.

3. Packing the Vagrant Box

The rest of the process is driven by Packer and is really easy. Here’s the command line I’m using for my latest build, executed from the packer directory:

$ packer build \
    --var iso_url=OSX_InstallESD_10.11.1_15B42.dmg \
    --only virtualbox-iso \
    template.json

Let’s break that down:

  • iso_url is the path to the installer disk image that prepare_iso built for us.
  • --only virtualbox-iso tells Packer to build only using VirtualBox. I actually have VMware Fusion on my machine, but not the Vagrant provider for it, so I don’t want Packer to build a box for VMware. Though it’ll happily do that if I want.

This process is quite time-consuming, but you can watch progress in the virtual machine console that pops up and on the command-line. Once done, you’ll have a Vagrant box.

4. Using the Box with Vagrant

Packer’s output is a Vagrant box, e.g. packer_virtualbox-iso_virtualbox.box. Adding that box to Vagrant is straightforward:

$ vagrant box add \
    --name osx-10.11.1 \
    packer_virtualbox-iso_virtualbox.box

Once the box is in, you can head over to your project directory and run vagrant init osx-10.11.1 (or whatever you named your box) to set up the initial Vagrantfile.

You’re almost ready to vagrant up, but one final caveat applies for VirtualBox users—there are no guest additions for OS X, so if you want to sync files, you’ll need to set up a shared folder in the VagrantFile to use rsync:

config.vm.provider "virtualbox" do |vb|
  config.vm.synced_folder ".", "/vagrant", type: "rsync"
end

And you’re done! vagrant up, vagrant ssh (or use some other remote access tool, like Screen Sharing), and away you go!

 
Conversation
  • Roberto says:

    This guide is great! I was looking for a solution to develop iOS in a repeatable manner, this seems to be an answer!

    Following this guide, however, the checksum didn’t go through with the name iso_checksum. I checked the template.json from the git repo, and that seems to have changed to iso_checksum_type. You may want to update this article for future devs with the same need.

    Cheers!

  • Pradyun Gedam says:

    From what I gather, the linked PR completely removes the need for checksums.

    My 2 cents. :D

    • Matt Behrens says:

      Thanks! I confirmed, you don’t need a checksum to build the image anymore. I’ve updated the post.

  • David Biglin says:

    Hi,

    Thanks so much for this post really helpful. I have run into an issue at stage 3 and i get the following output from packer.

    ==> virtualbox-iso: Starting the virtual machine…
    ==> virtualbox-iso: Error starting VM: VBoxManage error:
    ==> virtualbox-iso: Unregistering and deleting virtual machine…
    ==> virtualbox-iso: Deleting output directory…
    Build ‘virtualbox-iso’ errored: Error starting VM: VBoxManage error:

    Any ideas where the log files will be to start diagnostics. I am trying to get El Captain running on a MBP.

    Cheers
    Dave

    • Matt Behrens says:

      Hi David,

      I’m not sure—I’ve never seen that before. If VirtualBox is installed correctly, it might be a Packer problem. I’d check to see if your Packer installation can build any other kinds of Vagrant boxes.

  • Job Evers-Meltzer says:

    If you get an error about “VBoxManage error: VBoxManage: error: Implementation of the USB 2.0 controller not found!”

    You’ll need to install the extension pack. See (https://github.com/timsutton/osx-vm-templates#extension-pack) for more info

  • Job Evers-Meltzer says:

    I think its also worth adding that the entire process can take 3+ hours and you’ll need at least 25gb of free space (6+ for the El Capitan Installer, 9 for preparing the iso and another 9 for the packer build)

  • Alan Berman says:

    I had better luck using NFS for the shared folder, rather than rsync.
    A private network is required for NFS to work, so if you want to use NFS for the synced folder, use something like this:

    config.vm.provider “virtualbox” do |vb|
    config.vm.network “private_network”, ip: “192.168.33.10”
    config.vm.synced_folder “.”, “/vagrant”, type: “nfs”
    end

    Also worth noting, you may have to enter your admin credentials to get the NFS service running.

    • Matt Behrens says:

      Yep, that’s a good option to have, especially if you’re used to live updates between the host and guest.

      I personally prefer rsync because it’s lower-impact and sufficient for my needs, but definitely go this route if you find it useful.

  • Aparna S says:

    I am getting this error Error creating VM: VBoxManage error: VBoxManage: error: Guest OS type ‘MacOS1012_64’ is invalid

    Any idea what is the guest os type to use?

    • Matt Behrens says:

      It doesn’t appear that VirtualBox has specific support for macOS Sierra at this time, so you would want to try MacOS1011_64 instead.

    • Aparna S says:

      This is the complete error message :

      ==> virtualbox-iso: Error creating VM: VBoxManage error: VBoxManage: error: Guest OS type ‘MacOS1012_64’ is invalid
      ==> virtualbox-iso: VBoxManage: error: Details: code VBOX_E_OBJECT_NOT_FOUND (0x80bb0001), component VirtualBox, interface IVirtualBox, callee nsISupports
      ==> virtualbox-iso: VBoxManage: error: Context: “CreateMachine(bstrSettingsFile.raw(), bstrName.raw(), ComSafeArrayAsInParam(groups), bstrOsTypeId.raw(), createFlags.raw(), machine.asOutParam())” at line 275 of file VBoxManageMisc.cpp
      ==> virtualbox-iso: Deleting output directory…
      Build ‘virtualbox-iso’ errored: Error creating VM: VBoxManage error: VBoxManage: error: Guest OS type ‘MacOS1012_64’ is invalid
      VBoxManage: error: Details: code VBOX_E_OBJECT_NOT_FOUND (0x80bb0001), component VirtualBox, interface IVirtualBox, callee nsISupports
      VBoxManage: error: Context: “CreateMachine(bstrSettingsFile.raw(), bstrName.raw(), ComSafeArrayAsInParam(groups), bstrOsTypeId.raw(), createFlags.raw(), machine.asOutParam())” at line 275 of file VBoxManageMisc.cpp

  • Comments are closed.