Introduction to Ansible Playbook – Part 2

In the previous post, you saw how to run a basic Ansible playbook. The example wall command ran a single command in all the configured servers. Let’s spice it up a bit by adding more tasks in the playbook.

For this session, I am trying to install MongoDB on a set of servers. MongoDB is a free and open-source cross-platform document-oriented database program. I am using Ubuntu 16.04. My setup includes 1 Ansible control machine and 2 remote servers. My Ansible version is 2.2.1.0.

You have to update the inventory file with the new list of servers first. If you haven’t enabled passwordless SSH connection to your remote machines, do that. Note that instead of the default inventory file, I am using inventory.ini file and while running the playbook I will be using -i inventory.ini in the command. You can use the default inventory file if you want.

sudo vim /home/mdtutorials2/inventory.ini
[mongodb_servers]
remote-machine-1
remote-machine-2

[web_servers]
remote-machine-3
remote-machine-4

I have grouped 2 servers under mongodb_servers. You will be running the MongoDB play against this group.

Manual steps for installing MongoDB on Ubuntu 16.04

  • sudo apt-key adv –keyserver hkp://keyserver.ubuntu.com:80 –recv 0C49F3730359A14518585931BC711F9BA15703C6
  • echo “deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse” | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list
  • sudo apt-get update
  • sudo apt-get install -y mongodb-org
  • sudo service mongod start

Let’s see how we can convert these steps to Ansible tasks.

Converting the first step to a Task

Now when you are writing a task, the first thing to find is, which module to use for the particular task. Just doing a google search like ‘Ansible <your purpose/command>’ will provide you with the modules in most cases.

In this case, my first step is to add a keyserver for the apt-repository. When I do a google search for ‘Ansible add key server’, the first result shown was from Ansible docs, apt-key. From that module documentation, the parameters keyserver, state, and id are required. The state parameter has the value ‘present’ by default. But still, it is better to add it. The documentation also provides some examples at the bottom of the page.

- name: Add APT key 
  apt_key: 
    keyserver: "hkp://keyserver.ubuntu.com:80" 
    id: "0C49F3730359A14518585931BC711F9BA15703C6"
    state: present

I added the name, which will be shown in the execution summary. The apt-module will first check the remote servers for the presence of the key. We have the given the state as present. It means the required state after the task runs, is the key to be present. If the key is not present, it will be added. If it already present, then the task won’t change anything. So repeating the task won’t have any effect on the system state.

Converting Second Step to a Task

The next step is adding the repo details. I searched for Ansible apt-repo module and was redirected to the apt-repository module. From the module, I checked what all parameters I require and also whether it is supported in the installed Ansible version. I am using 2.2.1.0. The first parameter ‘codename’ was introduced in 2.3 only. So I can’t use it. Make sure the version compatibility is there. Or else Ansible will throw an error: ‘unsupported parameter for module’.

I am using the repo parameter for specifying the location of the repo, the state parameter for specifying whether I want the repo to be added or removed and the filename parameter. You don’t have to enter the full path to the filename(/etc/apt/sources.list.d/), since it is stated in the comments against the repo parameter that it ‘Sets the name of the source list file in sources.list.d. ‘

- name: Add APT repository 
  apt_repository: 
    repo: deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse 
    state: present 
    filename: 'mongodb-org-3.4'

Converting the last set of steps to Tasks

The last three steps are for updating the package list, downloading the package and starting the service. I searched for the modules required and the parameters needed like I did for last two tasks. Now, the full Ansible playbook for installing the MongoDB looks like this.

Ansible playbook example

- hosts: mongodb_servers
  tasks:
  - name: Add APT key
    apt_key:
      keyserver: "hkp://keyserver.ubuntu.com:80"
      id: "0C49F3730359A14518585931BC711F9BA15703C6"

  - name: Add APT repository
    apt_repository:
      repo: deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse
      state: present
      filename: 'mongodb-org-3.4'

  - name: Update repo list and download mongodb package
    apt:
      name: mongodb-org
      update_cache: yes

  - name: Start the mongodb service
    service:
      name: mongod
      state: started

I ran the playbook by using the following command.

ansible-playbook -s -i inventory.ini mongodb.yaml

If you look at the execution status, you can see that each task is run on all the servers before starting with the next task. If the task fails one node, then no further tasks will run on the failed node. The APT key and APT repository tasks show the status as OK since I had already executed those both tasks before. When I ran the Ansible playbook again, since the remote system was in the required state, nothing changed.

Note – When running the playbook, if a task fails for a particular host, then no other task would run for that host in the current playbook execution. But since the tasks are idempotent, you can run the playbook again after fixing the issues.

 

ansible playbook tutorial MongoDB installation

Playbook with multiple plays

An Ansible playbook can also have multiple plays. For example, in the previous playbook, we can add a new play for installing Apache server. But we will be targeting the new play for a different set of servers.

Add the below play in the existing playbook, below the current play for installing mongoDB.

- hosts: web_servers
  vars:
    http_port: 80
  tasks:
  - name: ensure apache is at the latest version
    apt:
      name: httpd
      state: present
  - name: write the apache config file
    template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf

You can check the entire playbook at github.

The new play will install the httpd package in the remote servers in the first task. It will then update the /etc/httpd.conf file in the remote servers using the template module. What the template module does is, it will replace the variables in the httpd.j2 file, available in the local machine, with the values provided in the playbook, like http_port. And then it will copy this file to the remote servers. We will learn more about templates in a later section.

Like this we can added multple plays in a playbook, each having its set of variables.

In the next post, we will see how to organize a complex Ansible playbook with multiple plays using roles.