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 126.96.36.199.
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 188.8.131.52. 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.
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.