WavebreakMediaMicro - Fotolia

Create Vagrant boxes with Packer for rapid IT environment builds

Vagrant boxes enable IT admins to test infrastructure updates in production-identical QA environments. Follow this Vagrant tutorial to build a machine and export it to a Vagrant box.

While Vagrant and Packer are two HashiCorp tools designed for different needs, they can also work together nicely, especially in DevOps environments.

Packer creates a single, coded configuration of a machine build that runs on various platforms, such as a server on AWS or on Microsoft Azure.

Vagrant manages virtualized environments, mainly with testing rather than production systems. Vagrant boxes are useful as replicas of production systems for testing and prototyping purposes. In DevOps environments, application updates come rapidly from developers, an approach that requires an easily created and managed test environment for configuration changes before they hit live servers.

The creation of Vagrant boxes is where Packer and Vagrant intersect, by way of a post-processor task. The post-processor task in Packer exports a built machine to various platforms. In this tutorial, after Packer builds the machine, the post-processor task exports it to automatically create Vagrant boxes.

Start with Vagrant base boxes

A common reason DevOps engineers pick up Packer and Vagrant is ultimately to create a Vagrant base box, which contains the minimum setup for Vagrant to operate. Additional configuration instructions for an image, such as the shell scripts it must run and networking connections, are added via the Vagrantfile.

Base boxes typically include an installed package manager, as well as remote management connections, Secure Shell (SSH) for Linux or Windows Remote Management (WinRM). They might also contain a configuration management tool, such as Chef or Puppet.

Create a Packer build

To start this Packer and Vagrant tutorial, build a Windows 10 system in Packer. This example Packer build is a descendant of Stefan Scherer's Windows 10 template on GitHub. These steps take ISO for Windows 10 build 1803, install the OS in Oracle VM VirtualBox, run a few PowerShell scripts and then export the build to a Vagrant box.

{
  "builders": [‘
    {
      "boot_command": "",
      "boot_wait": "6m",
      "communicator": "winrm",
      "disk_size": "{{user `disk_size`}}",
      "floppy_files": [
        "{{user `autounattend`}}",
        "./scripts/Install-Software.ps1"
      ],
      "guest_additions_mode": "disable",
      "guest_os_type": "Windows10_64",
      "headless": "{{user `headless`}}",
      "iso_checksum": "{{user `iso_checksum`}}",
      "shutdown_command": "shutdown /s /t 10 /f /d p:4:1 /c \"Packer Shutdown\"",
      "iso_checksum_type": "{{user `iso_checksum_type`}}",
      "iso_url": "{{user `iso_url`}}",
      "type": "virtualbox-iso",
      "vboxmanage": [
        [
          "modifyvm",
          "{{.Name}}",
          "--memory",
          "6096"
        ],
        [
          "modifyvm",
          "{{.Name}}",
          "--cpus",
          "4"
        ]
      ],
      "vm_name": "windows_10",
      "winrm_password": "vagrant",
      "winrm_timeout": "{{user `winrm_timeout`}}",
      "winrm_username": "vagrant"
    }
  ],
  "variables": {
    "autounattend": "./answer_files/10/Autounattend.xml",
    "disk_size": "61440",
    "disk_type_id": "1",
    "headless": "false",
    "iso_url": "./iso/SW_DVD9_Win_Pro_Ent_Edu_N_10_1803_64BIT_English_-4_MLF_X21-87129.ISO",
    "iso_checksum_type": "sha256",
    "iso_checksum": "F38B0AEAE0756E01DCD9B1600DE62416E04AA963C72CEA30929141F54F1235B3",
    "restart_timeout": "5m",
    "vhv_enable": "false",
    "winrm_timeout": "6h"
  },
  "post-processors": [
    {
      "keep_input_artifact": false,
      "output": "windows_10_{{.Provider}}.box",
      "type": "vagrant",
      "vagrantfile_template": "vagrantfile-windows_10.template"
    }
  ]
}

There are a few things to point out in this Packer build. First, VirtualBox is the only provider on which the build will run. Packer can run builds in parallel. It is set to run headless, meaning the VM has no GUI by default. Many DevOps teams avoid GUIs on VMs, preferring automated steps in the DevOps pipeline over administrators doing tasks manually. Because the tutorial builds a Windows 10 box, WinRM is included to connect to the box instead of SSH. Lastly, a few variables, such as the ISO and ISO hash, are included and hardcoded for simplicity.

Set up the Vagrant post-processor

Next, let's explore the Vagrant post-processor in Packer.

There are several options to create a Vagrant box, in terms of parameters. For example, a DevOps engineer might add a Vagrantfile template that specifies the networking, port mapping and hardware to use, which get implemented during the initial provisioning of a Vagrant box on a client. In addition, users can configure a compression level and paths to files to include in the Vagrant box.

In the Vagrant post-processor in the Packer template below, we configure the type as Vagrant, as well as the template file and the output path of the box, which is prefixed with windows_10 and the Packer provider VirtualBox.

  "post-processors": [
    {
      "output": "windows_10_{{.Provider}}.box",
      "type": "vagrant",
      "vagrantfile_template": "vagrantfile-windows_10.template"
    }
  ]

Build the Vagrant box

Now, start the build process in Packer to create a Vagrant box.

Run the command packer build. There is no need for variables, since they are hardcoded in this template. The only other necessary parameter in packer build is the path to the JSON template file. With Scherer's GitHub repository for the Windows 10 Vagrant box cloned locally to the C:\Scripts\packer\test directory (see below), all of the required files are included in C:\Scripts\packer\test> packer build .\windows_10.json.

Since VirtualBox is the only provider in Packer for this tutorial, the output indicates that:

VirtualBox ISO

The Vagrant box post-processing task shuts down the Packer VM, removes the floppy drives and port mapping, and then creates the Vagrant Open Virtualization Format file, which contains metadata on the Vagrant box. Finally, multiple files are compressed in a Vagrant box file. The box contains the VM disk file (hard disk), JSON information (metadata) and the Vagrantfile template file (instructions to provision the Vagrant VM).

Boot up the Vagrant box

Now that Packer created the Vagrant box, add that box to a Vagrant client, and use it in a project.

First, use the local box file created from Packer to add the box:

C:\Scripts\packer\test\ > vagrant box add .\windows_10_virtualbox.box --name=windows_10

Next, create a new directory, and initialize the Vagrant box with the vagrant init command:

C:\Scripts\packer\test\> mkdir vagranttest
C:\Scripts\packer\test\> cd .\vagranttest\
C:\Scripts\packer\test\vagrantest> vagrant init window_10

Because this step builds a base box, the Vagrantfile created in the root directory is somewhat blank. This file contains the box name windows_10 used to load it via the vagrant up command:

C:\Scripts\packer\test\vagrantest> cat .\Vagrantfile | Select-String 'config.vm.box ='
  config.vm.box = "windows_10"

Finally, use vagrant up to boot up the box. Since VirtualBox is the only provider for the build, the box will boot into VirtualBox by default. The Vagrant template provided to Packer specifies to use port mapping of ports 3389, 22, 5985 and 5986, which display in the output:

Dig Deeper on Systems automation and orchestration

Software Quality
App Architecture
Cloud Computing
SearchAWS
TheServerSide.com
Data Center
Close