Tuesday, March 19, 2024
HomeAnsibleHow to write a Ansible Playbook - Explained

How to write a Ansible Playbook – Explained

For now we have seen how to install Ansible on CentOS/RHEL & Ubuntu, and tried some sample commands. Now will see how to write your first ever playbook and how run it. For that login to your ansible controller (knowly where do you installed ansible and call it as master or whatever you named)

Read more: Install Ansible on CentOS/RHEL & Ubuntu

To make sure you have a root login to all listed hosts in inventory use below command;

# ansible all -m shell -a id

Sample Output:

Controller.foxutech.com | success | rc=0 >>
uid=0(root) gid=0(root) groups=0(root)

This shows that the login was successful (return code zero = OK) and that when the command “id” was run on the remote machines, it was running as user “root”.

Writing a playbook

A playbook comprises of a list of hosts and tasks entries, like below:

- hosts: ...
  tasks: ...
- hosts: ...
  tasks: ...
- hosts: ...
  tasks: ...

In each section, you define a set of task(s) to be run on a set of host(s). The playbook is run in sequence way, although the same task can run on multiple hosts in parallel.

Write First playbook

You will do the following as the “ansible” user. Make sure you are in ansible user home directory;

# pwd   # should get /home/ansible

If you are not on the particular user home directory, use ‘cd’ to change Directory. Once you been to the directory, create a playbook file with “.yml”  file extension. For example: “ping.yml” (you can name it any). Add below content and check it.

# vim ping.yml

- hosts:
    - all
  tasks:
    - action: ping

Now run the playbook like this:

# ansible-playbook ping.yml

Did it work? The output should have these sections:

GATHERING FACTS

This is when the “setup” module is being run to collect information about the hosts you are connecting to

TASK: ping

The task you defined in the playbook

PLAY RECAP

Summarizes which tasks were run, how many were success or failure, and how many changes were made

So far your playbook is essentially doing what you did using the ansible command-line.

Let’s Create a Web Server

Let’s use real time example, which we can reproduce for few more examples too. Let’s install nginx package in two systems.

Create webserver.yml which looks like this:

- hosts:
    - server1.foxutech.com
    - server2.foxutech.com
  tasks:
    - action: yum update_cache=yes
    - action: yum pkg=nginx state=present

Replace server1 and server2 with two of the hosts you are managing; they must exist in your inventory.

Run it (note that it may be slow the first time).

# ansible-playbook webserver.yml

Hope it’s working!!!, Make a note of “ok” & “Changed” values

Let’s Run it again:

# ansible-playbook webserver.yml

How do the “ok” and “changed” values look now?

Explanation: there are two tasks involving the yum module. One updates the cache of available packages (like “yum update”) and the other ensures that nginx is installed.

Once it done, you can see on both server web service installed, you can open the URL server1.foxutech.com & server2.foxutech.com and check it.

You should see “Nginx Ubuntu Default Page”

Documentation

It would be helpful if the playbook could be self-documenting, so edit webserver.yml so it now looks like this:

- hosts:
    - server1.foxutech.com
    - server2.foxutech.com
  tasks:
    - name: ensure package cache is up to date
      action: yum update_cache=yes
    - name: install web server
      action: yum pkg=nginx state=present

Run it again. You should get more helpful TASK descriptions as it runs.

Copy a File

Instead of nginx webpage, sometime we would like to have our own web page. For that that let’s write a own html page.

On ansible home directory, create a file web.html with some HTML text, e.g.

<html>
<head><title>FoxuTech’s Ansible</title></head>
<body>
This is FoxuTech’s Ansible page
</body>
</html>

Now add a new task to our playbook:

- hosts:
    - server1.foxutech.com
    - server2.foxutech.com
  tasks:
    - name: ensure package cache is up to date
      yum: update_cache=yes
    - name: install web server
      yum: pkg=nginx state=present
    - name: install index page
      copy: src=web.html dest=/var/www/html/index.html backup=yes

After this has run successfully (check for “changed=1”), point your web browser at your two hosts and check you have a new index page.

What about if we wanted to keep the original file? That is what backup=yes is for. If you log in to one of those hosts and look at the contents of that directory, you’ll see that the original file is still there but renamed to a name containing its timestamp.

# ls /var/www/html

index.html  index.html.2017-05-31@15:29~

Check and Diff

Suppose you want to know what changes ansible will make, before it makes them? Two flags are provided for this.

  • –check will tell you which changes would be made, without actually making them. (Not all modules support this)
  • –diff shows you the differences between the old and new files

It is common to use both flags. Try changing the text in front.html, and then running this command:

# ansible-playbook webserver.yml --check --diff

It should identify that index.html is going to be updated, and show you the differences.

Run it again without the –check flag and then it will actually apply the change.

Handlers

Sometimes when you make a configuration change it’s necessary to restart the service. Ansible supports this though “handlers”.

Imagine that whenever the index.html page changes you need to restart nginx (although that’s not actually true). You add a “notify:” statement to every action which needs the restart, and a “handler:” which performs the restart.

- hosts:
    - server1.foxutech.com
    - server2.foxutech.com
  tasks:
    - name: ensure package cache is up to date
      yum: update_cache=yes
    - name: install web server
      yum: pkg=nginx state=present
    - name: install index page
      copy: src=web.html dest=/var/www/html/index.html backup=yes
      notify: restart nginx
  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

Run your playbook again, firstly without changing front.html, and then after changing front.html.

In the latter case you should see

NOTIFIED: [restart nginx]

which shows that the handler was triggered.

Tags

As your playbook gets bigger, it may get slower to run, and you may wish to run only part of a playbook to bypass the earlier steps. The way to do this is using ‘tags’. Example:

- hosts:
    - server1.foxutech.com
    - server2.foxutech.com
  tasks:
    - name: ensure package cache is up to date
      yum: update_cache=yes
      tags: install
    - name: install web server
      yum: pkg=nginx state=present
      tags: install
    - name: install index page
      copy: src=web.html dest=/var/www/html/index.html backup=yes
      tags: configure
      notify: restart nginx
  handlers:
    - name: restart nginx
      service: name=nginx state=restarted

Now try:

# ansible-playbook webserver.yml -t configure

and it will run only the task which has been tagged as “configure”. When writing a playbook, you can assign whatever tags make sense to you.

To Run a playbook on Particular Hosts

You can also tell the playbook to run against only a single host or a subset of hosts. The way to do this is with the ‘-l’ (limit) option.

# ansible-playbook webserver.yml -l server2.foxutech.com

This is particularly useful for testing and staged rollout; but note that the -l flag is only a filter against the hosts already listed in the playbook. It cannot cause the playbook to run against other hosts.

For example:

# ansible-playbook webserver.yml -l 'server2.foxutech.com;server3.foxutech.com '

will only run those tasks which were already defined to run on either server2 or server3.

Hosts Group

Finally, a way to make your playbook easier to maintain is to make use of host groups in the inventory.

Edit your inventory file (/etc/ansible/hosts), remembering you have to use sudo to do this. Divide it into groups by adding group headings surrounded by square brackets, so that it looks like this:

# cat /etc/ansible/hosts

[app_web]
server1.foxutech.com ansible_ssh_user=root
server2.foxutech.com ansible_ssh_user=root
[app_db]
server3.foxutech.com ansible_ssh_user=root

Then you can simplify your playbook by listing the groups instead of the individual hosts:

- hosts:
    - app_web
  tasks:
    ... as before
- hosts:
    - app_db
  tasks:
    ... as before

Now test that everything still works:

# ansible-playbook webserver.yml

You can also use groups on the command line, e.g.

# ansible app_web -m shell -a 'ls /'

Playbook Storage

Your webserver.yml file now documents exactly how you built your web servers, and can be used to create additional servers, or rebuild a server if its disk dies.

This means that it’s a valuable asset. You should store it somewhere safe, e.g. in a version control system like subversion or git, or in a backed-up file server

This is the end, hope now you understand how to write a playbook, and how use tags, handlers. On next session will see what roles and how to create/run it.

RELATED ARTICLES
- Advertisment -

Most Popular

Recent Comments