Image for post
Image for post

Vagrant Provisioning with Ansible

Provisioning Virtual Systems with Ansible Local

Vagrant supports provisioning systems with Ansible, either through executing tasks remotely from the host, or through executing tasks locally on the target system.

About Ansible

Ansible is a popular remote execution tool that can replace the classical ssh-for-loop patterns. Coupled with change configuration capability, Ansible is great web application deployments or for cloud environments where orchestration is required.


As this tutorial is about Vagrant, you need to install Vagrant, and along with Vagrant, you need the virtual systems with Virtualbox. It may be possible to use other virtual platforms, but this can be complex, and doesn’t work consistently across macOS, Windows, and Linux.

Image for post
Image for post

Windows 8.1

Using Chocolatey to install the requirements:

macOS High Sierra 10.3

Using Homebrew to install the requirements:

Fedora 28

Using native package manager Dandified YUM, or in short DNF, to install requirements:

Part I: Ansible Role with Intelligent Defaults

We’ll start with an Ansible role called hello_web that will install Apache web server on Ubuntu, and have Vagrant bring up the guest system and run the tasks in the role.

Initial Work Area Structure

Let’s great the staging area or work area for this project.

mkdir -p ~/vagrant-ansible/provision/roles
cd ~/vagrant-ansible
touch Vagrantfile provision/playbook.yml
ansible-galaxy init provision/roles/hello_web
mkdir -p provision/roles/hello_web/{defaults,files,tasks}
touch provision/roles/hello_web/{defaults/main.yml,tasks/main.yml}
cat <<-'HTML' > provision/roles/hello_web/files/index.html
<h1>Hello World!</h1>
├── Vagrantfile
└── provision
├── playbook.yml
└── roles
└── hello_web
├── defaults
│ └── main.yml
├── files
│ └── index.html
└── tasks
└── main.yml

Vagrant Configuration

Now we need to create our Vagrant configuration with this Vagrantfile:

Vagrant.configure("2") do |config| = "bento/ubuntu-16.04" "forwarded_port", guest: 80, host: 8086
####### Provision #######
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "provision/playbook.yml"
ansible.verbose = true

Create the Playbook

The provisioner picks a playbook to run for the provisioning process. This is where we can select the the hello_web role. Update provision/playbook.yml with this:

- hosts: all
gather_facts: yes
become: true
- hello_web

Create the Role Defaults

Now we can start digging into the role parts. First let’s set some default variables with some intelligent defaults that make sense for a Ubuntu 16.04 Xenial Xerus system.

docroot: /var/www/html
package: apache2
service: apache2

Create the Role Tasks

From within the hello_web role, update tasks/main.yml with this:

- name: "Install Web Service"
name: "{{ hello_web.package }}"
state: present
- name: "Start Web Service"
name: "{{ hello_web.service }}"
state: started
enabled: yes
- name: "Copy Web Content"
src: "{{ role_path }}/files/index.html"
dest: "{{ hello_web.docroot }}/index.html"

Testing the Solution

vagrant up                    # download, start guest, provision
curl -i # access content
HTTP/1.1 200 OK
Date: Sun, 12 Aug 2018 01:06:50 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Sun, 12 Aug 2018 01:06:38 GMT
ETag: "3c-5733296c755b3"
Accept-Ranges: bytes
Content-Length: 60
Content-Type: text/html
<h1>Hello World!</h1>

Part II: Ansible Role using Extra Variables

Now let’s swap out the guest system for CentOS virtual guest. We’ll have to send some different variables to the hello_web as the role defaults are will not work for CentOS.

Update Vagrant Configuration

Update the Vagrantfile with this content below, which use the CentOS box by the Bento project, and adds some new variables that will be used later by the hello_web role.

Vagrant.configure("2") do |config| = "bento/centos-7.5" "forwarded_port", guest: 80, host: 8086
####### Provision #######
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "provision/playbook.yml"
ansible.verbose = true
ansible.extra_vars = {
hello_web: {
package: "httpd",
service: "httpd",
docroot: "/var/www/html"

Testing the Updated Solution

Let’s try the new configuration:

vagrant destroy --force # purge old environment
vagrant up # download, create guest, provision
curl -i
HTTP/1.1 200 OK
Date: Sun, 12 Aug 2018 08:43:09 GMT
Server: Apache/2.4.6 (CentOS)
Last-Modified: Sun, 12 Aug 2018 01:30:35 GMT
ETag: "3c-57332ec6c9bce"
Accept-Ranges: bytes
Content-Length: 60
Content-Type: text/html; charset=UTF-8
<h1>Hello World!</h1>

Final Thoughts

I hope this helps give a introduction to Ansible and how Vagrant can be used to easily develop and test Ansible playbook and roles.

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