In this example we are going to use Vagrant and Ansible to build two Ubuntu servers which have same packages installed so they will be identical. The only difference they have is the "hostname" and "IP" address.


System


I am using Ansible 2.4.3.0 and Vagrant 1.9.5 on MacOS.


Structure


$ tree
.
├── Vagrantfile
├── provisioning
│   ├── group_vars
│   │   └── all
│   ├── hosts.yml
│   ├── roles
│   │   └── server
│   │   ├── handlers
│   │   │   └── main.yml
│   │   ├── tasks
│   │   │   └── main.yml
│   │   └── templates
│   │   └── ntp.conf.j2
│   └── site.yml
└── vagrant_hosts.yml

Tasks



Files


vagrant_hosts.yml


# Reflect any "hostname" and "ip" changes in "provisioning/hosts.yml" file

- name: This is for Linux 1 box
label: Linux 1 - 192.168.99.31
hostname: linux1
ip: 192.168.99.31

- name: This is for Linux 2 box
label: Linux 2 - 192.168.99.32
hostname: linux2
ip: 192.168.99.32

Vagrantfile


# -*- mode: ruby -*-
# vi: set ft=ruby :

require "yaml"

boxes = YAML.load_file("vagrant_hosts.yml")

Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/xenial64"

ANSIBLE_RAW_SSH_ARGS = []
i = 0

boxes.each do |box|
ANSIBLE_RAW_SSH_ARGS << "-o IdentityFile=.vagrant/machines/#{box["hostname"]}/virtualbox/private_key"

config.vm.define box["hostname"] do |machine|
machine.vm.hostname = box["hostname"]
machine.vm.network "private_network", ip: box["ip"]
machine.vm.synced_folder box["hostname"], "/srv/www", create: true, nfs: true, mount_options: ["actimeo=2"]
machine.vm.provider :virtualbox do |virtualbox|
virtualbox.name = box["label"]
end
i += 1

if i == boxes.count
machine.vm.provision :ansible do |ansible|
ansible.raw_ssh_args = ANSIBLE_RAW_SSH_ARGS
ansible.verbose = "-vvv"
ansible.limit = "all"
ansible.inventory_path = "provisioning/hosts.yml"
ansible.playbook = "provisioning/site.yml"
end
end
end
end
end

provisioning/hosts.yml


# Reflect any "hostname" and "ip" changes in "../vagrant_hosts.yml" file

all:
children:
servers:
hosts:
linux1:
ansible_host: 192.168.99.31
linux2:
ansible_host: 192.168.99.32

provisioning/site.yml


---
# This playbook sets up whole stack.

- name: Apply common configuration to "server" hosts
hosts: servers
remote_user: root
become: yes
roles:
- server

provisioning/group_vars/all


---
# Variables listed here are applicable to "all" host

ansible_python_interpreter: /usr/bin/python3

provisioning/roles/server/handlers/main.yml


---
# This playbook contains common handlers that can be called in tasks.

# sudo service ntp restart (whether running or not)
- name: Restart ntp
service:
name: ntp
state: restarted
enabled: yes

provisioning/roles/server/tasks/main.yml


---
# This playbook contains common actions that will be run on "linux" hosts.

# sudo apt-get update
- name: Update apt packages
apt:
update_cache: yes
tags:
- system

# sudo timedatectl set-timezone Europe/London
- name: Set time zone to Europe/London
timezone:
name: Europe/London
tags:
- system

# sudo apt-get install ntp
- name: Install ntp
apt:
name: ntp
state: present
update_cache: yes
tags:
- ntp

# sudo cp provisioning/common/templates/ntp.conf.j2 /etc/ntp.conf
- name: Configure ntp file and restart
template:
src: ntp.conf.j2
dest: /etc/ntp.conf
notify: Restart ntp
tags:
- ntp

# sudo apt-get install nano
- name: Install nano
apt:
name: nano
state: present
update_cache: yes
tags:
- nano

# sudo apt-get autoclean
- name: Remove useless apt packages from the cache
apt:
autoclean: yes
tags:
- system

# sudo apt-get autoremove
- name: Remove dependencies that are no longer required
apt:
autoremove: yes
tags:
- system

provisioning/roles/server/templates/ntp.conf.j2


driftfile /var/lib/ntp/drift

# Specify UK NTP servers.
server 0.uk.pool.ntp.org
server 1.uk.pool.ntp.org
server 2.uk.pool.ntp.org
server 3.uk.pool.ntp.org

# Use Ubuntu's NTP server as a fallback.
server ntp.ubuntu.com

# Local users may obtain data from NTP servers.
restrict 127.0.0.1
restrict ::1

Build


$ vagrant up
...
PLAYBOOK: site.yml *************************************************************
1 plays in provisioning/site.yml
PLAY [Apply common configuration to "server" hosts] ****************************
TASK [Gathering Facts] *********************************************************
TASK [server : Update apt packages] ********************************************
TASK [server : Set time zone to Europe/London] *********************************
TASK [server : Install ntp] ****************************************************
TASK [server : Configure ntp file and restart] *********************************
TASK [server : Install nano] ***************************************************
TASK [server : Remove useless apt packages from the cache] *********************
TASK [server : Remove dependencies that are no longer required] ****************
RUNNING HANDLER [server : Restart ntp] *****************************************
META: ran handlers
META: ran handlers
PLAY RECAP *********************************************************************
linux1 : ok=9 changed=5 unreachable=0 failed=0
linux2 : ok=9 changed=5 unreachable=0 failed=0

References