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.
#!/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
#!/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.
[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.
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.