Daniel Watrous on Software Engineering

A Collection of Software Problems and Solutions

Software Engineering

Using Vagrant to Explore Ansible

Last week I wrote about Vagrant, a fantastic tool to spin up virtual development environments. Today I’m exploring Ansible. Ansible is an open source tool which streamlines certain system administration activities. Unlike Vagrant, which provisions new machines, Ansible takes an already provisioned machine and configures it. This can include installing and configuring software, managing services, and even running simple commands. Ansible doesn’t require any agent software to be installed on the system being managed. Everything is executed over SSH.

Ansible only runs on Linux (though I’ve heard of people running it in cygwin with some difficulty). In order to play with Ansible, I used Vagrant to spin up a control box and a subject box that are connected in a way that I can easily run Ansible commands. Here’s my Vagrantfile

# -*- mode: ruby -*-
# vi: set ft=ruby :
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|

  # define ansible subject (web in this case) box
  config.vm.define "subject" do |subject|
    subject.vm.box = "ubuntu/trusty64"
    subject.vm.network "public_network"
    subject.vm.network "private_network", ip: ""
    subject.vm.provider "virtualbox" do |v|
      v.name = "Ansible subject"
      v.cpus = 2
      v.memory = 768
    # copy private key so hosts can ssh using key authentication (the script below sets permissions to 600)
    subject.vm.provision :file do |file|
      file.source      = 'C:\Users\watrous\.vagrant.d\insecure_private_key'
      file.destination = '/home/vagrant/.ssh/id_rsa'
    subject.vm.provision :shell, path: "subject.sh"
    subject.vm.network "forwarded_port", guest: 80, host: 8080
  # define ansible control box (provision this last so it can add other hosts to known_hosts for ssh authentication)
  config.vm.define "control" do |control|
    control.vm.box = "ubuntu/trusty64"
    control.vm.network "public_network"
    control.vm.network "private_network", ip: ""
    control.vm.provider "virtualbox" do |v|
      v.name = "Ansible control"
      v.cpus = 1
      v.memory = 512
    # copy private key so hosts can ssh using key authentication (the script below sets permissions to 600)
    control.vm.provision :file do |file|
      file.source      = 'C:\Users\watrous\.vagrant.d\insecure_private_key'
      file.destination = '/home/vagrant/.ssh/id_rsa'
    control.vm.provision :shell, path: "control.sh"
  # consider using agent forwarding instead of manually copying the private key as I did above
  # config.ssh.forward_agent = true

Notice that I created a public network to get a DHCP external address. I also created a private network with assigned addresses in the open address space. This is so I can indicate to Ansible in the hosts file where to locate all of the inventory.

I had trouble getting SSH agent forwarding to work on Windows through PuTTY, so for now I’m manually placing the private key and updating known_hosts with the ‘ssh-keyscan’ command. You can see part of this in the Vagrantfile above. The remaining work is done in two scripts, one for the control and one of the subject.


#!/usr/bin/env bash
# set proxy variables
#export http_proxy=http://myproxy.com:8080
#export https_proxy=https://myproxy.com:8080
# install pip, then use pip to install ansible
apt-get -y install python-dev python-pip
pip install ansible
# fix permissions on private key file
chmod 600 /home/vagrant/.ssh/id_rsa
# add subject host to known_hosts (IP is defined in Vagrantfile)
ssh-keyscan -H >> /home/vagrant/.ssh/known_hosts
chown vagrant:vagrant /home/vagrant/.ssh/known_hosts
# create ansible hosts (inventory) file
mkdir -p /etc/ansible/
cat /vagrant/hosts >> /etc/ansible/hosts


#!/usr/bin/env bash
# fix permissions on private key file
chmod 600 /home/vagrant/.ssh/id_rsa

I also provide copy this hosts file into place on the control system so it knows against which inventory it should operate.


localhost   ansible_connection=local    ansible_connection=ssh

After running ‘vagrant up‘, I can verify that the control box is able to access the subject box using the ping module in ansible.



This post doesn’t demonstrate the use of Ansible, aside from the ping command. What it does do is provide an environment where I can build and run Ansible playbooks, which is exactly what I plan to do next.

11 Comments Using Vagrant to Explore Ansible

  1. Pingback: Build a Multi-server LEMP stack using Ansible | Daniel Watrous on Software Engineering

  2. Josh Padilla

    Why is it necessary to use Vagrant to create/provision VM guests? Do you think it’s possible to remove Vagrant from the provisioning workflow and use only KVM and Ansible? I normally ssh from a MacBook into a dedicated Ubuntu 14 Server.

    I prefer to bypass the whole Virtual Box/Vagrant steps on a local machine issue by just dedicating a PC to my dev environment. But I have yet to find a good guide to managing Ubuntu KVM nodes and their guests with Ansible. I’ve been trying tools like virt-builder and vmbuilder (deprecated?) but haven’t got very far.

    1. Daniel Watrous

      Josh, it’s not necessary to use Vagrant, but it is convenient. This is especially true for Windows users where the combination of Vagrant and VirtualBox are easy to get setup.

      If you already have a *nix environment setup and prefer to use KVM, that doesn’t make any difference to Ansible. You could probably even setup Devstack and create your automation using OpenStack API calls.

      1. Josh Padilla

        Thanks Daniel. I think OpenStack is a bit down the line for me. I find all the components (Keystone, Swift, etc, etc.) large investments of reading, hardware and it’s all just too much. I’m exploring virt-builder, vm-builder and Packer QEMU Builder (http://www.packer.io/docs/builders/qemu.html).

        Combining these w/ Ansible gives me that agile, traditional Unix tool feel that I always gravitate towards while still keeping an eye on scalability. Once LXC, OSv and Docker mature from a production and security standpoint, I’ll probably be focusing on them more. With so many choices and changes every month, it is hard for me to stay focused and feel confident about my DevOps toolchain choices.

  3. Durga Prasad R

    which version of Vagrant and virtual box used in setting up Ansible with Vagrant.. facing some issues with.
    my objective is to play in an environment where I can build and run Ansible playbooks on Windows7 machine.

    Appreciate your response.

  4. Pingback: What is Cloud Native? | Daniel Watrous on Software Engineering

  5. Kurdy

    I’m trying your example, but every time I end with: | FAILED => SSH Error: Permission denied (publickey,password).

    Any ideas on what I’m doing wrong?

  6. Kurdy

    The key copying seemed going wrong.
    Succeeded after creating public key on ‘subject’ with:
    ssh-keygen -y -f ~/.ssh/id_rsa > ~/.ssh/id_rsa.pub
    Emptied known hosts on ‘control’ (just to be sure).
    ssh-copy-id vagrant@
    And now success:
    ansible all -m ping
    localhost | success >> {
    “changed”: false,
    “ping”: “pong”
    } | success >> {
    “changed”: false,
    “ping”: “pong”

    I’m on W10, using Vagrant 1.7.4.

    λ echo %VAGRANT_HOME%

    subject.vm.provision :file do |file|
    file.source = ‘E:\Vagrant\boxes\insecure_private_key’
    file.destination = ‘/home/vagrant/.ssh/id_rsa’

  7. David

    Thanks. Tried this approach on windows before without success; you have added a couple more details (eg the scripts re the insecure private key) which means that i now have success.


Leave A Comment