Image for post
Image for post

Vagrant Provisioning

Using Shell Provisioner to Configure Virtual Systems

One of the coolest and core features of Vagrant is the ability to provision systems, or in other words configure systems to an initial state. Vagrant can do this with through shell scripts, popular change configuration systems, or through containers with Docker.

Prerequisites

This small tutorial requires that Vagrant is installed along with virtual system VirtualBox. These instructions use Curl and Bash, so if you do not have those, you’ll use whatever is equivalent in your shell environment. For example, Windows users would need to find the equivalent PowerShell commands, and utilize something like the System.Net.WebClient object in place of Curl.

Image for post
Image for post

Installing Vagrant on macOS (using Homebrew)

A small guide that runs through using Homebrew to install Vagrant and VirtualBox.

Installing Vagrant on Windows (using Chocolatey)

A small guide that runs through using Chocolatey to install Vagrant and VirtualBox.

Installing Vagrant on Fedora

A small guide that runs through installing Vagrant and VirtualBox on Fedora.

Part I: Provisioning Ubuntu Systems

Image for post
Image for post
Ubuntu 16.04 Xenial Xerus

Vagrant Structure

To get started we need to create a working directory and support files:

WORKAREA=${WORKAREA:-"${HOME}/vagrant-shell"}mkdir -p ${WORKAREA}/scripts
touch ${WORKAREA}/{Vagrantfile,scripts/hello_web.sh}
cd ${WORKAREA}
~/vagrant-shell
├── Vagrantfile
└── scripts
└── hello_web.sh

Vagrant Configuration

Now we need to fill out the Vagrantfile configuration script to get started. Here’s a configuration for Ubuntu 16.04 Xenial Xerus:

script_path = './scripts'Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"
config.vm.network "forwarded_port", guest: 80, host: 8080
####### Provision #######
config.vm.provision "shell" do |script|
script.path = "#{script_path}/hello_web.sh"
script.args = %w(apache2 apache2 /var/www/html)
end
end
vagrant up --no-provision

Provisioning Script

Our provisioning script will install Apache HTTP server and create some content. Edit the scripts/hello_web.sh with this:

#!/usr/bin/env bash#### Set variables with intelligent defaults
APACHE_PACKAGE=${1:-'apache2'}
APACHE_SERVICE=${2:-'apache2'}
APACHE_DOCROOT=${3:-'/var/www/html'}
#### Download and Install Package
apt-get update
apt-get install -y ${APACHE_PACKAGE}
#### Start, Enable Service
systemctl start ${APACHE_SERVICE}.service
systemctl enable ${APACHE_SERVICE}.service
#### Create Content
cat <<-'HTML' > ${APACHE_DOCROOT}/index.html
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
HTML
vagrant provision

Testing the Solution

We can test the solution out using by running:

curl -i http://127.0.0.1:8080
HTTP/1.1 200 OK
Date: Wed, 08 Aug 2018 08:41:30 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Wed, 08 Aug 2018 08:39:09 GMT
ETag: "37-572e871b6e929"
Accept-Ranges: bytes
Content-Length: 55
Content-Type: text/html
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>

Part II: Adapting to Other Operating Systems

Image for post
Image for post
Debian • Ubuntu • CentOS • Fedora • Gentoo • ArchLinux

Update Vagrantfile

As we added the ability to pass arguments to the shell script from Vagrant, we can easily modify our Vagrantfile to support other operating systems.

script_path = './scripts'Vagrant.configure("2") do |config|
config.vm.box = "centos/7"
config.vm.network "forwarded_port", guest: 80, host: 8080
####### Provision #######
config.vm.provision "shell" do |script|
script.path = "#{script_path}/hello_web.sh"
script.args = %w(
httpd
httpd
/var/www/html
)
end
end
Image for post
Image for post
Vagrant box name and arguments for package, service, docroot
script_path = './scripts'Vagrant.configure("2") do |config|
config.vm.box = "generic/gentoo"
config.vm.network "forwarded_port", guest: 80, host: 8080
####### Provision #######
config.vm.provision "shell" do |script|
script.path = "#{script_path}/hello_web.sh"
script.args = %w(
www-servers/apache
apache2
/var/www/localhost/htdocs
)
end
end

Updating Provisioning Script

We also need to evolve our provisioning script scripts/hello_web.sh to support different distros. This can get quite complex, as different distros have different package management and service management systems.

#!/usr/bin/env bash#### Set variables with intelligent defaults
APACHE_PACKAGE=${1:-'apache2'}
APACHE_SERVICE=${2:-'apache2'}
APACHE_DOCROOT=${3:-'/var/www/html'}
#### Download and Install Package
DISTRO=$(
awk -F= '/^ID=/{print tolower($2) }' /etc/os-release \
| tr -d '"'
)
case "${DISTRO}" in
centos|rhel)
yum install -y ${APACHE_PACKAGE}
;;
fedora)
dnf install -y ${APACHE_PACKAGE}
;;
debian|ubuntu)
apt-get update
apt-get install -y ${APACHE_PACKAGE}
;;
gentoo)
emerge ${APACHE_PACKAGE}
;;
arch)
pacman -Syu --noconfirm
pacman -S --noconfirm ${APACHE_PACKAGE}
;;
*)
echo "Distro '${DISTRO}' not supported" 2>&1
exit 1
;;
esac
#### Start, Enable Service
case "${DISTRO}" in
centos|rhel|fedora|debian|ubuntu|arch)
systemctl start ${APACHE_SERVICE}.service
systemctl enable ${APACHE_SERVICE}.service
;;
gentoo)
rc-update add ${APACHE_SERVICE} default
/etc/init.d/${APACHE_SERVICE} start
;;
*)
echo "Distro '${DISTRO}' not supported" 2>&1
exit 1
;;
esac
#### Create Content
cat <<-'HTML' > ${APACHE_DOCROOT}/index.html
<html>
<body>
<h1>Hello World!</h1>
</body>
</html>
HTML

Shell Provisioning is Complex — Don’t do it

As you can see, wiring in all these variations can get quite complex to script in shell or other scripting language, as you have to handle all these variations.

package($package_name).install()
service($service_name).enable().start()
file("$docroot/index.html", $source).create()

Wrapping Up

That is essentially all there is to it, the take away is that you can use Vagrant to configure your system with a variety of solutions. This can be used to rapidly develop and test on virtual systems at no cost other than the time it takes to initially download the image from VagrantCloud.

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