Use Packer to build a custom Vagrant Box, from another Vagrant Box
This post will demonstrate:
- using packer to run a build based on an existing vagrant box
- using the
vagrant
post-processor to generate a new vagrant box from that build
Context
Packer is really great at building images, and there are “builders” for all the various platforms (vmware, virtualbox, aws, docker, etc). Each of these builders start with an “input”, either an ISO to boot and install with, or a source image to use as a foundation. If you’ve used packer, you’ve probably automated the OS install for some Linux distro or BSD out there. It’s great that it can be done, but for some tasks, I’d like to start with an existing foundation.
Vagrant has a concept of “boxes”, which is similar to an “image” in the container ecosystem (with each VM created from that template box as the “container” in the analogy). There are many existing boxes, so if you want to build a local dev environment for your peers, or want a place to test your configuration management formula, wouldn’t it be nice to start the packer build with an existing box?
This is all great, however, there isn’t a clear and documented route to using an existing vagrant box as the source for a packer build. It’s still possible, here is how I did it.
Initial Setup
download & install:
For me, that looked like:
ᐅ wget https://releases.hashicorp.com/vagrant/1.9.5/vagrant_1.9.5_x86_64.deb
ᐅ sudo dpkg --install vagrant_1.9.5_x86_64.deb
ᐅ vagrant version
Installed Version: 1.9.5
Latest Version: 1.9.5
You're running an up-to-date version of Vagrant!
ᐅ wget https://releases.hashicorp.com/packer/1.0.0/packer_1.0.0_linux_amd64.zip
ᐅ unzip packer_1.0.0_linux_amd64.zip -d ~/bin/
ᐅ packer version
Packer v1.0.0
ᐅ wget http://download.virtualbox.org/virtualbox/5.1.22/virtualbox-5.1_5.1.22-115126\~Ubuntu\~trusty_amd64.deb
ᐅ sudo dpkg --install virtualbox-5.1_5.1.22-115126\~Ubuntu\~trusty_amd64.deb
ᐅ virtualbox --help | head -n 2
Oracle VM VirtualBox Manager 5.1.22
(C) 2005-2017 Oracle Corporation
Got everything? Great!
Grab the box
Let’s say you have chosen the ubuntu/trusty64
box as the foundation for the packer build.
Grab it!
ᐅ vagrant box add ubuntu/trusty64 --provider virtualbox
==> box: Loading metadata for box 'ubuntu/trusty64'
box: URL: https://atlas.hashicorp.com/ubuntu/trusty64
==> box: Adding box 'ubuntu/trusty64' (v20170530.0.1) for provider: virtualbox
box: Downloading: https://atlas.hashicorp.com/ubuntu/boxes/trusty64/versions/20170530.0.1/providers/virtualbox.box
==> box: Successfully added box 'ubuntu/trusty64' (v20170530.0.1) for 'virtualbox'!
The OVF
Now, we’ve “imported” this box into vagrant, but we need to tell Packer about a disk image it can use for the build (like an OVF file).
If we poke around Vagrant’s .path, we’ll find that OVF:
ᐅ ls -Alh ~/.vagrant.d/boxes/ubuntu-VAGRANTSLASH-trusty64/20170530.0.1/virtualbox
total 426M
426M Jun 1 07:41 box-disk1.vmdk
11K Jun 1 07:40 box.ovf
25 Jun 1 07:41 metadata.json
505 Jun 1 07:40 Vagrantfile
If you remember, we imported the 20170530.0.1
version of the ubuntu/trusty64
box. The pattern here is simple to see: ~/.vagrant.d/boxes/$REPO-VAGRANTSLASH-$BOX/$VERSION/$VM_PROVIDER/box.ovf
Packer build template
Let’s plug this into an example build template. We will use the virtualbox-ovf
builder to import the existing Vagrant box, some provisioners to customize that box, and finally the vagrant
post-processor to export our customizations as a new box that we can import into Vagrant:
{
"variables": {
"home": "{{env `HOME`}}",
"out_dir": "output-box",
"name": "base-host",
"box": "trusty64",
"repo": "ubuntu",
"version": "20170526.4.0"
},
"builders": [{
"type": "virtualbox-ovf",
"source_path": "{{user `home`}}/.vagrant.d/boxes/{{user `repo`}}-VAGRANTSLASH-{{user `box`}}/{{user `version`}}/virtualbox/box.ovf",
"ssh_username": "vagrant",
"ssh_password": "vagrant",
"ssh_wait_timeout": "90s",
"shutdown_command": "echo 'packer' | sudo -S shutdown -P now"
}],
"provisioners": [ ... ],
"post-processors": [{
"type": "vagrant",
"keep_input_artifact": true,
"output": "{{user `out_dir`}}/{{user `name`}}-{{user `repo`}}-{{user `box`}}-{{user `version`}}.box"
}]
}
Import into Vagrant!
ᐅ vagrant box add base-host output-box/base-host-ubuntu-trusty64-20170526.4.0.box