Switch branches/tags
Nothing to show
Find file History
leucos Fixes READMEs and deprecations hunting
Fixes README replicated changes by @GMLudo
Fixed deprecation warnings for 2.5
Latest commit 5bdc75f May 5, 2018


Ansible tutorial


We'll use the haproxy as loadbalancer. Of course, install is just like we did for apache. But now configuration is a bit more tricky since we need to list all web servers in haproxy's configuration. How can we do that?

HAProxy configuration template

Ansible uses Jinja2, a templating engine for Python. When you write Jinja2 templates, you can use any variable defined by Ansible.

For instance, if you want to output the inventory_name of the host the template is currently built for, you just can write {{ inventory_hostname }} in the Jinja template.

Or if you need the IP of the first ethernet interface (which ansible knows thanks to the setup module), you just write: {{ ansible_eth1['ipv4']['address'] }} in your template.

Jinja2 templates also support conditionals, for-loops, etc...

Let's make a templates/ directory and create a Jinja template inside. We'll call it haproxy.cfg.j2. We use the .j2 extension by convention, to make it obvious that this is a Jinja2 template, but this is not necessary.

    maxconn 256

    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

listen cluster
    bind {{ ansible_eth1['ipv4']['address'] }}:80
    mode http
    stats enable
    balance roundrobin
{% for backend in groups['web'] %}
    server {{ hostvars[backend]['ansible_hostname'] }} {{ hostvars[backend]['ansible_eth1']['ipv4']['address'] }} check port 80
{% endfor %}
    option httpchk HEAD /index.php HTTP/1.0

We have many new things going on here.

First, {{ ansible_eth1['ipv4']['address'] }} will be replaced by the IP of the load balancer on eth1.

Then, we have a loop. This loop is used to build the backend servers list. It will loop over every host listed in the [web] group (and put this host in the backend variable). For each of the hosts it will render a line using host's facts. All hosts' facts are exposed in the hostvars variable, so it's easy to access another host variables (like its hostname or in this case IP).

We could have written the host list by hand, since we have only 2 of them. But we're hoping that the server will be very successful, and that we'll need a hundred of them. Thus, adding servers to the configuration or swapping some out boils down to adding or removing hosts from the [web] group.

HAProxy playbook

We've done the most difficult part of the job. Writing a playbook to install and configure HAproxy is a breeze:

- hosts: haproxy
    - name: Installs haproxy load balancer
        pkg: haproxy
        state: present
        update_cache: yes

    - name: Pushes configuration
        src: templates/haproxy.cfg.j2
        dest: /etc/haproxy/haproxy.cfg
        mode: 0640
        owner: root
        group: root
        - restart haproxy

    - name: Sets default starting flag to 1
        dest: /etc/default/haproxy
        regexp: "^ENABLED"
        line: "ENABLED=1"
        - restart haproxy

    - name: restart haproxy
        name: haproxy
        state: restarted

Looks familiar, isn't it? The only new module here is template, which has the same arguments as copy. We also restrict this playbook to the group haproxy.

And now... let's try this out. Since our inventory contains only hosts necessary for the cluster, we don't need to limit the host list and can even run both playbooks. Well, to tell the truth, we must run both of them at the same time, since the haproxy playbook requires facts from the two webservers. In step-11 we'll show how to avoid this.

$ ansible-playbook -i step-10/hosts step-10/apache.yml step-10/haproxy.yml

PLAY [web] ********************* 

GATHERING FACTS ********************* 
ok: [host1.example.org]
ok: [host2.example.org]

TASK: [Updates apt cache] ********************* 
ok: [host1.example.org]
ok: [host2.example.org]

TASK: [Installs necessary packages] ********************* 
ok: [host1.example.org] => (item=apache2,libapache2-mod-php5,git)
ok: [host2.example.org] => (item=apache2,libapache2-mod-php5,git)

TASK: [Push future default virtual host configuration] ********************* 
ok: [host2.example.org]
ok: [host1.example.org]

TASK: [Activates our virtualhost] ********************* 
changed: [host1.example.org]
changed: [host2.example.org]

TASK: [Check that our config is valid] ********************* 
changed: [host1.example.org]
changed: [host2.example.org]

TASK: [Rolling back - Restoring old default virtualhost] ********************* 
skipping: [host1.example.org]
skipping: [host2.example.org]

TASK: [Rolling back - Removing out virtualhost] ********************* 
skipping: [host1.example.org]
skipping: [host2.example.org]

TASK: [Rolling back - Ending playbook] ********************* 
skipping: [host1.example.org]
skipping: [host2.example.org]

TASK: [Deploy our awesome application] ********************* 
ok: [host2.example.org]
ok: [host1.example.org]

TASK: [Deactivates the default virtualhost] ********************* 
changed: [host1.example.org]
changed: [host2.example.org]

TASK: [Deactivates the default ssl virtualhost] ********************* 
changed: [host2.example.org]
changed: [host1.example.org]

NOTIFIED: [restart apache] ********************* 
changed: [host2.example.org]
changed: [host1.example.org]

PLAY RECAP ********************* 
host1.example.org              : ok=10   changed=5    unreachable=0    failed=0    
host2.example.org              : ok=10   changed=5    unreachable=0    failed=0    

PLAY [haproxy] ********************* 

GATHERING FACTS ********************* 
ok: [host0.example.org]

TASK: [Installs haproxy load balancer] ********************* 
changed: [host0.example.org]

TASK: [Pushes configuration] ********************* 
changed: [host0.example.org]

TASK: [Sets default starting flag to 1] ********************* 
changed: [host0.example.org]

NOTIFIED: [restart haproxy] ********************* 
changed: [host0.example.org]

PLAY RECAP ********************* 
host0.example.org              : ok=5    changed=4    unreachable=0    failed=0    

Looks good. Now head to and see the result. Your cluster is deployed!

you can even peek at HAProxy's statistics at

Now on to the next chapter about "Variables again", in step-11.