If you’re a regular reader of my blog, you will know two things about me:

  1. I like Ansible.
  2. I frequently begin posts with “if you’re a regular reader of my blog”.

I recently discovered that Ansible got a “pull mode”, which is a super-simple way for Ansible to pull a repository and run commands from a file you specify. Unfortunately, documentation is pretty sparse, but that’s only a disadvantage until you realize that pull mode is really, really simple.

What “pull mode” is.

“Pull mode” is a single, very simple script. You can invoke it with ansible-pull, and all it does is what is described in its man page:

  • It pulls the specified git repository into a specified directory.
  • If the repository has changed[1], it runs a file called <hostname>.yml or local.yml in the repository’s root directory.

That is literally everything ansible-pull does. Therefore, it should be obvious by now how you use it:

  1. Add it to your crontab.
  2. Add the <hostname>.yml or local.yml file to your repository.
  3. No third step.

[1] Note: Ansible doesn’t actually do that by default, it always runs the playbook instead, but I added an option to do it and submitted a pull request.

What it’s for

The advantages to this mode should be equally obvious. If you have 30 servers, you no longer have to instruct ansible to log into each one and run the same commands. The servers poll the repository themselves and auto-apply the changes in the files, which scales massively (as far as your git server can support). This is extremely handy, as it allows you to automatically deploy the latest code in your repository, even if the servers are different. The branch to pull is specified on the ansible-pull command line, so production can run master, staging can run staging and the “live” server can run develop. I find the fact that you don’t have to run a deploy step, other than just committing, completely magical.

If you don’t want to poll, and would rather use a webhook instead, I wrote a simple piece of software that enables you to send it a webhook to trigger ansible-pull. It’s called Captain Webhook and is very easy to set up.

How to use

This is my short /etc/cron.d/ansible-pull file:

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

*/20 * * * * root /usr/local/bin/ansible-pull -o -C develop -d /var/projects/myrepo -i /var/projects/myrepo/hosts -U git://github.com/myrepo >> /var/log/ansible-pull.log 2>&1

You can use this sample ansible_pull.yml to deploy this configuration to your host. It also includes a logrotate configuration file and some other commands to set up the whole thing.

When to use

All that having been said, this is probably suitable for small-to-medium deployments. For larger deployments, I wouldn’t use the VCS directly, as you should have some assurance that the code will not break something when deployed. In those scenarios, your deployments should probably only be triggered by your CI server, and you may want to use OS-native deployment tools (apt/yum) to deploy pre-built packages of your software.

That way, you know what exactly is running where, and can quickly roll it back if needed. Just exercise good judgement and choose the right tool for your use case.

Epilogue

I just started using this, so I don’t have a list of best practices yet, and I haven’t figured out how to tie it in with my previously-posted ansible configuration, especially how to juggle the user permissions (restarts should be as root, various commands should be as the project user), but I’ll write a new post when I get it figured out to my satisfaction.

If you have any tips or feedback on how to do this better, please post here!