Image for post
Image for post

VirtualBox and Friends on Windows 8.1

VirtualBox, Vagrant, Test Kitchen, Docker Machine, Minikube

Introduction

Across macOS, Windows, and Linux, you’ll find these two popular tools of awesomeness: Vagrant and VirtualBox.

Image for post
Image for post

Vagrant allows you to automate creation and provisioning of disposable systems and infrastructure with ease, using a variety of backend virtualization solutions, with the free open source VirtualBox.

You can provision a system using CFEngine, CAPS (Chef, Ansible, Puppet, Salt Stack), Docker, shell scripts, etc. Vagrant supports them all, and more through rich a plug-in community.

Image for post
Image for post

As you develop change configuration scripts, you may want to validate the results using test automation scripts. There’s a tool just for this, that can orchestrate Vagrant and run tests: Test Kitchen.

Image for post
Image for post

If you use some immutable production patterns, where instead of configuring systems, you run pre-configured disposable Linux containers with Docker, using a tool called Docker Machine. This tool will create a sandboxed Docker environment using a small Linux guest system created on VirtualBox.

Image for post
Image for post

For orchestrating Docker containers, Kubernetes is now the most popular platform for this. You can run a Kubernetes cluster using Minikube, which in the background using Docker Machine.

This is a tutorial that demonstrates how to install and use on a Windows 8.1 host. The instructions will run in PowerShell console running as Administrator mode.

Required Prerequisite

Microsoft Windows does not have a package management system for installing FOSS (free and open-source software).

Image for post
Image for post

We can work around this limitation by installing Chocolatey. This will require administrative access to your computer, and you need run PowerShell with Run an Administrator option. If you have PowerShell pinned to your task bar, you can right click and access the option:

Image for post
Image for post

When you bring PowerShell with Run as Administrator mode, type this to get Chocolatey:

# Set privilege for running scripts
Set-ExecutionPolicy Bypass -Scope Process -Force
# variables for readibility
$scripturl = 'https://chocolatey.org/install.ps1'
$wc = New-Object System.Net.WebClient
# Install Chocolately
Invoke-Expression ($wc.DownloadString($scripturl))

When installing Chocolatey packages, you will need to update the environment to get access to the newly installed packages. Instead of closing and re-opening PowerShell windows, here’s a convenience function for updating the environment:

Function Update-Environment
{
$m = [System.Environment]::GetEnvironmentVariable("Path","Machine")
$u = [System.Environment]::GetEnvironmentVariable("Path","User")
$env:Path = $m + ";" + $u
}

If you open up a new PowerShell window for any reason, make sure to use this function again to easily update the environment after installing a Chocolatey package.

Virtualbox

Image for post
Image for post

The central cross platform tool (Linux, Windows, macOS) to make all of this magic work is VirtualBox.

Installing VirtualBox

With Chocolatey, you can install VirtualBox by running this

choco install -y virtualbox
Update-Environment

Afterward, we can check to see if it is installed:

# Test Version
vboxmanage --version
5.2.16r123759

Vagrant

Image for post
Image for post

Vagrant automates virtual machines and containers. It is essentially an orchestrator to juggle running different systems and quickly provision them with your favorite change configuration solution, like shell, CFEngine or CAPS (Chef, Ansible, Puppet, Salt Stack).

With Vagrant, we can easily download and run system images from Vagrant Cloud or other sources, or even run images you created locally with a tool like Packer).

Installing Vagrant

We can install Vagrant easily with:

choco install -y vagrant

Using Vagrant: Manjaro Linux on Windows

In this demo, let’s run a popular Linux distro called Manjaro. The box will be downloaded from the Vagrant Cloud.

mkdir $home/mymanjaro
cd $home/mymanjaro
vagrant init mloskot/manjaro-i3-17.0-minimal
vagrant up

Now let’s do something a little more colorful, and download and install screenFetch on our virtual guest:

$url = 'https://github.com/KittyKatt/screenFetch/archive/master.zip'
vagrant ssh --command "curl -OL $url"
vagrant ssh --command 'sudo pacman -S unzip'
vagrant ssh --command 'unzip master.zip'
vagrant ssh --command './screenFetch-master/screenfetch-dev'

This will display something like following:

Image for post
Image for post
ScreenFetch running on Manjaro Linux

Using Vagrant: Windows on Windows

We can run through this same process with another image built by Matt Wrock’s Windows Packer scripts:

# add recently build vagrant box to Vagrant (path varies)
$winboxpath = 'path\to\windows2016min-virtualbox.box'
vagratbox add $winboxpath --name 'my/win2016'
# create staging area
mkdir
$home\mywindows
cd $home\mywindows
# create local copy and start instance
vagrant init my/win2016
vagrant up

From here, we need to be able to log into an interactive bash shell to run screenFetch. We can get a bash shell by installing MSYS2. And we can install MSYS2, which we can install using Chocolatey package management system on our guest system.

On a Windows host, we can remote into the system through winrm mechanism (make sure to do this from PowerShell console in Run As Administrator mode):

vagrant powershell

Afterward, we can run a few commands to investigate our guest environment:

cmd /c verMicrosoft Windows [Version 10.0.14393]$PSVersionTable.PSVersionMajor  Minor  Build  Revision
----- ----- ----- --------
5 1 14393 0

In the same remote PowerShell session on the guest, type these commands:

Function Update-Environment
{
$m = [System.Environment]::GetEnvironmentVariable("Path","Machine")
$u = [System.Environment]::GetEnvironmentVariable("Path","User")
$env:Path = $m + ";" + $u
}
Set-ExecutionPolicy Bypass -Scope Process -Force$scripturl = 'https://chocolatey.org/install.ps1'
$wc = New-Object System.Net.WebClient
Invoke-Expression ($wc.DownloadString($scripturl))
Update-Environment
choco install -y bitvise-ssh-server
Start-Service BvSshServer
choco install -y msys2

Now that SSH server is running, we can log into through SSH and get a command shell prompt, and start up a bash session:

vagrant ssh  # user/password = vagrant# start bash session
c:\tools\msys64\usr\bin\bash.exe

From bash shell, we can now install and run screenFetch:

# install unzip package
PATH
=/usr/bin:$PATH
pacman -S unzip
# install screenfetch
URL=https://github.com/KittyKatt/screenFetch/archive/master.zip
curl -OL $URL
unzip master.zip
# run screenfetch
./screenFetch-master/screenfetch-dev

This will give us:

Image for post
Image for post
ScreenFetch running on MSYS2 on Windows Server 2016

Test Kitchen

Image for post
Image for post

Test Kitchen is a test harness, and similar to Vagrant, in that it orchestrates several systems, provisions them, and then facilitates running tests on them. Test Kitchen in fact uses Vagrant as the backend driver to create the virtual guest systems, but can be configured to use Docker or other backends.

Installing Test Kitchen

For demonstration purposes, and easy scaffolding, we’ll install Test Kitchen using ChefDK set of tools:

choco install -y chefdk

Using Test Kitchen with ChefDK

For this small demo, we can use the Chef to auto-generate a cookbook, which includes a default Test Kitchen configuration:

Image for post
Image for post
Test Kitchen configuration

To get started, we generate a cookbook, and bring up the environment.

cd $home
# Generate example
chef generate cookbook helloworld
cd helloworld
# Create Ubuntu and CentOS systems
kitchen create

This will create Ubuntu and CentOS systems using Vagrant as the backend driver. We can then view the running systems with kitchen list:

Image for post
Image for post

Run Something on Test Systems

Let’s download a screenFetch shell script locally:

$path = "$home\.kitchen\cache"# Download Archive
$url = 'https://github.com/KittyKatt/screenFetch/archive/master.zip'
$wc = New-Object System.Net.WebClient
[Net.ServicePointManager]::SecurityProtocol = "tls12, tls11, tls"
$wc.DownloadFile($url, "$path\master.zip")
# Unzip Archive
Add-Type -AssemblyName System.IO.Compression.FileSystem
function Unzip
{
param([string]$zip, [string]$out)
[System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $out)
}
Unzip "$path\master.zip" "$path\"

The $home\.kitchen\cache is a global shared directory for all Vagrant guest systems managed by Test Kitchen. We can exchange files between the host and virtual guest systems using this mechanism.

With screenFetch script available from the shared directory, let’s use it across all systems.

# Install pciutils on CentOS (required by screenfetch)
kitchen exec centos --command='sudo yum -y install pciutils'
# Install a snap on Ubuntu (avoids warnings w/ screenfetch)
kitchen exec ubuntu --command='sudo snap install hello-world'
# Run screenfetch script on all systems
kitchen exec default* `
--command='sudo /tmp/omnibus/cache/screenFetch-master/screenfetch-dev'

This will print something pretty for all clients:

Image for post
Image for post
Screenfetch script on all test-kitchen clients

Docker Machine

Image for post
Image for post

Docker Machine is an automation tool that can spin up a virtual system for facilitating Docker. Specifically on Windows, you have to run Docker on a virtual guest, as Linux containers automated by Docker only run on Linux. Docker Machine automates this process.

Install Docker Toolbox

Image for post
Image for post

We can get a recent version of Docker Machine from Docker Toolboxpackage. This will also install the Docker client as well.

choco install -y docker-toolbox
Update-Environment

Using Docker

With these tools installed, let’s run some containers, using Docker client on the host after starting a Docker daemon running on a virtual system:

# Create a docker machine environment called default
docker-machine create --driver virtualbox 'default'
# Tell docker engine to use machine's docker (defaulting to default)
& docker-machine env default | Invoke-Expression
# Run a container fetched from docker hub
docker run docker/whalesay cowsay Hello World
_____________
< Hello World >
-------------
\
\
\
## .
## ## ## ==
## ## ## ## ===
/""""""""""""""""___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\______/

Minikube

Image for post
Image for post

Minikube allows you to run Kubernetes cluster locally. It leverages off of Docker Machine to create a single-node Kubernetes cluster.

Installing Minikube and Kubectle Client

Install Minikube and kubectl using Chocolatey:

choco install -y minikube
Update-Environment

Using MiniKube

We can now start up our cluster and deploy some containers on our cluster. When we start up Minikube, it will make the necessary client configurations needed for kubectl.

# Start minikube environment
minikube start --vm-driver=virtualbox
# Deploy Something
kubectl run hello-minikube `
--image=k8s.gcr.io/echoserver:1.4 `
--port=8080
kubectl expose deployment hello-minikube `
--type=NodePort

We check to see if the pod(s) are running.

kubectl get pod
NAME READY STATUS RESTARTS AGE
hello-minikube-6c47c66d8-k4vlc 1/1 Running 0 11m

Once the pods are ready, we can connect to the running service’s endpoint:

$url = & minikube service hello-minikube --url
(New-Object System.Net.WebClient).DownloadString($url)
CLIENT VALUES:
client_address=172.17.0.1
command=GET
real path=/
query=nil
request_version=1.1
request_uri=http://192.168.99.101:8080/
SERVER VALUES:
server_version=nginx: 1.10.0 - lua: 10001
HEADERS RECEIVED:
connection=Keep-Alive
host=192.168.99.101:31559
BODY:
-no body in request-

Conclusion

Tools Installed

In total, we have installed 7 tools (1 virtual management platform, 4 x orchestration systems, and 2 client tools):

"`nVirtualBox $(vboxmanage --version)`n" + `
"$(vagrant --version)`n" + `
"$(kitchen --version)`n" + `
"$(docker-machine --version)`n" + `
"$(docker --version)`n" + `
"$(minikube version)`n" + `
"Kubectl Client: " + `
"$(kubectl version | Select-string "Client")".Split('"')[5] + `
"`n"
VirtualBox 5.2.16r123759
Vagrant 2.1.2
Test Kitchen version 1.22.0
docker-machine.exe version 0.14.0, build 89b8332
Docker version 18.03.0-ce, build 0520e24302
minikube version: v0.28.2
Kubectl Client: v1.11.1

We installed these piece by piece, but if you wanted to install these all in one command, you could create a Package.config manifest and install them all at once with choco install -y choco.config.

Image for post
Image for post

From Powershell, you can create and run using this:

@'
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="virtualbox" />
<package id="vagrant" />
<package id="chefdk" />
<package id="docker-toolbox" />
<package id="kubernetes-cli" />
<package id="minikube" />
</packages>
'@ | Out-File -Encoding "UTF8" $home/choco.config
choco install -y $home/choco.config

Virtual Guest Systems Created

With these 4 orchestration tools, we have created 6 virtual guests on VirtualBox:

vboxmanage list runningvms | ForEach-Object {$_.Split('"')[1]}
default
minikube
default-ubuntu-1604_default_1533101176498_15519
default-centos-7_default_1533101311605_33025
mywindows_default_1533247865771_48942
mymanjaro_default_1533248064205_34202

And with the graphical Virtualbox Manager console, we can see the same thing:

Image for post
Image for post

Cleaning Up

Now that we are finish, we can stop the running virtual machines hosting our development and test solutions, and optionally remove them completely.

######## vagrant w/ manjaro cleanup ########
cd $home\mymanjaro
vagrant halt # stop running vm guest
vagrant destroy # delete vm guest entirely
######## vagrant w/ win2016 cleanup ########
cd $home\mywindows
vagrant halt # stop running vm guest
vagrant destroy # delete vm guest entirely
######## testkitchen cleanup ########
cd $home\helloworld
kitchen destroy # destroys all test systems
######## dockermachine cleanup ########
docker-machine stop # stop vm hosting docker
docker-machine rm default # remove vm entirely
######## minkube cleanup ########
minikube stop # stop kubernetes cluster
minikube rm # remove vm hosting cluster and kubectl config entries

After stopping the virtual guests, vboxmanage list runningvms will show an empty list. If we removed them as well, then vboxmanage list vms will also show an empty list.

Final Thoughts

The main goal of this is to show you what is possible and create some interest and passion around these set of tools. I wanted to show that the same tools that work well on a Linux host or macOS host can also work on a Windows host as well.

Using these cross platform tools, we can easily facilitate experimentation and learning activities, and drive DevOps patterns from local development and test into a continuous integration and continuous delivery pipeline.

Resources

Here are some links for these tools.

Virtualbox

Vagrant

Vagrant supports has many backend provider solutions besides Virtualboxand has built in provisioner support for popular change configuration solutions.

Test Kitchen

Test Kitchen test harness has rich community support for a variety of backend driver support, provisioner support, and verifier support:

Docker Machine

Docker Machine has a few options for backend providers outside of Virtualbox:

Minikube

Vagrant Boxen

Change Configuration

Systems Integration Testing

Written by

Linux NinjaPants Automation Engineering Mutant — exploring DevOps, Kubernetes, CNI, IAC

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store