AKRABAT
One thing that would be useful for one of my projects is an easy way to install IIS, PHP & SQL Server on Windows in a repeatable way. I wasn’t sure how to do this until I came across Chocolatey and Boxstarter. Chocolatey is a package manager for Windows along the same lines as yum and apt for Linux and knows how to install a remarkable amount of software. Boxstarter is a way to automate installations of Windows using Chocolatey packages.
This is the start of my journey and I’ve not yet reached the destination I’m hoping to get to.
The Windows Vagrant base box
To start out I need a Windows base box for Vagrant. There doesn’t seem to be an obvious frequently-updated Windows Server 2016 Vagrant box out there, so I turned to Matt Wrock‘s article Creating windows base images using Packer and Boxstarter which provides a great overview on what to do. He even provides a GitHub repository of packer-templates which do the hard work.
I forked his repo and tweaked a few bits and then ran packer on my Mac and it generated a windows2016min-virtualbox.box base box.
To install into Vagrant, you can add to the Vagrant Cloud so that it’s easily shareable, or you can just add to your local vagrant with:
$ vagrant box add --name {your-org-name}/windows2016 windows2016min-virtualbox.box
For myself, I named my box 19ft/windows2016.
Vagrantfile
The initial Vagrantfile is quite simple:
# -*- mode: ruby -*- # vi: set ft=ruby : # Base box: https://github.com/akrabat/packer-templates Vagrant.configure("2") do |config| config.vm.box = "19ft/windows2016" config.vm.guest = :windows config.vm.boot_timeout = 600 config.vm.hostname = "WinDev" config.vm.network "private_network", ip: "192.168.99.201" config.vm.communicator = "winrm" config.vm.provider "VirtualBox" do |vb| # Display the VirtualBox GUI when booting the machine vb.gui = true # Customize the amount of memory on the VM: vb.memory = "2048" vb.cpus = 2 end end
We can then start our VM:
$ vagrant up
This will fire up Virtualbox with Windows 2016 in a GUI that you can log into. There are two users: Administrator and Vagrant, both have the same password: vagrant.
You may want to turn on VirtalBox’s shared clipboard from the Devices menu.
The next step is to automate installing some software on it.
Automating software installation
We can use Chocolatey controlled by Boxstarter install useful software.
Firstly we need to add a provisioning script to our Vagrantfile
:
config.vm.provision "shell", privileged: "true", inline: <<-'POWERSHELL' Set-TimeZone "Coordinated Universal Time" # Install Boxstarter . { iwr -useb https://boxstarter.org/bootstrapper.ps1 } | iex; Get-Boxstarter -Force # Copy setup.ps1 to the Temp directory and then run boxstarter with our setup.ps1 script $env:PSModulePath = "$([System.Environment]::GetEnvironmentVariable('PSModulePath', 'User'));$([System.Environment]::GetEnvironmentVariable('PSModulePath', 'Machine'))" cp C:vagrantsetup.ps1 $env:TEMP Import-Module Boxstarter.Chocolatey $credential = New-Object System.Management.Automation.PSCredential("vagrant", (ConvertTo-SecureString "vagrant" -AsPlainText -Force)) Install-BoxstarterPackage $env:TEMPsetup.ps1 -Credential $credential POWERSHELL
If we vagrant destroy the the current VM and then run vagrant up again, Vagrant will run our inline provisioning script which will install Boxstart which will then run setup.ps1
setup.ps1 is the script that contains the instructions for setting up Windows and installing various software. My initial one looks like this:
# Boxstarter setup script # Notes: # - This file has to be idempotent. it will be run several times if the # computer needs to be restarted. When that happens, Boxstarter schedules # this script to run again with an auto-logon. Fortunately choco install # handles trying to install the same package more than once. # - Pass -y to choco install to avoid interactive prompts # Fix Windows Explorer Set-WindowsExplorerOptions -EnableShowHiddenFilesFoldersDrives -EnableShowProtectedOSFiles -EnableShowFileExtensions -EnableShowFullPathInTitleBar # Useful apps choco install -y googlechrome choco install -y firefox choco install -y 7zip choco install -y notepadplusplus choco install git -y -params '"/GitAndUnixToolsOnPath /NoAutoCrlf"' Install-ChocolateyPinnedTaskBarItem "${env:ProgramFiles(x86)}GoogleChromeApplicationchrome.exe" Install-ChocolateyPinnedTaskBarItem "${env:ProgramFiles(x86)}Mozilla Firefoxfirefox.exe" # SQL Server choco install -y sql-server-2017 --params='/SAPWD="Indigo12!" /SECURITYMODE=sql' choco install -y sql-server-management-studio # IIS choco install -y IIS-WebServerRole -source windowsfeatures choco install -y IIS-WebServer -source windowsfeatures choco install -y IIS-CommonHttpFeatures -source windowsfeatures choco install -y IIS-StaticContent -source windowsfeatures choco install -y IIS-DefaultDocument -source windowsfeatures choco install -y IIS-DirectoryBrowsing -source windowsfeatures choco install -y IIS-HttpErrors -source windowsfeatures choco install -y IIS-ApplicationDevelopment -source windowsfeatures choco install -y IIS-CGI -source windowsfeatures choco install -y IIS-HealthAndDiagnostics -source windowsfeatures choco install -y IIS-HttpLogging -source windowsfeatures choco install -y IIS-LoggingLibraries -source windowsfeatures choco install -y IIS-RequestMonitor -source windowsfeatures choco install -y IIS-Security -source windowsfeatures choco install -y IIS-RequestFiltering -source windowsfeatures choco install -y IIS-HttpCompressionStatic -source windowsfeatures choco install -y IIS-WebServerManagementTools -source windowsfeatures choco install -y IIS-ManagementConsole -source windowsfeatures choco install -y IIS-ManagementScriptingTools -source windowsfeatures choco install -y WAS-WindowsActivationService -source windowsfeatures choco install -y WAS-ProcessModel -source windowsfeatures choco install -y urlrewrite # PHP choco install -y php --package-parameters="/InstallDir:C:PHP"
When the script runs it sets some configuration options on Windows Explorer and then install Chrome. Chrome requires a restart, so Boxstarter notes that a restart is required, so will store the information required in order to start up again after the reboot and then initiate the reboot.
Vagrant doesn’t handle this well and will fail with a message something like this:
Chocolatey installed 1/1 packages. 0 packages failed. See the log for details (C:ProgramDatachocolateylogschocolatey.log). Boxstarter: found C:UsersvagrantAppDataLocalBoxstarterBoxstarter.1648.restart we are restarting ++ Boxstarter finished Calling Chocolatey to install tmpF47D.tmp. This may take several minutes to complete... 00:29:24.5097146 Boxstarter: writing restart file Boxstarter: Restore Automatic Updates from Windows Update Boxstarter: UAC Enabled. Disabling... Boxstarter: Disabling UAC Boxstarter: Securely Storing WINDEVvagrant credentials for automatic logon Boxstarter: Logon Set Boxstarter: Restart Required. Restarting now... Errors : {} ComputerName : localhost Completed : True FinishTime : 11/12/2019 1:59:01 PM StartTime : 11/12/2019 1:29:21 PM Stderr from the command:
Don’t worry though, the VM will restart and Boxstarter will continue. As there’s no way to monitor this through Vagrant, having the GUI available is useful so we can watch it work. Boxstarter will the go on and install a Firefox, NotePad++, git, SQL Server, IIS and PHP for me with no intervention required.
Note that provisioning takes a long while. At the end though, we have Sql Server and IIS/PHP installed. We can then use vagrant package if we want to store the state at this point should we wish to.
All done
I’m a fan of scripted set up of infrastructure as I’m much more likely to be able to repeat it and share with team members. With Boxstarter and Chocolatey, it has been a nice surprise that I can build a Windows Vagrant VM mostly automatically in the same way I can with Linux.
It’s not pain-free though as it seems far less robust and sometimes I have to re-run the boxstarter script which is irritating, but not the end of the world.
The full Vagrantfile and setup.ps1 are in this gist.
Source: AKRABAT