Article directory
Reuse Playbooks
The two reuse mechanisms supported by Ansible are Roles and Includes.
-
Roles
It is a collection of reusable tasks and variables, a concept similar to packages in programming languages. -
Includes
It is a method of decomposing a Playbook into multiple files. You can put some commonly used tasks and variables in separate files, and then reference these files in the required Playbook.
include statement
In Ansible, you can use the include keyword to introduce one or more files into a playbook to achieve 重用
the purpose of the code. By writing commonly used and common tasks in one file, the codes for these tasks can be included 避免
in each Playbook 重复编写
, greatly reducing the workload. In addition, using include statements is okay 提高代码的可读性和可理解性
because common code is abstracted away 使得Playbook的代码更加简洁清晰,易于维护和更新
. At the same time, using the include statement is also helpful 降低代码的耦合性
, because abstracting common tasks can make the dependencies between different Playbooks clearer, thereby avoiding the problem of excessive code coupling.
The following is a simple example using the include statement:
Suppose we have an ansible project in which two playbooks are used: web.yaml and db.yaml, which are used to deploy the web server and database server respectively. Now we want to introduce a common task file: common.yaml into the two Playbooks to avoid repeatedly writing the same task code in the two Playbooks.
First, create a folder named tasks in the root directory of the project to store the common task file common.yml. Then create a file named common.yml in the folder with the following content:
- name: install packages
remote_user: root
yum:
name: git,vim,curl,wget,unzip,zip,net-tools
state: present
This task is used to install some commonly used software packages, which need to be installed in both web servers and database servers.
Next, we can use the include statement in web.yaml and db.yaml to introduce the file. The code is as follows:
web.yaml file:
- name: Deploy web server
hosts: test1
tasks:
- include: tasks/common.yaml
- name: install and configure Apache
yum:
name: httpd
state: present
- service:
name: httpd
enabled: true
state: started
db.yaml file:
- name: Deploy database server
hosts: test2
tasks:
- include: tasks/common.yaml
- name: install and configure Mysql
yum:
name: mariadb-server
state: present
- service:
name: mariadb
enabled: true
state: started
In the above code, we use the include statement to introduce the tasks in the tasks/common.yml file. This avoids repeatedly writing task codes for installing common software packages in web.yaml and db.yaml.
How to write role
Role has a more powerful and flexible code reuse and sharing mechanism than include. include is similar to include in programming languages. It reuses a single file and has limited reuse functions.
The role is similar to a "Package" in a programming language, which can reuse a set of files to form a complete function. For example, installing and configuring Apache requires not only tasks to implement the installation package and copy templates, but also template files for httpd.conf and index.html, as well as the restart function implemented by the handler file. These files can be placed in a role for reuse in different Playbook files.
Define the complete directory structure of the role
在Ansible中,通过遵循特定的目录结构,就可以实现对role定义。
So how do you create a role directory?
ansible-galaxy init myrole
# 上述命令会在当前目录下创建一个名为myrole的目录,其默认包含了标准的角色目录结构。
A standard role directory structure is as follows:
If you want to call role in ansible.yaml
---
- hosts: test1
remote_user: root
roles:
- myrole
Ansible does not require the role to contain all the above directories and files. You can add the corresponding directories and files according to the function of the role. Here are the functions of each directory and file:
- tasks directory: stores role task files, which
main.yaml
are required. Other task files can be added as needed. - templates directory: stores Jinja2 template files used by roles.
- files directory: stores ordinary files used by characters.
- vars directory: stores the variable files used by the role, which
main.yaml
are required. Other variable files can be added as needed. - defaults directory: stores the default variables of the role, which
main.yaml
are required. Other default variable files can be added as needed. - meta directory: stores character metadata files, including character name, author, dependencies and other information.
- handlers directory: stores role handlers, which
main.yaml
are required, and other handlers can be added as needed. - README.md: The description file of the role, including the purpose of the role, how to use it, and other information.
- The tests directory contains the following files:
inventory
: The host list file of the role's test case, which defines the host and host group information that needs to be used in the test case.test.yaml
: The test case file of the role, which defines the tasks and test methods that need to be performed in the test case.
In addition, the following files do not need to be absolute or relative paths. They can be used directly just like files placed in the same directory.
copy or scipt uses files under roles/x/files/
Template uses files under roles/x/templates
include uses files under roles/x/tasks
When writing a role, the role entry file roles/x/tasks/main.yaml should generally be included. Other files and directories can be added according to your own needs.
role with parameters
The following defines a role with parameters, named myrole, and its directory structure is as follows
main.yaml
roles
myrole
tasks
main.yaml
In roles/myrole/tasks/main.yaml, just use the variables defined by { { }}
---
- name: use param
debug:
msg="{
{ param }}"
Use role with parameters
In main.yaml, you can use myrole as follows:
---
- hosts: test1
remote_user: root
roles:
- role: myrole
param: 'Test ansible'
- role: myrole
param: 'Test ansible2'
role specifies default parameters
After specifying the default parameters, if parameters are passed when calling, then the passed parameter values will be used. If no parameters are passed when calling, then the default parameter values will be used.
Specifying default parameters is very simple, take the above parameters as an example
main.yaml
roles
myrole
tasks
main.yaml
defaults
main.yaml
In roles/myrole/defaults/main.yaml
---
- hosts: test1
remote_user: root
roles:
- role: myrole
- role: myrole
param: "I am the value from external"
The difference between default variables and ordinary variables
In the previous definition, you may be curious why the variables under the folder default and vars are added to Play. Are they different from the above?
default/main.yaml are default variables. The priority is the lowest among all variables and is used to place some variables that need to be overwritten.
The variables in vars/main.yaml are role variables with relatively high priority. Some variables are placed that do not want to be overwritten. Therefore, the name of the role is generally added as a prefix when naming the variables. If placed, they may be accidentally overwritten by variables defined in the Playbook.
tasks/main.yaml How to use variables, static files and templates
Tasks are the core of Playbooks and roles. Roles are a way to organize Playbooks and include resources such as tasks, templates, variables, and files. In the role, the task file tasks/main.yaml is the entry file, in which resources such as variables, static files, and templates can be used. Learning how to use these resources is the key to writing roles.
The resources in role can be divided into two categories:
- One class is automatically loaded and usually placed in x/*/main.yaml
- The other type needs to be called explicitly, usually placed in x/*/other_but_main.yaml.
Use variables in x/*/main.yaml
Use variables and handlers in x/*/main.yaml
Use variables and handlers in x/*/main.yaml just like resources in the same Playbook
Use files under x/{files,template}/
Use variables placed here as if they were files in the same directory. Requires the module and the file type used to match
copy and script correspond to files in the files directory
template corresponds to the file under templates
For example, the directory of role x is as follows
[root@localhost ansible]# tree myrole/
myrole/
├── files
│ └── index.html
├── tasks
│ └── main.yml
├── templates
│ └── httpd.conf.j2
└── vars
└── main.yml
The files below files are
<!DOCTYPE html>
<html>
<head>
<title>hello world</title>
</head>
<body>
hi I am csq
</body>
</html>
The files under vars are
---
# http.conf vars
http_port: 9999
The files under tasks are
---
- name: Deploy server web
yum:
name: httpd
state: present
- name: copy index.html
copy:
src: index.html
dest: /var/www/html/index.html
- name: copy http.conf
template:
src: httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
- name: service restart
service:
name: httpd
enabled: true
state: restarted
- name: Release Port
firewalld:
port: 9999/tcp
permanent: true
state: enabled
Execute this role
---
- hosts: test1
remote_user: root
roles:
- myrole
Use resources from x/*/other_but_main.yaml
If the content below role x is more complex and you need to further classify tasks or vars, you can use files other than main.yaml. How should I use tasks or vars from other files? Ansible provides two keywords: include and include_vars, which are used to introduce tasks and vars contained in other files other than main.yaml in the role.
For example, in the following role
myrole/
├── tasks
│ └── main.yml
│ └── http_install.yaml
│ └── http_configure.yaml
│ └── mysql_install.yaml
│ └── mysql_configure.yaml
├── templates
│ └── httpd.conf.j2
│ └── mysql.conf.j2
└── vars
└── httpd.yaml
└── mysql.yaml
Then, in x/*/main.yaml, after introducing the httpd variables through include_var, you can load the tasks in the files install.yaml and configure.yaml through include.
---
- name: add the os specific varibles
include_vars: httpd.yaml
- name: install packages
yum:
name: {
{
packages}}
state: present
- include: http_install.yaml
- include: http_configure.yaml
role dependencies
Installing an Nginx requires configuring the yum repository. If you do not want to re-implement the function of configuring the yum repository in the Nginx Playbook, you can solve it through role dependencies. The definition file of role dependency is x/meta/main.yaml. If role x is defined as dependent on role y, role y will be called before role x is called in the Playbook. When multiple roles depend on the same role, Ansible will automatically filter to avoid repeatedly calling roles with the same parameters.
In the following example, both role db and Web depend on role common. If db and Web are called in the Playbook, Ansible will ensure that role common is run first and only once before role db and Web are run.
playbook.yaml
roles
├── common
│ └── tasks
│ └── main.yaml
├── db
│ ├── meta
│ │ └── main.yaml
│ └── tasks
│ └── main.yaml
└── web
├── meta
│ └── main.yaml
└── tasks
└── main.yaml
Add in {web,db}/meta/main.yaml
dependencies:
- {
role: common }
The content of main.yaml below common is
- name: xiugai quanxian
command: chattr -a csq.txt
The content of main.yaml below web is
- name: shuru xinxi
shell: echo "I am web,hi csq" >> csq.txt
- name: jia quanxian
command: chattr +a csq.txt
The content of main.yaml below db is
- name: shuru xinxi
shell: echo "I am db,hi csq" >> csq.txt
- name: jia quanxian
command: chattr +a csq.txt
The content of playbook.yaml is
---
- hosts: test1
remote_user: root
roles:
- common
- db
- web
Results of the
[root@localhost ansible]# ansible-playbook main.yaml
PLAY [test1] ***********************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************************
ok: [192.168.200.30]
TASK [common : xiugai quanxian] ****************************************************************************************************************************
changed: [192.168.200.30]
TASK [db : shuru xinxi] ************************************************************************************************************************************
changed: [192.168.200.30]
TASK [db : jia quanxian] ***********************************************************************************************************************************
changed: [192.168.200.30]
TASK [web : shuru xinxi] ***********************************************************************************************************************************
changed: [192.168.200.30]
TASK [web : jia quanxian] **********************************************************************************************************************************
changed: [192.168.200.30]
PLAY RECAP *************************************************************************************************************************************************
192.168.200.30 : ok=6 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Then check whether the content of the remote host has changed and whether the hidden permissions are still there
[root@localhost ansible]# ansible test1 -m shell -a "cat csq.txt && lsattr csq.txt"
192.168.200.30 | CHANGED | rc=0 >>
I am web,hi csq
I am web,hi csq
-----a---------- csq.txt