Microsoft & .NET.NETVirtualize Your Windows Development Environments with Vagrant, Packer, and Chocolatey, Part 2

Virtualize Your Windows Development Environments with Vagrant, Packer, and Chocolatey, Part 2

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

Editor’s Note: This is Part 2 of a two-part article. The first part has already been published.

Use Case 2: Deploy the ASP.NET MVC Application and Share the Web Link to Others

If you have an ASP.NET MVC application that is running in IIS 8.5 on a production server of Windows Server 2012 R2 and would like to deploy to a similar environment for development and testing purpose and share the local deployed web application, please follow the steps mentioned below. Let’s use base box “WinServer2012R2” that was created in Use Case 1 to start with.

Steps:

  1. Script the installation of the IIS web server and webdeploy./p>
    Import-Module ServerManager
    $features = @(
       "Web-WebServer",
       "Web-Static-Content",
       "Web-Http-Errors",
       "Web-Http-Redirect",
       "Web-Stat-Compression",
       "Web-Filtering",
       "Web-Asp-Net45",
       "Web-Net-Ext45",
       "Web-ISAPI-Ext",
       "Web-ISAPI-Filter",
       "Web-Mgmt-Console",
       "Web-Mgmt-Tools",
       "NET-Framework-45-ASPNET"
    )
    Add-WindowsFeature $features -Verbose
    iex ((new-object net.webclient).DownloadString
       ('https://chocolatey.org/install.ps1'))
    choco install webdeploy
    

    Listing 3: PowerShell script for installation of the IIS web server and webdeploy

    Listing 3 is a PowerShell script that uses a ServerManager module to install IIS features and Chocolatey to install webdeploy. Save this as “provision-web.ps1” in the same directory where you initialized the Vagrant box (the directory where Vagrantfile is located).

  2. Associate the installation script to the provision section of Vagrantfile.
    config.vm.provision "shell", path: "provision-web.ps1"

    The preceding line should be in the Vagrantfile.

  3. Forward guest port 80 to host machine port 8080.
    config.vm.network "forwarded_port", guest: 80,
       host: 8080, id: "iis-defaultsite"
    
  4. Run the virtual machine.
    vagrant up

    If your virtual machine is already running, use the following command.

    vagrant reload -provision
  5. Web deploy the ASP.NET MVC application with a Visual Studio publish feature.

    Because guest virtual machine port 80 is mapped to host machine 8080, deploy the application to URL http://127.0.0.1:8080, as shown in Figure 6. Please use the credential that was created while creating the base box.

    Virtualize06
    Figure 6: Visual Studio Publish Web options to Windows Server 2012 R2 Virtual Server

  6. Access to the deployed web application locally with URL http://127.0.0.1:8080/.
  7. Create an account with vagrant cloud if you do not have one and log in from the command line.

    Vagrant cloud URL – https://vagrantcloud.com

    vagrant login

    Virtualize07
    Figure 7: Vagrant login successful message

    Figure 7 shows the interactive “vagrant login” command that prompts for a username and login.

  8. Vagrant share to get a public URL to the deployed web application on the guest virtual machine and share it with others.
    vagrant share -http 8080

    The preceding command instructs Vagrant to share HTTP port 8080 (which is mapped port to 80 of the guest virtual machine running Windows 2012 Server R2). Grab the public URL generated by command output and share it with other, as shown in Figure 8.

    Virtualize08
    Figure 8: Vagrant share command output

    As we can see in Figure 8, the URL generated was http://creative-bear-9962.vagrantshare.com. To stop sharing, press Ctrl+C. Please note, every time we use the Vagrant share command, a new URL would be generated.

Use Case 3: Create a Plain Windows 2012 R2 and Make It a Development Virtual Machine by Provisioning Visual Studio 2013 and SQL Server 2012 Express with Vagrant

In the previous scenario, we saw how to deploy the application to a IIS server for Windows 2012 R2 server. In this scenario, we will make the Windows 2012 R2 server as a development machine by provisioning Visual Studio 2013 and SQL Server 2013. We will use the same box that was created in Use Case 1 and script the additional software installation to make it a development box.

Steps:

  1. Navigate to the directory where you initialized the Vagrant box (created in Use Case 1).
  2. Script the development tools installation.
    iex ((new-object net.webclient).DownloadString
       ('https://chocolatey.org/install.ps1'))
    choco install VisualStudio2013Ultimate
    choco install MsSqlServer2012Express
    

    Save the above PowerShell script to a file as “dev-tools.ps1“. Please note that the Chocolatey install instructions will install trial versions of Visual Studio and Express Edition of SQL Server 2012. Please look into these packages at the Chocolatey site to further customize the installation process.

  3. Associate this script file to the provision section of the Vagrant file.
    config.vm.provision "shell",
       path: " dev-tools.ps1"
    
  4. Run the virtual machine.
    vagrant up
  5. RDP and start working on the development machine.
    vagrant rdp

Use Case 4: Create a Windows 2012 R2 Development Base Box and Share It with the Team

In Use Case 3, we used a plain Windows Server 2012 R2 box and provisioned it with development tools with Vagrant. This would be applicable to an instance only that is initialized with the command “vagrant up“. Other team members can use the base box and provision it with different development tools. This makes team members use individual development tools and do development. But, any team might like to have its team members use same set of development tools to have consistency and standards being followed.

To achieve this, we should provision the required development tools while creating the base box itself so that all team members can inherit the same set of tools for development and further customize with a Vagrant provision for additional software. Let’s see how we can do this in this scenario.

Steps:

  1. Git clone the repo https://github.com/joefitzgerald/packer-windows and navigate to the packer-windows folder.
  2. Create a shell script for development tools installation.
    iex ((new-object net.webclient).DownloadString
       ('https://chocolatey.org/install.ps1'))
    choco install VisualStudio2013Ultimate
    choco install Robomongo
    

    Save the previous PowerShell script as “dev-tools.ps1” to the scripts folder. Add the required Chocolatey-based installation for your requirements. In this case, I just need Visual Studio 2013 for application development and robomongo, a mongodb client tool.

  3. Associate the PowerShell script to the windows_2012_r2.jsonfile.
    {
       "type": "shell",
       "remote_path": "C:/Windows/Temp/dev-tools.ps1",
       "script": "./scripts/dev-tools.ps1",
       "execute_command": "Powershell.exe
          -executionpolicy unrestricted -File {{.Path}}"
    }
    

    Add the preceding JSON provisioner to the windows_2012_r2.json provisioner array element. This instructs Packer to copy the file dev-tools.ps1 from its current directory on the host machine to location C:/Windows/Temp/ on the guest virtual machine and execute it.

  4. Validate the JSON configuration.
    packer validate windows_2012_r2.json

    If there are any errors, correct accordingly and validate again.

  5. Build a VirtualBox Vagrant base box.
    packer build windows_2012_r2.json
  6. Distribute the generated box file to team members.

    Distribute the box file that is generated out of the Packer build command to team members. Each team member can use commands such as “vagrant box add” to add the box file to their Vagrant box list, “vagrant init <boxname>” to initialize the box, “vagrant up” to run the virtual machine, “vagrant rdp” to remote into and work, “vagrant halt” to shut down the running virtual machine, and “vagrant destroy” to dispose the virtual machine completely. For details on these commands, refer to Use Case 1.

Use Case 5: Create a Windows Box from the Existing VirtualBox Windows 2012 R2 Virtual Machine, That Is Manually Provisioned with the Required Tools and Software, and Share It with the Team

In a few cases, we might have had already provisioned the virtual machine with required software and necessary software configuration that you would like to share it with team. We can make this a reusable box and share it with other team members to save team members’ valuable time.

Steps:

  1. Package the configured virtual machine that is provisioned with VirtualBox.
    vagrant package --base <virtualbox-virtual-machine-name>

    Note: The package command works only with a irtual machine running in VirtualBox. Any other virtual machine management software, like yper-V or VMWare, will be addressed in future releases of Vagrant.

  2. Distribute the generated box file to team members.

    Distribute the box file that is generated out of the Packer build command to team members. Each team members can use commands like “vagrant box add” to add the box file to their vagrant box list, “vagrant init <boxname>” to initialize the box, “vagrant up” to run the virtual machine, “vagrant rdp” to remote into and work, “vagrant halt” to shut down the running virtual machine, and “vagrant destroy” to dispose the virtual machine completely. For details on these commands, refer to Use Case 1.

Use Case 6: Create a Windows 2012 R2 Development Base Box, Linux VM Provisioned with MongoDB, and Have Team Members Use Both Boxes with One Single Command

If you have a requirement of web application that is targeted to run on a IIS server of Windows Server box and the data to be persisted in a Linux operating system-based database, for development purpose you would need two Vagrant boxes initialized individually. But, what if you would like to have one configuration file that is capable of configuring and run both boxes with one single command? Yes, this is possible with the Vagrant multi-machine feature. With this feature, you can define the requirements of two machines in one single configuration file and distribute to your team members to run the boxes on their host machines easily.

Note: We will be using the Windows 2012 R2 development base box that we generated in Use Case 4.

Steps:

  1. Add the Windows 2013 R2 development case box to the Vagrant box list,
    To the Vagrant box, add Win2012R2VSandDevTools windows_2012_r2_dev_virtualbox.box,
  2. Navigate to a new folder with any name of your choice.
    C:SureshOfficialvagrantMultimachine
  3. Script the MongoDB installation for the Ubuntu operating system.
     1. #!/usr/bin/env bash
     2.
     3. echo ">>> Installing MongoDB"
     4.
     5. # Get key and add to sources
     6. sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80
           --recv 7F0CEB10
     7. echo 'deb http://downloads-distro.mongodb.org/repo/ubuntu-upstart dist 10gen'
           | sudo tee /etc/apt/sources.list.d/mongodb.list
     8.
     9. # Update
    10. sudo apt-get update
    11.
    12. # Install MongoDB
    13. # -qq implies -y --force-yes
    14. sudo apt-get install -qq mongodb-org
    15.
    16. # Make MongoDB connectable from outside world without SSH tunnel
    17. if [ $1 == "true" ]; then
    18.    # enable remote access
    19.    # setting the mongodb bind_ip to allow connections from everywhere
    20.    sed -i "s/bind_ip = */bind_ip = 0.0.0.0/" /etc/mongod.conf
    21.    sudo service mongod restart
    22. Fi
    

    Listing 4: MongoDB installation script

    The following points describe the code mentioned in Listing 4:

    • This is a shell script for installing MongoDB on the Ubuntu operating system.
    • Line 6 imports the public key used by the package management system.
    • Line 7 creates a list file.
    • Line 10 issues the command to reload the package database.
    • Line 14 command does a silent installation of MongoDB.
    • Linea 20 and 21 make MongoDB accessible from any IP address outside so that I can access from different servers (please note this is conditional execution based on arguments passed to this script).

    Save this script as “mongodb.sh“.

  4. Initialize Vagrant to produce a Vagrantfile.
    vagrant init

    This command produces the Vagrantfile that is to be configured.

  5. Edit the Vagrantfile to define multi machine configuration.
     1. # -*- mode: ruby -*-
     2. # vi: set ft=ruby :
     3.
     4. # Vagrantfile API/syntax version. Don't touch unless you 
          know what you're doing!
     5. VAGRANTFILE_API_VERSION = "2"
     6.
     7. Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
     8.
     9.    config.vm.define "devtools" do |devtools|
    10.    devtools.vm.box = "Win2012R2VSandDevTools"
    11.    devtools.vm.communicator = "winrm"
    12.
    13.    # Admin user name and password
    14.    devtools.winrm.username = "vagrant"
    15.    devtools.winrm.password = "vagrant"
    16.
    17.    devtools.vm.guest = :windows
    18.    devtools.windows.halt_timeout = 15
    19.
    20.    devtools.vm.network :forwarded_port, guest: 3389,
              host: 3393, id: "rdp", auto_correct: true
    21.    devtools.vm.network :forwarded_port, guest: 22,
              host: 2222, id: "ssh", auto_correct: true
    22.    devtools.vm.network "forwarded_port",
              guest: 80, host: 8080, id: "iis-defaultsite"
    23.    devtools.vm.network "private_network",
              ip: "192.168.33.12"
    24.    end
    25.
    26.    config.vm.define "db" do |db|
    27.    db.vm.box = "hashicorp/precise64"
    28.    db.vm.network "private_network",
              ip: "192.168.33.13"
    29.    config.vm.provision "shell", path: "mongodb.sh",
              args: "true"
    30.    end
    31.
    32. End
    

    Listing 5: Multi-machine Vagrant Configuration Script

    The following points describe the code mentioned in Listing 5:

    • The listing is a multi-machine Vagrantfile configuration script.
    • Edit your generated Vagrant file to have the script shown.
    • Because the Vagrantfile configuration script has Ruby syntax, we can define multiple sub blocks within the main config block. As we have a requirement to configure two boxes, we will define two sub blocks.
    • Lines 9 to 24 define a sub block called “devtools”; this defines all configurations for the Windows development box.
    • Line 10 instructs Vagrant to use a box named “Win2012R2VSandDevTools” that we have added to the list as part of Step 1.
    • Any assignments that follow the patterns of devtools.<prop>.<sub-property> will be applied to the devtools box.
    • Line 20 is a forwarded port for RDP access.
    • Line 23 defines a private network with an assigned IP address. Please note, with a forward port, the host machine can only access the guest machine and not vice versa. For complex networking requirements, we can use the private network feature of Vagrant. In this case, we would like to have both boxes communicate with each other, so we are defining a private network with an assigned IP address.
    • Lines 26 to 30 define a sub block called “db”, and its base box “hashicorp/precise64” in Line 27. Vagrant gets this from VagrantCloud in case if you do not have it in Vagrant cached boxes. This box is the Ubuntu operating system distributed by Vagrant itself.
    • Line 28 defines a private network with the same network that was defined for the “devtools” box also but with a different last octet.
    • Line 29 associates the MongoDB.sh shell script file as part of provisioning the Ubuntu box with one argument being passed as true (to enable MongoDB accessible from any IP address).
  6. Run the development and database boxes
    vagrant up

    This command will bring up both machines online.

  7. Remote/ssh into respective boxes to start development work.

    Because there are two machines running now with one Vagrant configuration, we need to explicitly mention the box name to the remote desktop into or SSH into.

    vagrant rdp devtools
    vagrant ssh db

    Please note that, to SSH into a Linux box, you need an SSH client. By default, you will not be able to use the preceding command from the command prompt or PowerShell. I used a Git command line client tool that has an SSH client to execute the vagrant SSH command.

    You can see these boxes in their running state if you open the Oracle VM VirtualBox Manager GUI tool, as shown in Figure 9.

    Virtualize09
    Figure 9: Visual Indication of two boxes running with Oracle VM VirtualBox Manager

    You now can connect MongoDB running on the “db” Linux box from the “devtools” box by using the client tool Robomongo that is available in “devtools”. Figure 10 shows two machines, one RDP to “devtools” box and the other SSH to “db”. Also, Figure 10 depicts a Windows box with the obomongo tool connected to MongoDB on IP address 192.168.33.13, which is the “db” box. And, “db” is connected with the Git client command tool because it has the SSH client.

    Virtualize10
    Figure 10: Guest VMs with Windows Server connected to MongoDB on the Ubuntu virtual machine

Summary

In this article, we have seen the challenges that a developer would face in maintaining different software for different projects, and how open source tools like Vagrant, Packer, and Chocolatey help in overcoming these challenges. Although in this article, I have used Vagrant on a Windows desktop, it works same on other major platforms like Mac or any Linux distribution. And, I also used VirtualBox as a provider for Vagrant, but you can use any other providers like VMWare, Hyper-V, Docker, or any custom provider.

References

Vagrant: https://www.vagrantup.com/

Packer: https://www.packer.io/

Chocolatey: http://chocolatey.org/

Windows build starter templates for Packer: https://github.com/joefitzgerald/packer-windows

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories