Playbooks are a great way to match up tasks with specific roles, but what if we want to reuse these tasks in different roles, and what if we want to bring in tasks that somebody else has created? Well, Ansible provides a way that we can organize functionality a little bit more cleanly than we are right now, and we use something called roles to do that. So we can abstract out these tasks into roles and then just include the specific roles we want. So it provides a nice way to organize our tasks, but also to bring in tasks and roles from other people.
So to do this to start off, let's create a folder called roles, and then I'm going to tell Ansible about the roles folder in the default configuration section here. The configuration key is roles path, and I just provided a series of paths that are separated by colons. If I had another path, I could do it like this. But for now, I only have this one folder called roles, and so Ansible provides a nice flexible way to organize your project. But I like to put the roles into the roles folder.
And then for each role that we want, you create a folder for that role. So for instance, I might have a folder called-- or a role called node.js and so I'll create a folder called node.js. And then inside of that folder, we organize the roles functionalities into specific folders and files within this folder. So for instance, we create a tasks folder and inside of the tasks folder, we create a file called main.yml. So it's kind of a folder and file structure for organizing roles, and Ansible knows how to deal with this file structure automatically.
Now inside of this node.js role, let's go back to our playbook site.yml. And what I want to do is move this task into the node.js role. And we can just make the tasks the root level elements, and so the tasks are going to be an array of tasks like this that are in the main.yml file of the role folder. And now in the playbook, instead of having a specific task, I can get rid of that completely and provide a key called roles and then just include an array of roles.
Back in the node.js role, we can organize the tasks folder a little bit better. So I can put all the tasks into this main yml file, but I can also create as many task yml files as I want. So you might break up your tasks into specific chunks of functionality.
For example, install.yml and config.yml, or a couple of other standard ones. And then I can take this task, move it into install.yml-- oops-- and then include it here like this-- include install.yml. So this provides a way to organize the functionality into a bunch of different include statements, and it's useful if you have a bunch of different steps that are logically a little bit different, like installing versus configuring.
Another nice feature is that I can tag each of the includes. So another property I can provide is called tags, and then I can give this an array of tag names. So a tag name might be install and node.js install. This way when I run this role, I can provide an option on the command line to say only execute the tasks that have this specific tag. So I could execute all the install tasks or all the configuration tasks if I had a bunch of different roles that I was running at the same time.
So now my playbook site dot Y-M-L-- yml-- has an entry that maps this role, node.js, to all the hosts. And inside of this role, there's an main yml task file and an install yml task file, and I've applied tags so that we can filter what actually gets applied. For example, back in the command line, if I say Ansible Playbook and I want to run the site yml Playbook, I can provide an option called tags and then the tag that I want to filter by is node.js install. I can even omit these quotation marks, and now it will filter all of the different tasks and only run the node.js install based on its tag.
I want to head an off-camera created roles for NGINX and MongoDB, following a similar pattern to what we just did with node.js. A couple of minor differences-- if you look inside of the NGINX role, for example, notice that there's a couple more tasks inside the task folder. And if we look at the main task, which is the one that Ansible is going to run for us automatically, it has two include statements, one for installation and the other for start.
So all I've done is just separate these tasks into an install phase and a start phase, and we can filter those on the command line by using these tags. So either install and start, or more specifically NGINX colon install and NGINX colon start. And I've done the same thing for MongoDB and node.js. So MongoDB has a main file, which includes the install script and the start script.
Just like before, we can run this entire playbook by using Ansible playbook, and if I want to filter by just one of the specific tasks, I can use the tags option to that command line. Let's say I just wanted to start NGINX, or I just want to make sure that all the services are started. I can filter by the start tag, and that will skip everything else except starting all the services.
So if you want to, you can put tasks directly into the playbook itself and sometimes that's a good idea and works well. But a lot of the times, you're going to want to create independent roles that exist in a roles folder, and that way we can mix and match tasks across different playbooks as needed. And you'll see later how we can also pull in roles from other authors on the web.