官术网_书友最值得收藏!

Understanding roles – the playbook organizer

Roles are designed to enable you to efficiently and effectively reuse Ansible code. They always follow a known structure and often will include sensible default values for variables, error handling, handlers, and so on. Taking our Apache installation example from the previous chapter, we know that this is something that we might want to do over and over again, perhaps with a different configuration file each time, and perhaps with a few other tweaks on a per-server (or per inventory group) basis. In Ansible, the most efficient way to support the reuse of this code in this way would be to create it as a role.

The process of creating roles is in fact very simpleAnsible will (by default) look within the same directory as you are running your playbook from for a roles/ directory, and in here, you will create one subdirectory for each role. The role name is derived from the subdirectory namethere is no need to create complex metadata or anything elseit really is that simple. Within each subdirectory goes a fixed directory structure that tells Ansible what the tasks, default variables, handlers, and so on are for each role.

The roles/ directory is not the only play Ansible will look for roles this is the first directory it will look in, but it will then look in /etc/ansible/roles for any additional roles. This can be further customized through the Ansible configuration file, as discussed in  Chapter 2, Understanding the Fundamentals of Ansible.

Let's explore this in a little more detail. Consider the following directory structure:

site.yml
frontends.yml
dbservers.yml
roles/
   installapache/
     tasks/
     handlers/
     templates/
     vars/
     defaults/
   installtomcat/
     tasks/
     meta/

The preceding directory structure shows two roles defined in our hypothetical playbook directory, called installapache and installtomcat. Within each of these directories, you will notice a series of subdirectories. These subdirectories do not need to exist (more on what they mean in a minute, but for example, if your role has no handlers, then handlers/ does not need to be created). However, where you do require such a directory, you should populate it with a YAML file named main.yml. Each of these main.yml files will be expected to have certain contents, depending on the directory that contained them. 

The subdirectories that can exist inside of a role are as follows:

  • tasks: This is the most common directory to find in a role, and it contains all of the Ansible tasks that the role should perform.
  • handlers: All handlers used in the role should go into this directory.
  • defaults: All default variables for the role go in here.
  • vars: These are other role variables—these override those declared in the defaults/ directory as they are higher up the precedence order.
  • files: Files needed by the role should go in here—for example, any configuration files that need to be deployed to the target hosts.
  • templates: Distinct from the files/ directory, this directory should contain all templates used by the role.
  • meta: Any metadata needed for the role goes in here. For example, roles are normally executed in the order they are called from the parent playbook—however, sometimes a role will have dependency roles that need to be run first, and if this is the case, they can be declared within this directory.

For the examples we will develop in this part of this chapter, we will need an inventory, so let's reuse the inventory we used in the previous section (included in the following for convenience):

[frontends]
frt01.example.com https_port=8443
frt02.example.com http_proxy=proxy.example.com

[frontends:vars]
ntp_server=ntp.frt.example.com
proxy=proxy.frt.example.com

[apps]
app01.example.com
app02.example.com

[webapp:children]
frontends
apps

[webapp:vars]
proxy_server=proxy.webapp.example.com
health_check_retry=3
health_check_interal=60

Let's get started with some practical exercises to help you to learn how to create and work with roles. We'll start by creating a role called installapache, which will handle the Apache installation process we looked at in the previous section. However, here, we will expand it to cover the installation of Apache on both CentOS and Ubuntu. This is good practice, especially if you are looking to submit your roles back to the community as the more general purpose they are (and the wider the range of systems they will work on), the more useful they will be to people. Step through the following process to create your first role:

  1. Create the directory structure for the installapache role from within your chosen playbook directorythis is as simple as this:
$ mkdir -p roles/installapache/tasks
  1. Now, let's create the mandatory main.yml inside the tasks directory we just created. This won't actually perform the Apache installationrather, it will call one of two external tasks files, depending on the operating system detected on the target host during the fact-gathering stage. We can use this special variable,  ansible_distribution, in a when condition to determine which of the tasks files to import:
---
-
name: import a tasks based on OS platform
import_tasks: centos.yml
when: ansible_distribution == 'CentOS'
- import_tasks: ubuntu.yml
when: ansible_distribution == 'Ubuntu'
  1. Create centos.yml in roles/installapache/tasks to install the latest version of the Apache web server via the yum package manager. This should contain the following content:
---
- name: Install Apache using yum
yum: name: "httpd" state: latest
- name: Start the Apache server
service:
name: httpd
state: started
  1. Create a file called ubuntu.yml in roles/installapache/tasks to install the latest version of the Apache web server via the apt package manager on Ubuntu. Notice how the content differs between CentOS and Ubuntu hosts:
---
- name: Install Apache using apt
apt: name: "apache2" state: latest
- name: Start the Apache server
service:
name: apache2
state: started

For now, we're keeping our role code really simplehowever, you can see that the preceding tasks files are just like an Ansible playbook, except that they lack the play definition. As they do not come under a play, they are also at a lower indentation level than in a playbook, but apart from this difference, the code should look very familiar to you. In fact, this is part of the beauty of roles: as long as you pay attention to getting the indentation level right, you can more or less use the same code in a playbook or a role.

Now, roles don't run by themselveswe have to create a playbook to call them, so let's write a simple playbook to call our newly created role. This has a play definition just like we saw before, but then rather than having a tasks: section within the play, we have a roles: section where the roles are declared instead. Convention dictates that this file be called site.yml, but you are free to call it whatever you like:

---
- name: Install Apache using a role
hosts: frontends
become: true

roles:
- installapache

For clarity, your final directory structure should look like this:

.
├── roles
│ └── installapache
│ └── tasks
│ ├── centos.yml
│ ├── main.yml
│ └── ubuntu.yml
└── site.yml

With this completed, you can now run your site.yml playbook using ansible-playbook in the normal wayyou should see output similar to this:

$ ansible-playbook -i hosts site.yml

PLAY [Install Apache using a role] *********************************************

TASK [Gathering Facts] *********************************************************
ok: [frt01.example.com]
ok: [frt02.example.com]

TASK [installapache : Install Apache using yum] ********************************
changed: [frt02.example.com]
changed: [frt01.example.com]

TASK [installapache : Start the Apache server] *********************************
changed: [frt01.example.com]
changed: [frt02.example.com]

TASK [installapache : Install Apache using apt] ********************************
skipping: [frt01.example.com]
skipping: [frt02.example.com]

TASK [installapache : Start the Apache server] *********************************
skipping: [frt01.example.com]
skipping: [frt02.example.com]

PLAY RECAP *********************************************************************
frt01.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
frt02.example.com : ok=3 changed=2 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0

That's ityou have created, at the simplest possible level, your first role. Of course (as we discussed earlier), there is much more to a role than just simple tasks as we have added here, and we will see expanded examples as we work through this chapter. However, the preceding example is intended to show you how quick and easy it is to get started with roles.

Before we look at some of the other aspects relating to roles, let's take a look at some other ways to call your role. Ansible allows you to statically import or dynamically include roles when you write a playbook. The syntax between these importing or including a role is subtly different, and notably, both go in the tasks section of your playbook rather than in the roles section. The following is a hypothetical example that shows both options in a really simple playbook. The roles directory structure including both the common and approle roles would have been created in a similar manner as in the preceding example:

--- 
- name: Play to import and include a role
hosts: frontends
tasks: - import_role: name: common - include_role: name: approle

These features were not available in versions of Ansible earlier than 2.3, and their usage changed slightly in version 2.4 for consistency with the way that some other Ansible features work. We will not worry about the details of this here as Ansible is now on release 2.9, so unless you absolutely have to run a much earlier version of Ansible, it is sufficient to assume that these two statements work as we shall outline in the following.

Fundamentally, the import_role statement performs a static import of the role you specify at the time when all playbook code is parsed. Hence, roles brought into your playbook using the import_role statement are treated just as any other code in a play or role is when Ansible begins parsing. Using import_role is basically the same as declaring your roles after the roles: statement in site.yml, just as we did in the preceding example.

include_role is subtly but fundamentally different in that the role you specify is not evaluated when the playbook is parsed initiallyrather, it is processed dynamically during the playbook run, at the point at which include_role is encountered.

Probably the most fundamental reason to choose between the include or import statements given in the preceding is loopingif you need to run a role within a loop, you cannot do so with import_role and so must use include_role. There are, however, both benefits and limitations to both, and you will need to choose the most appropriate one for your scenariothe official Ansible documentation (https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse.html#dynamic-vs-static) will help you to make the right decision. 

As we have seen in this section, roles are incredibly simple to get started with and yet offer an incredibly powerful way in which to organize and reuse your Ansible code. In the next section, we will expand upon our simple task-based example by looking at adding role-specific variables and dependencies into your code.

主站蜘蛛池模板: 茂名市| 长沙县| 恩平市| 惠东县| 连平县| 镇坪县| 浙江省| 石台县| 威远县| 新河县| 衢州市| 洛宁县| 西平县| 诸城市| 江山市| 宜川县| 乐亭县| 绥江县| 饶平县| 饶平县| 德安县| 客服| 赫章县| 宜宾市| 宿松县| 阿拉善右旗| 东乌| 舞钢市| 元江| 遵义市| 郁南县| 壶关县| 岳阳县| 密云县| 漳平市| 米脂县| 九台市| 绩溪县| 天门市| 泽库县| 明水县|