In my last post I summarised how to enable versioning for Vagrant box outside Vagrant’s cloud. In this part I’d like to share how to update a box.
My environment
The environment hasn’t changed compared to the first post. In summary I’m using
- Ubuntu 20.04 LTS
- Virtualbox 6.1.6
- Vagrant 2.2.7
Updating a box
Let’s assume it’s time to update the base box for whatever reason. I most commonly update my boxes every so often after having run an “yum upgrade -y” to bring it up to the most current software. A new drop of the Guest Additions also triggers a rebuild, and so on.
Packaging
Once the changes are made, you need to package the box again. Continuing the previous example I save all my boxes and their JSON metadata in ~/vagrant/boxes. The box comes first:
[martin@host ~]$ vagrant package --base oraclelinux7base --output ~/vagrant/boxes/ol7_7.8.1.box
This creates a second box right next to the existing one. Note I bumped the version number to 7.8.1 to avoid file naming problems:
[martin@host boxes]$ ls -1 ol7_7.8.0.box ol7_7.8.1.box ol7.json
Updating metadata
The next step is to update the JSON document. At this point in time, it references version 7.8.0 of my box:
[martin@host boxes]$ cat ol7.json { "name": "ol7", "description": "Martins Oracle Linux 7", "versions": [ { "version": "7.8.0", "providers": [ { "name": "virtualbox", "url": "file:///home/martin/vagrant/boxes/ol7_7.8.0.box", "checksum": "db048c3d61c0b5a8ddf6b59ab189248a42bf9a5b51ded12b2153e0f9729dfaa4", "checksum_type": "sha256" } ] } ] }
You probably suspected what’s next :) A new version is created by adding a new element into the versions array, like so:
{ "name": "ol7", "description": "Martins Oracle Linux 7", "versions": [ { "version": "7.8.0", "providers": [ { "name": "virtualbox", "url": "file:///home/martin/vagrant/boxes/ol7_7.8.0.box", "checksum": "db048c3d61c0b5a8ddf6b59ab189248a42bf9a5b51ded12b2153e0f9729dfaa4", "checksum_type": "sha256" } ] }, { "version": "7.8.1", "providers": [ { "name": "virtualbox", "url": "file:///home/martin/vagrant/boxes/ol7_7.8.1.box", "checksum": "f9d74dbbe88eab2f6a76e96b2268086439d49cb776b407c91e4bd3b3dc4f3f49", "checksum_type": "sha256" } ] } ] }
Don’t forget to update the SHA256 checksum!
Check for box updates
Back in my VM directory I can now check if there is a new version of my box:
[martin@host versioning]$ vagrant box outdated Checking if box 'ol7' version '7.8.0' is up to date... A newer version of the box 'ol7' for provider 'virtualbox' is available! You currently have version '7.8.0'. The latest is version '7.8.1'. Run `vagrant box update` to update. [martin@host versioning]$
And there is! Not entirely surprising though, so let’s update the box:
[martin@host versioning]$ vagrant box update ==> default: Checking for updates to 'ol7' default: Latest installed version: 7.8.0 default: Version constraints: default: Provider: virtualbox ==> default: Updating 'ol7' with provider 'virtualbox' from version ==> default: '7.8.0' to '7.8.1'... ==> default: Loading metadata for box 'file:///home/martin/vagrant/boxes/ol7.json' ==> default: Adding box 'ol7' (v7.8.1) for provider: virtualbox default: Unpacking necessary files from: file:///home/martin/vagrant/boxes/ol7_7.8.1.box default: Calculating and comparing box checksum... ==> default: Successfully added box 'ol7' (v7.8.1) for 'virtualbox'!
At the end of this exercise both versions are available:
[martin@host versioning]$ vagrant box list | grep ^ol7 ol7 (virtualbox, 7.8.0) ol7 (virtualbox, 7.8.1) [martin@host versioning]$
This is so much better than my previous approach!
What are the effects of box versioning?
You could read earlier when I created a Vagrant VM based on version 7.8.0 of my box. This VM hasn’t been removed. What happens if I start it up now that there’s a newer version of the ol7 box available?
Bringing machine 'default' up with 'virtualbox' provider... ==> default: Checking if box 'ol7' version '7.8.0' is up to date... ==> default: A newer version of the box 'ol7' is available and already ==> default: installed, but your Vagrant machine is running against ==> default: version '7.8.0'. To update to version '7.8.1', ==> default: destroy and recreate your machine. ==> default: Clearing any previously set forwarded ports... ==> default: Fixed port collision for 22 => 2222. Now on port 2200. ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 (guest) => 2200 (host) (adapter 1) ==> default: Running 'pre-boot' VM customizations... ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2200 default: SSH username: vagrant default: SSH auth method: private key ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... ==> default: Setting hostname... ==> default: Mounting shared folders... default: /vagrant => /home/martin/vagrant/versioning ==> default: Machine already provisioned. Run `vagrant provision` or use the `--provision` ==> default: flag to force provisioning. Provisioners marked to run always will still run.
Vagrant tells me that I’m using an old version of the box, and how to switch to the new one. I think I’ll do this eventually, but I can still work with the old version.
And what if I create a new VM? By default, Vagrant creates the new VM based on the latest version of my box, 7.8.1. You can see this here:
Bringing machine 'default' up with 'virtualbox' provider... ==> default: Importing base box 'ol7'... ==> default: Matching MAC address for NAT networking... ==> default: Checking if box 'ol7' version '7.8.1' is up to date... ==> default: Setting the name of the VM: versioning2_default_1588259041745_89693 ==> default: Fixed port collision for 22 => 2222. Now on port 2201. ==> default: Clearing any previously set network interfaces... ==> default: Preparing network interfaces based on configuration... default: Adapter 1: nat ==> default: Forwarding ports... default: 22 (guest) => 2201 (host) (adapter 1) ==> default: Running 'pre-boot' VM customizations... ==> default: Booting VM... ==> default: Waiting for machine to boot. This may take a few minutes... default: SSH address: 127.0.0.1:2201 default: SSH username: vagrant default: SSH auth method: private key ==> default: Machine booted and ready! ==> default: Checking for guest additions in VM... ==> default: Setting hostname... ==> default: Mounting shared folders... default: /vagrant => /home/martin/vagrant/versioning2
Cleaning up
As with every technology, housekeeping is essential to keep disk usage in check. Refer back to the official documentation for more details on housekeeping and local copies of Vagrant boxes.
Summary
In the past I really struggled maintaining my local Vagrant boxes. Updating a box proved quite tricky and came with undesired side effects. Using versioning as demonstrated in this post is a great way out of this dilemma. And contrary to what I thought for a long time uploading my boxes to Vagrant cloud is not needed.
There is of course a lot more to say about versioning as this feature can do so much more. Maybe I’ll write another post about that subject some other time, until then I kindly refer you to the documentation.