Getting started with Ansible

I've been using Puppet for a few years now. Generally it's a great tool for server automation, however like all software it has it's share of rough edges.

One edge I've run up against recently is performance on low powered devices. For example running even trivial configuration on my Raspberry Pi takes a long time:

pi@raspberrypi:~ $ time sudo puppet apply -e "service {'sshd': ensure => running }"
Notice: Compiled catalog for raspberrypi.lan in environment production in 3.60 seconds
Notice: Finished catalog run in 0.62 seconds

real    0m38.155s
user    0m34.690s
sys     0m2.450s

With the above in mind I decided to have a look at using Ansible instead. Both because I hoped it would perform better, and because it's always interesting to learn about alternative tools.

Installing Ansible

Unlike Puppet, Ansible is agent-less. Therefore installation is just a case of getting Ansible installed on a single control host. On CentOS You can install the ansible package from EPEL:

yum install ansible

The Ansible docs cover installation on other platforms. It's worth noting that Windows cannot currently be used as a control host, however Ansible can be used to manage Windows systems.

SSH setup

The most common connection method used by Ansible is SSH. Although password authentication can be used it's normally a good idea to setup SSH keys. This requires two steps:

  1. Generate a public/private SSH key pair using ssh-keygen.
  2. Copy the public key onto each target host using ssh-copy-id.

After everything is set up the control host should be able to connect to each target host without using a password:

[user@ansible-control ~]$ ssh pi@192.168.1.129 hostname
raspberrypi

Connecting with Ansible

Once SSH keys have been set up Ansible should be able to connect:

[user@ansible-control ~]$ ansible all -i '192.168.1.129,' -u pi -m ping
192.168.1.129 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

The command above uses the Ansible ping module to connect to the target host. Once connected the module confirms Ansible has everything it needs to run on the host; namely a suitable python environment.

Inventory

The ping example above can be shortened significantly by using an inventory file. By default Ansible looks in /etc/ansible/hosts for host information. For example the following lines will create a pi group with a single host in it:

[pi]
192.168.1.129 ansible_user=pi

After the new config has been added to the inventory file, the name of the host group can be used in place of the IP and user name:

[user@ansible-control ~]$ ansible pi -m ping
192.168.1.129 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Root access

By default Ansible will run as the user it connected with:

[user@ansible-control ~]$ ansible pi -m command -a 'whoami'
192.168.1.129 | SUCCESS | rc=0 >>
pi

To become root you can use the --sudo option:

[user@ansible-control ~]$ ansible pi --sudo  -m command -a 'whoami'
192.168.1.129 | SUCCESS | rc=0 >>
root

This can also be set persistently in the inventory config using ansible_become:

[pi]
192.168.1.129 ansible_user=pi ansible_become=true

Note: the --sudo and ansible_become options will only work if sudo has been configured on the target host.

Thoughts so far

I'm still very new to Ansible, but I'm quite impressed with what I've seen so far. Getting up and running was pretty straightforward and Ansible is faster than Puppet. Well at least for the slightly contrived example I had at the start of this post:

[user@ansible-control ~]$ time ansible pi -m service -a 'name=sshd state=running'
192.168.1.129 | SUCCESS => {
    "changed": false,
    "name": "sshd",
    "state": "started"
}

real    0m2.769s
user    0m0.589s
sys     0m0.215s

From here I'm planning to have a go at writing a few Ansible playbooks to actually do something useful. This should give me a better idea of what Ansible is capable of, or at least make me a little less naive when it comes to Ansible.