Ansible: write and run your first playbook

What is Ansible?

Ansible is a free software for configuring and managing nodes. It easy to use and includes many built-in modules to allow easy configuration management. It uses ssh to connect the different nodes and configure them. The only thing you need on your machine in order to run Ansible is python installed ( > 2.4).

In this post I’m going to show you how to easily write your first playbook and run it. But before that let’s go over some basic definitions:


A task is simply the use of one of Ansible modules. Module implements specific functionality.  For example, installing a package would be a task since it will require us to use the ‘yum’ module. There are many modules, so a task can be running a service, fetching files, adding user and many more modules waiting for you to explore.

Let’s see how task looks like:

- name: Ensure python-ryu is installed
      name: python-ryu
      state: present

In the above example we use yum module to install a package named ‘python-ryu’. The state is the action we are using on this package. so ‘present’ tells Ansible to make sure python-ryu installed in the system. There are additional states, as ‘latest’ which means ‘make sure latest package is installed’, so if you have python-ryu-1.0 installed in your system, but there is python-ryu-2.0 available, it will be updated. This is not the case for ‘state: present’, which simply cares on whether the package is installed or not.

TIP: to see what states and other options available for yum module, use this command: ansible-doc yum


Play is a collection of tasks running on one or more hosts. It includes one or more task.


Playbook composed of one or more plays.

It’s important to be familiar with the relation between task, play and and playbook:


Install Ansible & prepare your environment

Before writing and running playbooks, you need to make sure ansible is installed on your system.

For Fedora/RHEL/CentOS simply run:

sudo dnf install ansible

Now we need to add the hosts you would like to manage and configure to ‘/etc/ansible/hosts’.

Let’s say you have two nodes, named hostA and hostB. You can  simply add these two lines to ‘/etc/ansible/hosts’:


but to easily refer the two nodes in one word, you should use ‘group’ name for both of them:


This way, to run tasks on both nodes, you can simply use ‘my_hosts’ group name.

Writing your first playbook

Before writing any lines, we need to have clear picture of what we want to run on our hosts and how we want  them to look after running the playbook.

So imagine our environment consists of two hosts:  hostA and hostB

We want to have two plays:

First play: one simple task – create file in /tmp named ‘yallo’.

Second play: two tasks  – task to add user named ‘mario’ with zsh as default shell, and anther task to install the latest  ‘zlib’ package.

We know what we want to run and on what hosts we want to run it. All that is left is to write it. Let’s start with the first play:

vi first_playbook.yml
- hosts: hostB
      - name: Create file
            path: /tmp/yallo
            state: touch

– hosts: hostB tells Ansible on which nodes to run the task in the above playbook. We chose hostB, but as we’ll see later, it’s possible to run task on several hosts or group of hosts.

tasks: is a list of tasks, each using one of the available modules of Ansible that you would like to execute on remote hosts. In our case, hostB.

Our list contain only one task that uses ‘file’ module. ‘file’ module allows us to create/remove files and directories or modify their attributes. In the example above we simply create empty file. the ‘path=/tmp/yallo’ used by the module to to create ‘yallo’ file in /tmp dir. by “state=touch” we are actually telling Ansible we would like to ensure such file exists. If it exists, ansible will do nothing, but if it doesn’t, it will create it.

Simple right? we finished writing our first play! Let’s now extend it to include the second one also:

- hosts: hostB
      - name: Create file
            path: /tmp/yallo
            state: touch

- hosts: my_hosts
  sudo: yes
      - name: Create user
            name: mario
            shell: /bin/zsh

      - name: Install zlib
            name: zlib
            state: latest

We now have two plays. How do we know that? We can see end of tasks list of our firs play and you can notice a start of new play by the line that starts with “-hosts …’.

There are two tasks – First one is for creating new user. We used the ‘user’ module for that. Remember we wanted him to have zsh as default shell? that is the ‘shell=/bin/zsh’.

Second task is about installing new package in your system. It using the ‘yum’ module with two options – name  of the package to be installed and state=latest. In the first example of this post we used ‘state=present’ to simply have the package installed in our system. ‘state=latest’ makes sure that if there is newer package available, it will be installed.

You probably noticed we have something new in the second play, except the different tasks. That is the ‘sudo: yes”. While for the first play you didn’t have to be root, because every user can create files in ‘/tmp’, for the second play you must be. Not every user can create new users in the system. So we ran the second play with sudo to make sure the play will not fail due to lack of permissions.

We finished writing our playbook. You have created file, user and installed package without knowing the actual commands to do so. Only simply yaml  format. Pretty neat!.

Running playbooks

Congrats! you wrote your first playbook. Just so you know, I’m proud of you. What are you waiting for? run it!

The command for running playbooks is pretty straightforward: ansible-playbook <playbook name>. In our case:

ansible-playbook first_playbook.yml

The results would look like

PLAY [hostB] ****************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [hostB]

TASK: [Create file] *********************************************************** 
changed: [hostB]

PLAY [my_hosts] *************************************************************** 

GATHERING FACTS *************************************************************** 
ok: [hostA]
ok: [hostB]

TASK: [Create user] *********************************************************** 
changed: [hostA]
changed: [hostB]

TASK: [Install zlib] ********************************************************** 
ok: [hostA]
ok: [hostB]

PLAY RECAP ******************************************************************** 
hostA                      : ok=5    changed=2    unreachable=0    failed=0   
hostB                     : ok=3    changed=1    unreachable=0    failed=0

That was quick! Look how what detailed output we got here (and it can be even more detailed).

First of all, you can see each new play starts with ‘PLAY: [host on which tasks applied]’. So the first play starts with ‘PLAY: [hostB]’.

‘GATHERING FACTS’  is a step in which Ansible gather all kind of information about your remote system (memory, os distribution, ip addresses, etc), ready for you to use in your playbooks. To see what information gathered in this step you can use:

ansible -m setup <hostname>

The tasks lines start with ‘TASK: [task name]’.  But the important information is right below those lines and it tells us whether the task ran successfully or failed and whether the nodes changed or not.

The user ‘mario’ wasn’t in the remote systems before running the playbook, that’s why you see ‘changed’ for each node. But the package ‘zlib’ was already installed on both them. When task doesn’t change anything and the node is already configured, you’ll get ‘ok’.

The summary lines start with ‘PLAY RECAP’.  They tell us how many  tasks ran successfully and how many failed. In case of failure due to connectivity issues, you’ll see unreachable is is greater than zero.

More playbooks!

You are ready, my young padawan! You have all the knowledge you need for writing additional great playbooks and start manage your nodes automatically.

But that’s not all. There are plenty of things left for you to learn about Ansible. Remember ‘ansible-doc’ is your friend!.

If there are additional subjects you want me to cover, send me a message or leave a comment =)

Q & A

Q: How can I install Ansible in my system if no ‘ansible’ rpm available?

A: you can use: ‘sudo pip install ansible’

Q: Where can I find a list of all Ansible core modules?

A: ansible-doc -l

Q: In ‘Running Playbooks’ you wrote “output can be even more detailed’. How?

A: ansible-playbook -vvvv <playbook name>

Q: Is there a way to configure hosts simply by using the command line, without writing any playbooks?

A: Yes, there is!  For example, our task for creating user in one simple line: ansible -m user -a “name=mario shell=/bin/zsh” my_hosts

16 thoughts on “Ansible: write and run your first playbook

  1. Its good i want check for a particular path is present or not, if present we have to rm that dir, if not present we have to create dir. how colud we do this


    1. – name: check the stats of the directory ‘/hello’
      register: hello_dir

      – name: Remove dir
      shell: rm -rf /hello
      when: hello_dir.stat.isdir is defined and hello_dir.stat_isdir

      – name: Create dir
      when: hello_dir.stat.isdir is not defined


  2. Hi, this is nice one!
    I’m super new ansible
    Then i wanna know how can i get start writing ansible playbooks using python.
    Is there any tutorial video or doc that can i learn from?
    let me know if you have a good solution.


  3. Wow. That is so elegant and logical and clearly explained. Brilliantly goes through what could be a complex process and makes it obvious.


  4. Hoi, thanks for the great guideline. Just as info . There might be people outside who are not using an sshkey. The –ask-pass option would solve this issue and allow them to run their first script with your instructions.

    ansible-playbook first_playbook.yml –ask-pass



  5. hi, am trying to checkout files from svn using subversion module but it is not deploying anything but the playbook running properly


  6. – name: verify application/database processes are not running
    shell: if ps -eaf | egrep ‘apache|http’|grep -v grep > /dev/null ;then echo ‘process_running’;else echo ‘process_not_running’;fi
    ignore_errors: true
    register: app_process_check

    If i write something like above , How do i Check/Display what value “app_process_check” has got ?


  7. Thanks! It was really easy to understand and hands on was quick too (Had some glitch in installing ansible on my Mac) so moved on to Linux system !


  8. Hi

    I am super new to ansible. I am getting below errors when running a play book .

    [root@centos7 myplatform]# ansible-playbook playbook.yml
    ERROR! The tasks/main.yml file for role ‘basic’ must contain a list of tasks

    The error appears to have been in ‘/myplatform/roles/basic/tasks/main.yml’: line 1, column 2, but may
    be elsewhere in the file depending on the exact syntax problem.

    The offending line appears to be:

    name: “Installing FTP”
    ^ here


    [root@centos7 ~]# cat /myplatform/roles/basic/tasks/main.yml
    name: “Installing FTP”
    yum: pkg=ftp state=installed


    [root@centos7 ~]# cat /myplatform/playbook.yml

    – hosts: all
    become: true
    – basic

    The colored feature in the file also not coming in my case. Please suggest


  9. Hi Breg,

    It’s a fantabulous blog. Thanks for posting !!

    Also, i would like to learn more about python scripting, would you please suggest me to get into it?


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s