Provisioning CircleCI with Ansible

I've been using Ansible provisioning for a long time to set up production and testing environments, as well as creating local environments with Vagrant. I've also been trying to make more use of CI in projects, most recently with CircleCI. However, I've generally provisioned CircleCI using a simulacrum of the live provisioning script rather than the actual thing.

In my latest project, I decided to spend the time I would have used to create the CircleCI script to instead see how easy it would be to make Ansible do the work for me. Turns out, it's not that hard. That the Ansible provisioning was written against Debian and the CircleCI environments use Ubuntu definitely helped, but nowadays most Ansible Galaxy roles do a good job of cross-compatibility.

Local provisioning

The first step was to figure out how to do local provisioning with Ansible. It turns out there are a bunch of different ways to do this, including specific command-line invocations of ansible-playbook and special playbook variables. I like using group_vars to keep my configuration in one place, so I went with those.

Since I also wanted to create a local provisioner for Vagrant so that I could test this out locally, I opted to split out my CircleCI host to a separate host file. If you have multiple groups in the same hosts file using the same IP Ansible seems to only recognise the first one, leading to all sorts of problems. In my circle_hosts file I placed this configuration;

[circleci]
127.0.0.1

Then in my group_vars/circleci file I added;

---
ansible_connection: local

This was all the base configuration that I needed. You can then add any environment-specific configuration to this group_vars file.

CircleCI provisioning

After setting up my local Ansible provisioning, I just needed to configure CircleCI to run it. To the dependencies section in my circle.yml file I added;

- sudo apt-get install software-properties-common
- sudo apt-add-repository ppa:ansible/ansible -y
- sudo apt-get update
- sudo apt-get install ansible
- ansible-playbook provisioning/playbook.yml -i circle_hosts --limit circleci

This adds the latest version of Ansible following the installation guide, then runs the playbook which lives in the provisioning directory of my repository.

This was remarkably simple to set up, and worked first time. We now have the advantage of being able to immediately use any dependencies we've provisioned with Ansible in our CI environment, which makes setting up tests that much more straightforward. If you're using Ansible and CircleCI, give this a go for yourself.