Combining Ansible and Fabric
Written by Yannik Messerli - 10 January 2015
Ansible is a python software to automate the configuration of systems, software deployements and other advanced stuff. Instead of writing dozen of shell commands and repeat them again and again for your different hosts, just write some "playbooks". They are sort of set of ordered commands that Ansible can run against hosts you will give him.
Fabric is a python library to help running a set of operations locally and/or on one (or multiple) host(s). It is useful to compile, sync, or migrate data before/after deploying an app.
While both seem similar in their description, they serve really different purposes. Ansible is useful for configuring different servers that will host one or multiple applications. Fabric is used to install one particular app. One example is the case of Capistrano. This software deploy one application on one server using its own startegy. (It creates multiple folders for the different releases.) Fabric can mimic the same strategy using Fabistrano. However, prerequies like python, git, etc, need to be installed beforehand. If Ansible can help you here, there is one drawback though: they haven't really been designed to play well together.
env.hosts = ["localhost:2221", "localhost:2222", "localhost:2223"] env.user = "vagrant" env.password = "..."
Indeed, both Fabric and Ansible need to know where they will work. Since one is designed to setup a fairly large number of servers, it requires a small file with minimal information about ssh connections. In the other hand, Fabric requires information for mostly one server, stored in an environment variable (see image 1 and 2). The challenge was then to combine both methods.
[test] vagrant1 ansible_ssh_host=localhost ansible_ssh_port=2221 ansible_ssh_user=vagrant ansible_ssh_private_key_file=... ansible_ssh_pass=... vagrant2 ansible_ssh_host=localhost ansible_ssh_port=2222 ansible_ssh_user=vagrant ansible_ssh_private_key_file=... ansible_ssh_pass=... vagrant3 ansible_ssh_host=localhost ansible_ssh_port=2223 ansible_ssh_user=vagrant ansible_ssh_private_key_file=... ansible_ssh_pass=...
Note: I'm using the term 'provision' in the same sense that Vagrant is using it, e.i. the process to install and configure a VM. I don't think it is the best sense though...
An obvious solution would be to pass to the Fabric script ansible host configurations. But, I struggled to find the way to pass it, e.g. to pass
ansible_ssh_private_key_file. Indeed - if I am not yet completly familiar with Ansible, it really looks there is a security mecanism that mutes these two variables. Doesn't it?
A workaround is to setup Fabric to connect to the remote server(s) using a ssh key we would setup beforehand, during the provsionning process in Ansible playbook. The key will be stored in the provision folder and will be used with any host. Note that this is definetely not the most secure way to do this. ;-)
Create a key to access the remote server(s)
We will use
ssh-keygen script to generate a key pair: a public and a private key. This utility is usually installed on most of the systems: it comes with OpenSSH. First, create a directory under your provision folder, such as
ssh. Create a file
id_rsa in it. Then, type:
ssh-keygen -t rsa
It will ask you where you wish to create the key pair. (You want to create alongside your playbook in the folder ssh, right?) It should look like this:
Enter file in which to save the key (/home/yannik/.ssh/id_rsa): ./ssh/id_rsa
The next question is about the passphrase - a security mecanism that protect your key from thieves. However, it requires you to enter the passphrase each time you want to use the key, which is not ideal when using it in Ansible. For the purpose of this tutorial, I will leave it blank.
Enter passphrase (empty for no passphrase):
At the end, you will get a nice random picture and your public key will be located at
Prepare the host - the playbook
So, you have probably a long playbook that is installing crazy packages on your server. At some point you want to run a Fabric command. Then, you can include these tasks to your playbook at the relevant position:
- name: add public for you ansible user on the server authorized_key: user= key="" - name: change key permision to avoid any error from ssh local_action: command chmod 600 ssh/id_rsa.pub - name: run your fab command and pass the key file to fabric's ssh system local_action: command fab your_command -H : -u -i ssh/id_rsa
You can run multiple Fabric command in your playbook.
Ansible is really great and powerful. I also really love Fabric and its simple interface - Fabristrano is definetely an important component in my deployement startegy. That said, this integration guide is probably not the best. So, I will probably follow up on this if I can find a better solution. Any help is welcomed in the comments below.