I looked for a deployment method for my ~800 Ubuntu nodes at work which would allow me to fully automate software deployments and manage configurations after an OS provisioning.

That’s how I met Ansible.

The tool has many benefits:

  • No agent: it uses SSH.
  • Playbooks are written in YAML which is human readable. As each tasks has a name, plays are auto documented.
  • Idempotency: Ansible check if what you want is already done. Remove an inexistant file will not break your play.
  • Modularity: tasks are grouped in roles
  • Templating engine: with jinja2, you can factorize your configurations.
  • Toolbox: dry-run/diff modes, secrets, tags, …

Tasks

To each kind of task correspond an Ansible module, file, copy, shell
It’s important to use native modules and to not use shell module for your tasks to keep idempotency.

---
- name: create resolv.conf
  copy:
    content: |
      nameserver 1.1.1.1
      nameserver 9.9.9.9
    dest: /etc/resolv.conf

Playbooks, plays and inventory

A playbook is a yaml file with a set of plays.
A play is a set of tasks and/or roles targetting a host/group from the inventory.
The inventory can be a static ini or yaml file or a dynamic inventory script, with hosts placed in groups.

[group1]
host1
host2
[group2]
host2

Roles

Tasks are grouped in roles, ansible-galaxy is a marketplace to share them.
A role has a specific structure:

roles/
    common/
        tasks/main.yml
        handlers/main.yml
        files/
        templates/
        [...]

tasks/main.yml contains all tasks of the role.
handlers/main.yml contains specific tasks which are triggered by passing notify key to a task. If the tasks has a changed status, then the handler will be run. Multiple notify will result at a single run at the end of the play.

# tasks/main.yml
---
- name: configure nginx
  template:
    src: templates/nginx.j2
    dest: /etc/nginx/nginx.conf
  notify: restart nginx
# handlers/main.yml
- name: restart nginx
  service:
    name: nginx
    state: restarted

Managing dotfiles with Ansible

Managing my desktop recipe with Ansible allows me to deploy my setup over multiple hosts with specific configuration (dualscreen, packages…) by using jinja2 templating.
Centralizing my configurations on github is comfortable, I can pull my configuration from anywhere, and deploy it to all my managed nodes easily.
It also let me share my configurations with other linux users.

I wanted my setup to be modulable at multiple levels. I use roles and inventory to be able to separate servers from desktops configuration.
Since I started to use Nixos, I separated my package management project from my dotfiles and added to each OS-projects my install scripts to automate provisioning process from the beggining.
I can use Nixos embeedeed automation process to configure the system, and push my dotfiles with ansible too in a second time.

As my configuration is fully managed, I can auto test at each push with a Continuous Integration tool : Travis-CI