Vagrant vs. Packer

Posted in automation on April 13, 2017 by Adrian Wyssmann ‐ 9 min read

When I started to investigate into tools which help to automate provision of virtual machines, I found packer and vagrant, both tools provided by Hashicorp.

When you are looking for provisioning tools you might sooner or later get in touch with Vagrant.

Vagrant is a tool for building and managing virtual machine environments in a single workflow. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases production parity, and makes the “works on my machine” excuse a relic of the past.

From the same company Hashicorp you also find a tool called Packer.

Packer is an open source tool for creating identical machine images for multiple platforms from a single source configuration. Packer is lightweight, runs on every major operating system, and is highly performant, creating machine images for multiple platforms in parallel.

Packer

As already mentioned Packer is used to create identical machine images from a single source configuration. Such a machine image are static and contains pre-configured operating system and software to quickly create new running machines. Before continuing it makes sense to get familiar with the packer specific terminology:

Builders

Builders are responsible to create a machine image for a specific platform like VMWare, VirtualBox Azure, etc. There are a lot of builders shipped with Packer but you also can add your own builder. Each builder comes with its own sets of configuration parameters. A builder expects either an ISO file - not supported by all providers - or an existing image as an input (e.g. a SKU in Azure) and always generate a builder-specific machine image as an output (e.g. ova, vhd, …).

Provisioners

Provisioning refers to installation and configuration activities (e.g. package installation, user creation, system patching etc. ) performed on a running machine. Packer itself doesn’t do any provisioning by itself - except uploading files to the machine - but rather uses other provisioning tools like a simple Shell or Ansible by means of provisioners. Provisioning happens on the running machine before the static image is created. For this Packer uses  which do the provisioning.

There are a lot of different provisioners shipped by default with Packer but also here, if you are missing something you may extend Packer with your own provisioner.

Communicators

Communicators is the mechanism Packer used to upload files or execute scripts. It is an essential configuration parameter in the template file and if not specified most provisioners will not work. There are basically two Communicators, one in SSH - which is used by default and WinRM. Each communicator comes with its configuration parameters which are documented on the Packer website.

Template Files

Packer only has few command line options, as creation of the images is controlled by the template files. A template is a JSON file which describes how to create one or more machine images. It follows a specific template structure which is described in detail on the respective page``. As already mentioned above it is important to provide the specific key-value pairs to the respective builder(s) and provisioner(s)

Vagrant

Vagrant is a command line tool to mange the lifecycle of virtual machines and supports quite a lot of different providers like Virtualbox, AWS and more. Sure one can use the the CLI interface of your platform to manage the lifecycle of your machine but each of them differs. With Vagrant you only have to learn one Vagrant  - even so Vagrant uses these utilities internally - it doesn’t matter for the Developer. Vagrant has some terms/artifacts which I will briefly explain below:

Vagrantfile

A Vagrantfile uses Ruby syntax to describe the type of machine, how to configure the machine and how to provision it. Beside of the common configuration parameters there are also provider-specific configuration parameters and provisioners-specific parameters which gives you decent control over your virtual machines and how they are provided to the end-user. A Vagrantfile defines the configuration in a block which looks like this:

Vagrant.configure("2") do |config|
  ## ...
end

As Vagrantfiles support backward compatibility, so you have to specify the version of the configuration object to be used - as of today its is either version “1” or"2″.  Also good to know is that most of the Vagrant commands work directly with a specific machine whereas the vagrant up command actually used the Vagrantfile.

Boxes

Boxes are the package format for Vagrant environment - you can see them as templates. The box files is a compressed file using tar, tar.gz, or zip containing an archive specific to a provider and a metadata.json hat specifies the name of the box, a description, available versions, available providers, and URLs to the actual box files (next component) for each provider and version. This is important: a box is provider-specific and are incompatible to each other so a box made for Virtualbox cannot be run on Hyper-V. All starts with a base box which you can create by your own or use existing boxes like the ones provided from HashiCorp’s Atlas.

A base box typically consists of only a bare minimum set of software for Vagrant to function. As an example, a Linux box may contain only the following:

  • Package manager
  • SSH
  • SSH user so Vagrant can connect
  • Perhaps Chef, Puppet, etc. but not strictly required.

In addition to this, each provider may require additional software.

Creating base boxes is provider-specific and time consuming and unless you use Packer to create reproducible builds for your base boxes it is manual work. So beginners usually start by using a base box from the HashiCorp’s Atlas box catalog. like

$ vagrant init hashicorp/precise64

or in your Vagrantfile:

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
end

Providers

Providers are plugins to manage machines running on different providers like Azure or VMWare. By default Vagrant ships providers for VirtualBox, Hyper-V, and Docker - whereas other can be installed via the Vagrant plugin system.

Provisioners

Provisioners in Vagrant are essentially the same as for Packer but in contrary to Packer, provisioning can happen at different moments

  • when the machine is started the first time
  • when provisioning is triggered or enforced on a running environment (vagrant provisioning or vagrant reload --provisioning)

Like with Packer, Vagrant has basically two ways of accessing the virtual machine: SSH and WinRM.

How to get started

As already mentioned the easiest way is to use an base box from HashiCorp’s Atlas box catalog - important to mention that this does not contain Windows boxes. So simply initialize your first box by vagrant init command

$ vagrant init hashicorp/precise64

Which creates an appropriate Vagrantfile:

Vagrant.configure("2") do |config|
  config.vm.box = "hashicorp/precise64"
end

Then you can start your machine with the vagrant up command

D:\Workspaces\Vagrant\Example1>vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Box 'hashicorp/precise64' could not be found. Attempting to find and install...
    default: Box Provider: virtualbox
    default: Box Version: >= 0
==> default: Loading metadata for box 'hashicorp/precise64'
    default: URL: https://atlas.hashicorp.com/hashicorp/precise64
==> default: Adding box 'hashicorp/precise64' (v1.1.0) for provider: virtualbox
    default: Downloading: https://atlas.hashicorp.com/hashicorp/boxes/precise64/versions/1.1.0/providers/virtualbox.box
    default: Progress: 100% (Rate: 12.3M/s, Estimated time remaining: --:--:--)
==> default: Successfully added box 'hashicorp/precise64' (v1.1.0) for 'virtualbox'!
==> default: Importing base box 'hashicorp/precise64'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'hashicorp/precise64' is up to date...
==> default: Setting the name of the VM: Example1_default_1491810153898_84120
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
==> default: Forwarding ports...
    default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: SSH address: 127.0.0.1:2222
    default: SSH username: vagrant
    default: SSH auth method: private key
    default:
    default: Vagrant insecure key detected. Vagrant will automatically replace
    default: this with a newly generated keypair for better security.
    default:
    default: Inserting generated public key within guest...
    default: Removing insecure key from the guest if it's present...
    default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
    default: The guest additions on this VM do not match the installed version of
    default: VirtualBox! In most cases this is fine, but in rare cases it can
    default: prevent things such as shared folders from working properly. If you see
    default: shared folder errors, please make sure the guest additions within the
    default: virtual machine match the version of VirtualBox you have installed on
    default: your host and reload your VM.
    default:
    default: Guest Additions Version: 4.2.0
    default: VirtualBox Version: 5.1
==> default: Mounting shared folders...
    default: /vagrant => D:/Workspaces/Vagrant/Example1

Packer and Vagrant provisioning

Both tools, Packer and Vagrant provide the possibility to perform provisioning. In addition, when you create your base images from a pure iso you also have the “answer file” from the unattended installation which does certain provisioning like network configuration or package installation.

Answer files: Are OS specific and are wasteful work to create, therefore I would only do the bare minimum which is basic installation of the OS and install the minimal packages. When it comes to base images for Linux you can pretty much forget “answer files” and rely on the boxes provided by Hashicorp. If you are interested in how the packages are created and how the unattended installation for them look like, checkout https://github.com/kaorimatz/packer-templates. For Windows the situation looks different as you might be able to create a base box from an iso and therefore have to fiddle with “answer files”.

Vagrant does not provide an automatic way to create base images from scratch (iso) so as recommended by Hashicorp you shall use Packer for this. But once you have a base image you can base on you might also use Vagrant to create re-usable packages from running VirtualBox or Hyper-V environments using the vagrant package command. Both tools provides provisioning via 3rd party Provisioners like Ansible or Chef so the provisioning scripts once written can be used by Packer and Vagrant. So unless you have to create images from scratch you probably only work with Vagrant and not with Packer.

At last, I would like to share my view of the provisioning concept using Packer and Vagrant.

Packer and vagrant provisioning concept
Packer and vagrant provisioning concept

This shall work for any provider so SCVMM could also be something else like ESX or Azure. The rest stays essentially the same. What do you think?