Browsing:

Category: Vagrant

Building a development environment with Vagrant, Packer, Windows 10 and Server 2016

Here is another post about creating Windows demo environments with Vagrant. This time we create our own Windows 10 LTSB and Windows 2016 CTP 5 core boxes from scratch with Packer.

packer

You can checkout the Packer templates on my Github page here: https://github.com/jacqinthebox/packer-templates.

TL;DR

For the impatient: I published my boxes at Hashicorp here. You can use them right away with Vagrant and Virtualbox. I'm currently writing Parallels providers as well.

Here is how.
Install Virtualbox and Vagrant for your OS.
Create a folderstructure on your machine for the Vagrant boxes. Then issue a 'vagrant init':

#Create a folder structure to host the Vagrant boxes 
#Can be named anything and placed anywhere you like
New-Item \Boxes\Win10 -Type Directory -Force; cd C:\Boxes\Win10

vagrant init jacqinthebox/windows10LTSB
vagrant up --provider Virtualbox

And now we wait!
When the box has finished downloading you can provision the box to your liking and sysprep it (there is an autounnattend.xml already in c:\logs).
I currently use this Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

$sysprep = <<'SYSPREP'
& $env:windir\system32\sysprep\sysprep.exe /generalize /oobe /unattend:C:\logs\unattend.xml /quiet /shutdown
SYSPREP

Vagrant.configure(2) do |config|
  config.vm.define "client01" 
  config.vm.box = "jacqinthebox/windows10LTSB"
  config.vm.hostname = "client01" 
  config.vm.network "private_network", ip: "192.168.56.10"
  config.vm.network :forwarded_port, guest: 3389, host: 33989, id: "rdp", auto_correct: true
config.vm.provision :shell, inline: $sysprep

end

The box comes with Chocolatey and Package Management preinstalled, so you can install Chrome with a simple:

Install-Package -Providername chocolatey googlechrome -ForceBootstrap -Force

OK, onto how the box was built and why.

Why build a Windows demo environment?

Indeed, why on earth would I want to build a demo environment? Well, I am a Powershell trainer. And I do most of my trainings at the customer premises. So there's no training equipment and I always ask my students to bring their own device. Now how would I make sure we are working on the same machines and the demo's work? Enter Vagrant.

Why not just create sysprepped golden images and clone them all the time?

I love Vagrant. I love automation! Here are some of my other Vagrant posts:

I did learn a lot in the meantime, so I will basically repeat everything in this post. And now Packer supports WinRM, so installing SSH on Windows is no longer necessary.

How to build the box with Packer

Install Vagrant, Virtualbox and Packer. I'm on Windows 10 and using OneGet, indeed, from the commandline! Hurray!

Install-Package -ProviderName Chocolatey - ForceBootstrap -Force vagrant,virtualbox,packer

Then clone the packer-templates Git repo:

git clone https://github.com/jacqinthebox/packer-templates.git

Now build the box like this and add it to Vagrant:

packer build -only virtualbox-iso windows_2016.json
vagrant box add --name windows_2016 windows_2016_virtualbox.box

How does Packer work?

Basically Packer builds the VM with parameters it reads from a json file.
This is the json file for the Windows 10 LTSB machine:

{
  "builders": [
    {
      "type": "virtualbox-iso",
      "iso_url": "{{user `iso_url`}}",
      "iso_checksum_type": "{{user `iso_checksum_type`}}",
      "iso_checksum": "{{user `iso_checksum`}}",
      "headless": false,
      "guest_additions_mode": "attach",
      "boot_wait": "2m",
      "communicator": "winrm",
      "winrm_username": "vagrant",
      "winrm_password": "vagrant",
      "winrm_timeout": "5h",
      "shutdown_command": "shutdown /s /t 10 /f /d p:4:1 /c \"Packer Shutdown\"",
      "shutdown_timeout": "15m",
      "guest_os_type": "Windows81_64",
      "disk_size": 61440,
      "floppy_files": [
        "{{user `autounattend`}}",
        "./answer_files/10/unattend.xml",
        "./scripts/bootstrap.ps1",
        "./scripts/sdelete.exe",
        "./scripts/oracle-cert.cer"
      ],
      "vboxmanage": [
        [
          "modifyvm",
          "{{.Name}}",
          "--memory",
          "2048"
        ],
        [
          "modifyvm",
          "{{.Name}}",
          "--cpus",
          "2"
        ]
      ]
    }
  ],
   "provisioners": [
    {
      "type": "powershell",
      "scripts": [
        "./scripts/provision.ps1"
      ]
    }
  ],
  "post-processors": [
    {
      "type": "vagrant",
      "keep_input_artifact": false,
      "output": "windows_10_{{.Provider}}.box",
      "vagrantfile_template": "vagrantfile-windows_10.template"
    }
  ],
  "variables": {
  
    "iso_url": "http://care.dlservice.microsoft.com/dl/download/6/2/4/624ECF83-38A6-4D64-8758-FABC099503DC/10240.16384.150709-1700.TH1_CLIENTENTERPRISE_S_EVAL_X64FRE_EN-US.ISO",
    "iso_checksum_type": "md5",
    "iso_checksum": "c22bc85b93eb7cc59193f12f30538f78",
     "autounattend": "./answer_files/10/Autounattend.xml"
   }
}

So, the whole creation process of a Vagrant box goes something like this:

  • Packer creates and configures the VM
  • Packer attaches the floppy files to the VM
  • It starts installing the OS, the Windows Installer grabs the answer file from the floppy
  • In the answer file the Vagrant user is created
  • In the answer file we will call a powershell script (bootstrap.ps1) which enables WinRM
  • As soon as WinRM is available, Packer will start provisioning scripts the box by executing provision.ps1
  • By running provision.ps1 the guest additions are installed and the box is compacted with sdelete.exe

Let's dissect parts of this the json file.

 "type": "virtualbox-iso",
 "iso_url": "{{user `iso_url`}}",
 "iso_checksum_type": "{{user `iso_checksum_type`}}",
 "iso_checksum": "{{user `iso_checksum`}}",

Here we declare that we are creating a Virtualbox vm.
The iso_url , iso_checksum_type and iso_checksum are variables, which are set in the variables block in the bottom of the file.

"headless": false,
"guest_additions_mode": "attach",
"boot_wait": "2m",
"communicator": "winrm",
"winrm_username": "vagrant",
"winrm_password": "vagrant",
"winrm_timeout": "5h"

We set headless to false to see what is going on. The guest_additions_mode is attach. Valid options are "upload", "attach", or "disable", but we choose attach because uploading the tools to the VM is not working via WinRM (it does work with SSH, but we are not using SSH). So we attach the guest additions iso and install the tools from there in the provision stage (more about that later). We set the winrm_timeout to 5h. This is the time Packer waits until WinRM becomes available.

"floppy_files": [
     "{{user `autounattend`}}",
     "./answer_files/10/unattend.xml",
     "./scripts/bootstrap.ps1",
     "./scripts/sdelete.exe",
     "./scripts/oracle-cert.cer"
      ],

This is the part where we define the scripts that are placed on the floppy disk that gets attached to the box.

  "provisioners": [
    {
      "type": "powershell",
      "scripts": [
        "./scripts/provision.ps1"
      ]
    }
  ],

This part is executed after WinRM is available. In the provison.ps1 script we enable RDP, install chocolatey, install the guest additions and last but not least the disk gets compacted with sdelete.exe.

So there it is! Clone the repo, check out the answer files and the scripts and build your boxes already!

Special thanks goes to..

This article: http://www.hurryupandwait.io/blog/creating-a-hyper-v-vagrant-box-from-a-virtualbox-vmdk-or-vdi-image and this Github repo: https://github.com/joefitzgerald/packer-windows.


Vagrant, Parallels and Windows guests

For all of you running a Mac, this is how to create a Windows guest with Vagrant and Packer.

packer
Packer

Vagrant supports Parallels 8 and higher, but please be aware that Vagrant only supports the Pro version of Parallels 11.

First install the plugin:

vagrant plugin install vagrant-parallels

Second, get the Parallels virtualization SDK here

Third, get Packer and unzip it in your Vagrant dir.

Fourth, clone packer-windows from Github.

git clone https://github.com/joefitzgerald/packer-windows

Now make sure the packer and the packer-windows executables are in the same folder. This makes the command easier because you don't need to think hard to make sure the paths to all the files and commands are right.

Fifth, download the Windows server iso upfront. I usually download the Windows Server iso first from here so that I don't have to wait for the download to finish during the packer build process.

Sixth, get this json config file for Parallels. You see that I put the iso from the fifth step on the desktop and reference it in the file.

Seventh, start building and grab coffee

./packer build -var iso_url=~/Desktop/9600.16384.WINBLUE_RTM.130821-1623_X64FRE_SERVER_EVAL_EN-US-IRM_SSS_X64FREE_EN-US_DV5.ISO windows_2012_r2_parallels.json 

And another coffee..

Screen Shot 2015-10-07 at 07.02.50

Step eight: add the template to vagrant

vagrant box add --name windows_2012_r2 windows_2012_r2_parallels.box

Step nine: create a Vagrant file

Create a folder named lab01 and put a Vagrantfile in it:

Vagrant.require_version ">= 1.6.2"

$root_provision_script = <<'ROOT_PROVISION_SCRIPT'
& $env:windir\system32\tzutil /s "W. Europe Standard Time"

ROOT_PROVISION_SCRIPT

Vagrant.configure("2") do |config|
    config.vm.define "lab01"
    config.vm.box = "windows_2012_r2"
    config.vm.hostname = "lab01" 
    config.vm.provider :virtualbox do |v, override|
        v.gui = false
        #v.customize ["modifyvm", :id, "--memory", 2048]
        #v.customize ["modifyvm", :id, "--cpus", 2]
    end


    config.vm.network :forwarded_port, guest: 3389, host: 3391, id: "rdp", auto_correct: true
    config.vm.network :forwarded_port, guest: 22, host: 2223, id: "ssh", auto_correct: true
    #config.vm.network "private_network", ip: "192.168.56.11"
    config.vm.provision "shell", inline: $root_provision_script
    #config.vm.provision "shell", path: "sysprep.ps1"
    

end

Then issue a 'vagrant up' and we're done.