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! VAGRANTFILE_API_VERSION = "2" 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: "192.168.51.4" subject.vm.provider "virtualbox" do |v| v.name = "Ansible subject" v.cpus = 2 v.memory = 768 end # 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' end subject.vm.provision :shell, path: "subject.sh" subject.vm.network "forwarded_port", guest: 80, host: 8080 end # 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: "192.168.50.4" control.vm.provider "virtualbox" do |v| v.name = "Ansible control" v.cpus = 1 v.memory = 512 end # 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' end control.vm.provision :shell, path: "control.sh" end # consider using agent forwarding instead of manually copying the private key as I did above # config.ssh.forward_agent = true end |
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.
control.sh
#!/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 192.168.51.4 >> /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 |
subject.sh
#!/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.
hosts
[targets] localhost ansible_connection=local 192.168.51.4 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.
Conclusion
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.
[…] a multi-server LEMP stack. This builds on the preliminary work I did demonstrating how to use Vagrant to create an environment to run Ansible. You can follow this entire example on any Windows (or Linux) […]
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.
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.
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.
daniel,
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.
I’m pretty close to the latest version for those tools. What issues are you facing?
[…] to abstract this away from the provider with mixed results. The configure step might include Ansible or a similar tool. The build, test and deploy process will likely use a tool like Jenkins to […]
Daniel,
I’m trying your example, but every time I end with:
192.168.51.4 | FAILED => SSH Error: Permission denied (publickey,password).
Any ideas on what I’m doing wrong?
This may be related to a change Vagrant made in which it now creates a new key for each VM. I use “config.vm.ssh.insert_key = false”
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).
Did:
ssh-copy-id vagrant@192.168.51.4
And now success:
ansible all -m ping
localhost | success >> {
“changed”: false,
“ping”: “pong”
}
192.168.51.4 | success >> {
“changed”: false,
“ping”: “pong”
}
I’m on W10, using Vagrant 1.7.4.
λ echo %VAGRANT_HOME%
E:\Vagrant\
subject.vm.provision :file do |file|
file.source = ‘E:\Vagrant\boxes\insecure_private_key’
file.destination = ‘/home/vagrant/.ssh/id_rsa’
end
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.