Ansible - Roles
Ansible 2.0
At the end of this article, we'll have the following file structure.
So far, we learned how Ansible can interact with configured clients from the command line with the ansible command, and how we can automate configuration with playbooks run through the ansible-playbook command.
We can use two techniques for reusing a set of tasks: includes and roles.
Roles are good for organizing Tasks and encapsulating data needed to accomplish those Tasks.
For example, to install Nginx, we need to add a package repository, install the package and set up configuration. We've installed Nginx using a Playbook, but as we add more functionality to our Playbook, they can become difficult to maintain as a single file. Roles allow us to create very minimal playbooks that then look to a directory structure to determine the configuration steps they need to perform.
In order for Ansible to correctly handle roles, we should build a directory structure so that Ansible can find and understand. We can do this by creating a Roles directory in our working directory.
The directory structure for Roles looks like this:
rolename - files - handlers - meta - templates - tasks - vars
A role's directory structure consists of files, handlers, meta, templates, tasks, and vars.
These are the directories that will contain all of the code to implement our configuration. We may not use all of the directories, so in real practice, we may not need to create all of these directories.
- files: This directory contains regular files that need to be transferred to the hosts we are configuring for this role. This may also include script files to run.
- handlers: All handlers that were in our playbook previously can now be added into this directory.
- meta: This directory can contain files that establish role dependencies. We can list roles that must be applied before the current role can work correctly.
- templates: We can place all files that use variables to substitute information during creation in this directory.
- tasks: This directory contains all of the tasks that would normally be in a playbook. These can reference files and templates contained in their respective directories without using a path.
- vars: Variables for the roles can be specified in this directory and used in our configuration files.
Ansible will search for and read any yaml file called roles/nginx/tasks/main.yml automatically.
We'll reorganize our nginx.yml file and put each component within the corresponding directory to create a cleaner set.
Here is our current nginx.yml:
--- - hosts: aws tasks: - name: Installs Nginx apt: pkg=nginx state=installed update_cache=true notify: - Start Nginx - name: Upload default index.php for host copy: src=static_files/index.php dest=/usr/share/nginx/html/ mode=0644 register: php ignore_errors: True - name: Remove index.html for host command: rm /usr/share/nginx/html/index.html when: php|success - name: Upload default index.html for host copy: src=static_files/index.html dest=/usr/share/nginx/html/ mode=0644 when: php|failed handlers: - name: Start Nginx service: name=nginx state=started
If we run ansible-playbook:
$ ansible-playbook -s nginx.yml -u ubuntu PLAY [aws] ******************************************************************** GATHERING FACTS *************************************************************** ok: [54.153.20.237] TASK: [Installs Nginx] ******************************************************** ok: [54.153.20.237] TASK: [Upload default index.php for host] ************************************* changed: [54.153.20.237] TASK: [Remove index.html for host] ******************************************** changed: [54.153.20.237] TASK: [Upload default index.html for host] ************************************ skipping: [54.153.20.237] PLAY RECAP ******************************************************************** 54.153.20.237 : ok=4 changed=2 unreachable=0 failed=0
We only want to keep the lines of tasks. Also, we can remove the extraneous spaces to the left of our tasks. After our changes, our new tasks/main.yml file will look like this:
--- - name: Installs Nginx apt: pkg=nginx state=installed update_cache=true notify: - Start Nginx - name: Upload default index.php for host copy: src=index.php dest=/usr/share/nginx/html/ mode=0644 register: php ignore_errors: True - name: Remove index.html for host command: rm /usr/share/nginx/html/index.html when: php|success - name: Upload default index.html for host copy: src=index.html dest=/usr/share/nginx/html/ mode=0644 when: php|failed
As we can see, the file just lists the steps that are to be performed, which makes it reads well.
We also made a change how we references external files in our configuration. Our src lines reference a static_files directory. This is unnecessary if we place all of our static files in the files subdirectory. Ansible will find them automatically.
Now that we have the task portion of the playbook in the tasks/main.yml file, we need to move the handlers section into a file located at handlers/main.yml.
- name: Start Nginx service: name=nginx state=started
Move index.html and index.php pages out of the static_files directory and put them into the roles/nginx/files directory.
Outside of the entire role structure, in our working directory, we can create a playbook file, play.yml:
--- - hosts: aws roles: - role: nginx
Time to run ansible-playbook:
$ ansible-playbook -s play.yml -u ubuntu PLAY [aws] ******************************************************************** GATHERING FACTS *************************************************************** ok: [54.153.20.237] TASK: [nginx | Installs Nginx] ************************************************ ok: [54.153.20.237] TASK: [nginx | Upload default index.php for host] ***************************** ok: [54.153.20.237] TASK: [nginx | Remove index.html for host] ************************************ changed: [54.153.20.237] TASK: [nginx | Upload default index.html for host] **************************** skipping: [54.153.20.237] PLAY RECAP ******************************************************************** 54.153.20.237 : ok=4 changed=1 unreachable=0 failed=0
I cloned it from Ansible repo, Ansible-Playbooks-Samples.
Ansible 2.0
Ph.D. / Golden Gate Ave, San Francisco / Seoul National Univ / Carnegie Mellon / UC Berkeley / DevOps / Deep Learning / Visualization