Skip to content

Ansible Playbooks

What are Ansible Playbooks?

Ansible is an open-source automation tool that allows you to configure and manage computers, network devices, and cloud infrastructure. Ansible uses a simple language called YAML to define the configuration of your infrastructure. An Ansible playbook is a YAML file that contains a set of tasks that you want to run on your infrastructure. Playbooks are used to define the desired state of your infrastructure and to automate the process of configuring and managing your infrastructure.

Note

Ansible playbooks are idempotent, meaning that they can be run multiple times without changing the state of the system. This is because Ansible only makes changes to the system if the system is not in the desired state. This makes Ansible playbooks safe to run multiple times.

In short, the developer defines a host inventory file, hosts, which contains the hosts that the developer wants to configure. The developer then defines a set of tasks that they want to run on those hosts, which can be found inside the role directory labelled <some_task>.yml. The developer can also define variables that can be used in the tasks, defined in group_vars directory. The developer then runs the playbook, and Ansible will connect to the hosts in the inventory and run the tasks on those hosts.

Tip

Ansible automatically looks for group_vars labelled with the same name as the group in the inventory file. For example, if the inventory file contains a group called control, Ansible will look for a group_vars/control.yml file. This file can contain variables that can be used in the tasks that are run on the hosts in the control group. Ansible uses templating syntax like {{ variable_name }} to reference variables in the tasks.

How do we use Ansible Playbooks?

We use Ansible playbooks to automate the process of configuring and managing our infrastructure. We have a set of playbooks that define the configuration of our infrastructure, including the developers local vagrant instance, our various Django apps: control, dash, seopt, etc. and our data collection/processing services. These playbooks are stored in the backend repository inside the ansible directory.

Example

Below is an example of a simple Ansible playbook that installs the nginx package on a host:

# playbook.yml
---
- hosts: all
  tasks:
    - name: Install nginx
      apt:
        name: nginx
        state: present

This playbook defines a single task that installs the nginx package on all hosts in the inventory.

Bitbucket Pipelines

We use Bitbucket Pipelines to automate the process of running Ansible playbooks. Bitbucket Pipelines is a continuous integration and continuous deployment (CI/CD) service that is integrated with Bitbucket Cloud. It allows us to define a set of steps that are run whenever a change is pushed to a repository.

Bitbucket Pipelines spin up a Docker container using an image from our AWS Elastic Container Registry (ECR) that contains Ansible and the necessary dependencies, the ECR images are managed in the Attribution Images repository. Bitbucket Pipelines then run the Ansible playbook on the host specified in the inventory file.

Updating the Pipeline Image

The Attribution Images repository contains the Dockerfiles that are uploaded to the ECR. These Dockerfiles define the image that is used by Bitbucket Pipelines to run the Ansible playbook. The Dockerfile contains the necessary dependencies to run the Ansible playbook, including the Ansible binary and the Python packages that are required by the playbook.

The repository has its own pipeline that builds the Docker image and uploads it to the ECR. If the developer wants to update the image that is used by Bitbucket Pipelines, they can make changes to the Dockerfile and push the changes to master. This will trigger the pipeline in the Attribution Images repository, which will build the new image and upload it to the ECR.

Pipeline Example

When a developer makes a pull request we run the ci.yml pipeline. This pipeline runs the Ansible playbook inside the docker container, performing various tasks such as database validation and system provisioning.

Example

Below is an example of one of the steps in the bitbucket-pipelines.yml file that runs the ci.yml playbook:

# bitbucket-pipelines.yml
---
- step:
    name: Backend
    caches:
    - pip
    script:
    - *setup
    - ansible-playbook ci.yml -i hosts
    - cd ../backend
    - python3 manage.py test
    services:
    - mysql
The ansible-playbook command runs the ci.yml playbook on the hosts specified in the hosts inventory file.

# ci.yml
---
- hosts: ci
connection: local
roles:
    - check
    - database
    - backend
    - validate