How I Understand Ansible

17 March 2016

Ansible works with the following basic concepts: - task - role - host - group - variable - play - playbook

Tasks

A task performs one Ansible command. Examples:

# A task that installs nginx name: install nginx apt: name: nginx state: present become: yes become_user: root

#A task that renders a template to the remote host name: install config template: src: uwsgi.ini.j2 dest: /etc/uwsgi/sites-available/tomato.ini become: yes become_user: root

Tasks represent Ansible's fundamental units of execution.

Roles

A role groups tasks with a common goal. A role represents a collection of tasks grouped around a particular functionality. The most common way of grouping is around a particular technology. That's why you will see on Ansible Galaxy, Ansible's roles repository, roles with names like ansible-nginx, ansible-postgres, ansible-sendmail, ansible-redis, etc.

Technically, you could use a role to focus on a specific functionality: a role that adds ppas and installs packages, a role that installs configuration files. This makes a role more or less identical in functionality to an Ansible module, so it provides less benefits. It also means you can't use defaults, because the role provides too high-level functionality.

To give a more general definition for roles, I would say that they group functionality that needs to be used in different contexts. For example, if you want to manage users, you can create a 'users' role that will create a user, give it sudo rights or other specific permissions.

Tags

Tags apply to tasks. They provide other ways of grouping your tasks. So you can have your roles and sometimes run only parts of the roles. They become useful as the scale of your app increases.

Hosts

The word has the same meaning as in the phrase "network host". It refers to a particular entity identified by a hostname or IP.

Groups

A group contains one or more hosts. A group gives you the option of giving a meaningful label to a host. Usual group names are 'development', 'production', 'web', 'db', etc.

Variables

You use a variable through this syntax: "{{ variable }}". Ansible offers many ways to define a variable: - in a group_vars file - in a role's default directory - in a task

What are some ways we can use variables? If we want to install a list of packages, we can use a variable:

name: install python libs apt: name: "{{ item }}" state: present with_items: - python-dev - python-pip - python-virtualenv become: yes become_user: root

If we want to allow the user to provide a template for a config file:

name: install nginx virtual host config template: src: "{{ nginx_virtualhost_conf_src }}" dest: "/etc/nginx/sites-available/{{ domain_name }}.conf" become: yes become_user: root

The template of the config file will contain variables, of course:

server { listen 80; server_name {{ nginx_server_name }}; access_log /var/log/nginx/{{ nginx_access_log }}; error_log /var/log/nginx/{{ nginx_error_log }};

client_max_body_size 20M;

location / {
    uwsgi_pass unix://{{ uwsgi_socket }};
    include uwsgi_params;
    uwsgi_intercept_errors on;
    error_page 404 /404.html;
    error_page 500 502 503 504 /50x.html;

    location /404.html {
        alias {{ nginx_templates_path }}/404.html;
    }
    location /50x.html {
        alias {{ nginx_templates_path }}/50x.html;
    }
}

location /static {
    alias {{ nginx_static_path }};
}

}

I didn't mention exactly where we set variables. We do that in a role's defaults directory or in the vars directory. The difference between them is that you can't override variables defined in the 'vars' directory.

Playbooks

A playbook represents a collection of plays. A play is a "run" of tasks or roles against specific hosts:

hosts: development gather_facts: no remote_user: vagrant roles: - ansible-python - ansible-postgres - ansible-nginx

Applying the principles

Small scale

At small scale, we use one host for each deployment target. That means we have a development box, a staging one and a production one. Each of these runs all our services: database, web server, cache, search server.

As a result, the groups represent each of the deployment targets. That's why we have development, staging, and production groups. This means we also have the equivalent playbooks: development.yml, staging.yml, production.yml. These playbooks have common roles. Actually, staging and production use identical roles, since we want to have minimal differences between the two.

Medium scale

At large scale, we start to put services on their own boxes or groups of boxes. That changes our groups. Now, we have 'web', 'db', 'cache', 'search'. Our plays look like this:

hosts: web gather_facts: no remote_user: prod roles: - ansible-locale - ansible-nginx

Who is my audience? - developers who want to manage their personal projects. they currently use shell scripts or Fabric. They haven't used a provisioning system yet. Or they don't use anything. They run everything by hand. Tudor. - developers who already use a provisioning system: chef, puppet, salt-stack. Octav.

Tudor wants a simple solution for managing his projects. He wants to know what to install, how to install it and in what order to do these steps.

Can you use Ansible for anything besides provisioning? Well, Ansible runs commands on remote or local hosts. Maybe penetration testers can also use Ansible since it doesn't require installing anything on the target host.