in Infrastructure

Versioned Vagrant boxes, privately.

With Vagrant 1.5 came Boxes 2.0, which introduced box short names and box versioning. These improvements brought the ability to upgrade boxes, which was much better than the “box installed or not” state boolean of earlier Vagrant versions.

Box versioning was designed and is only documented for use with HashiCorp’s box hosting in the cloud, Atlas. This service was previously provided through Vagrant Cloud which offered privately hosted boxes at a cost. At CoverMyMeds we wanted to self-host our boxes for privacy, licensing, and bandwidth concerns. Luckily in the Vagrantfile, we can point config.vm.box_url at our own server.

Let’s take a look at an Atlas hosted box to figure out how to recreate this on our own server. Since Atlas is the default box_url, the following is sufficient to reference a cloud hosted box in your Vagrantfile:

config.vm.box = "puppetlabs/centos-7.0-64-puppet"

Box versioning uses a JSON object from the hosting server to determine box metadata, which can be fetched from Atlas by appending a .json to the web UI. For puppetlabs/centos-7.0-64-puppet, you can see the JSON file.

Now that we can see the metadata format, we can create our own JSON file and put it on our web server.

{
  "description": "CMM RHEL7 Vagrant Box",
  "name": "cmm/rhel7",
  "versions": [
    {
      "providers": [
        {
          "checksum": "8643a7583234632c88f51fa4deea34803670283209a95f43228ee3a6392cc3b8",
          "checksum_type": "sha256",
          "name": "virtualbox",
          "url": "https://internal_web_server/vagrant/cmm-rhel7-virtualbox-0.1.1.box"
        }
      ],
      "version": "0.1.1"
    }
  ]
}

This example only has one box version, but to add another version we would extend the “versions” array and upload the box to the web server with a unique path. The Puppet Labs JSON example above shows this clearly.

In order to use versioning on our own private web server we need to modify our Vagrantfile.

config.vm.box = "cmm/rhel7"
config.vm.box_url = "https://internal_web_server/vagrant/cmm-rhel7.json"

As with Atlas or non-versioned box_url’s, the box will be fetched during vagrant up if not already downloaded.

Now that we have a versioned box, we are able to work with them just as we could with Atlas.

See versioned installed box versions:

❯ vagrant box list
cmm/rhel7       (virtualbox, 0.1.1)

See that a newer version is available during vagrant up.

❯ vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'cmm/rhel7'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'cmm/rhel7' is up to date...
==> default: A newer version of the box 'cmm/rhel7' is available! You currently
==> default: have version '0.1.1'. The latest is version '0.1.2'. Run
==> default: `vagrant box update` to update.
--- SNIP ---

So that box updates are non-destructive, Vagrant will not automatically update them. We can now manually update the box. Note that this process is run from an environment with a correctly configured Vagrantfile.

❯ vagrant box update
==> default: Checking for updates to 'cmm/rhel7'
    default: Latest installed version: 0.1.1
    default: Version constraints:
    default: Provider: virtualbox
==> default: Updating 'cmm/rhel7' with provider 'virtualbox' from version
==> default: '0.1.1' to '0.1.2'...
==> default: Loading metadata for box 'https://internal_web_server/vagrant/cmm-rhel7.json'
==> default: Adding box 'cmm/rhel7' (v0.1.2) for provider: virtualbox
    default: Downloading: https://internal_web_server/vagrant/cmm-rhel7-virtualbox-0.1.1.box
    default: Calculating and comparing box checksum...
==> default: Successfully added box 'cmm/rhel7' (v0.1.2) for 'virtualbox'!
❯ vagrant box list
cmm/rhel7                       (virtualbox, 0.1.1)
cmm/rhel7                       (virtualbox, 0.1.2)

More versioned box options are available such as disabling box update checks, ignoring SSL certificates, etc. See the Vagrantfile reference for more information.

Combined with reproducible Vagrant box builds, we here at CoverMyMeds can roll out updated boxes internally and completely under our control.

Write a Comment

Comment

11 Comments

  1. When creating the box using the ‘vagrant package’ command, I thought I was supposed to include the JSON metadata file using the ‘–include’ parameter. Is that not true? It sounds like I just create the box file and separately create this metadata for putting on the internal server, and then referencing from my Vagrantfiles. If so, what types of files would you suggest including when creating the box? I just wonder what that option is for…

    • Hi Edward,

      You want to create the metadata file separately and put it on your internal server. It shouldn’t be included in the base box.

      I’m not sure what else is intended to be included with a packaged box, but the description in the documentation says “Additional files will be packaged with the box. These can be used by a packaged Vagrantfile (documented below) to perform additional tasks.”

  2. hi, thx for the info. But in this example only one box is configured. what if i want to configure multiple boxes in a singlr json file and reffer from json from vagrant file. plz sugest. thx in advance

    • Hi pradeep,

      A single json file can only contain one named box. It can have multiple versions by extending the “versions” array and incrementing the version in the hash.

      If you want to refer to a separate box, e.g. “cmm/rhel6” then you’d need to create another json file for that box and refer to it at a unique URL.

    • Hi Hari,

      I’m not quite sure what you’re trying to accomplish. This post is showing you how to create your own versioned boxes on your own web server or local filesystem.

      -adam

  3. Hi,
    how will be using EC2 to host versioned boxes, what will be the security config to create the Vagrantfile and share it private.

  4. You could also try this: github.com/BenPhegan/vagrantshadow

    Provides a service that will do all indexing for you, just drop the box file in a directory and off you go, fully named boxes internally hosted.

    • Looks like a nice project. We already have this automated through jenkins and some custom scripts, with just Apache serving the files, but this looks like a good alternative for new setups.