Ansible 角色

Ansible角色

使用Ansible角色可以有更多的机会去重用以前便携的Playbook中的代码。可以在标准化目录结构中打包所有任务、变量、文件、模版以及调配基础架构或部署应用其他资源。

除了自行编写、使用角色外,也可从其他来源获取角色。常用红帽企业Linux管理角色包含在rhel-system-roles软件包中可以方便的去使用。也可以从Ansible Galaxy网站获取由社区提供的其他角色。

使用ansible-galaxy list可以看到在在当前Ansible配置环境下找到了Role角色列表。

那么Ansible怎么发现这些Role呢?这些Role的路径在ansible.cfg配置文件中已经定义好了,每个目录之间通过冒号分隔:

1
2
3
4
[defaults]
inventory=./inventory
remote_user=devops
roles_path=./roles:/usr/share/ansible/roles:/etc/ansible/roles

Ansible角色子目录

子目录 描述
defaults 此目录中的main.yml文件包含角色变量的默认值,使用角色时可以覆盖这些默认值。这些变量的优先级较低,应该在Play中更改和定义。
files 此目录包含由角色要处理的全部静态文件
handles 此目录中的main.yml文件包含角色的处理程序
meta main.yml中包含角色相关信息,如作者、许可证、平台、角色依赖项
tasks main.yml中包含角色任务的定义
templates 此目录包含角色引用的template模板
tests 此目录包含清单和test.yml Playbook,用于进行测试
vars 此目录的main.yml文件定义角色的变量值。这些变量通常用于角色内部用途。这些变量的优先级较高,不应在Playbook中覆盖修改

定义变量和默认值

对于角色变量可以通过在vars目录下的main.yml文件来定义。与其他变量一样,使用这些变量需要在角色文件中引入{{ VARS_NAME }}。这些变量具有较高的优先级,无法被Ansible中清单变量覆盖。

默认变量在defaults目录下的main.yml文件中定义。它们的变量优先级是最低的,任何定义变量的形式都会将其覆盖,所以更改默认变量可以使Play操作更精准、更适合受控主机。

可以在vars/main.yml或defaults/main.yml中定义具体的变量,但没必要在两者中都定义变量。

在Playbook中使用Ansible角色

可以在Play中引入roles即可使用。

1
2
3
4
- hosts: remote server
roles:
- role1
- role2

角色中使用的任何copy、script、template或include_tasks/import_tasks任务都可以引用角色中相关的文件、模版或任务文件,并且无需使用相对路径或绝对路径,因为Ansible会自动在角色的files、templates、tasks子目录下去寻找他们。

控制执行顺序

在Ansible中的每一个Play是会按照Play的顺序依次执行。在每个Play中如果定义了角色,那么会优先运行角色,之后再运行任务。在最后执行被激活的handles处理程序。

在某些情况下,可能需要在执行角色任务之前执行一些任务,你可以为Play配置pre_tasks部分,这样就可以在运行角色之前执行一部分任务。如果配置在pre_tasks中的任务出发了handles处理程序。那么也会在角色或其他普通任务之前执行处理程序。

当然也可以使用为Play配置post_tasks部分,来让任务在普通任务之后和激活的处理程序之后再运行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
---
- name: Play to illustrate order
hosts: example.com
pre_tasks:
- debug:
msg: "I am pre task"
notify: my handler
roles:
- role1
tasks:
- debug:
msg: "I am nomal task"
notify: my handler
post_tasks:
- debug:
msg: "I am posted handler"
...

上面的例子中,每个任务部分都会执行debug任务来通知my handler处理程序。my handler任务执行了三次:

  • 第一次在执行了所有的pre_tasks任务后执行处理程序
  • 第二次在执行角色结束后的普通tasks任务后执行
  • 第三次是在执行完post_tasks任务后执行处理程序

除了将角色包含在Play中的roles部分外,也可以将角色添加到普通的tasks中。使用include_role模块可以动态包含角色,使用import_role模块可以静态导入角色。

1
2
3
4
5
6
7
8
9
10
11
12
---
- name: Execute a role as a task
hosts: localhost
tasks:
- name: a simple task
debug:
msg: "Im first task"

- name: "A task to include role here"
include_role:
name: linux-system-roles.network
...

RHEL 系统角色

RHEL红帽系统中,从Linux 7.4开始,系统内随附了多个Ansible角色。它们位于rhel-system-roles软件包内。RHEL8中,需要启动AppStream仓库来安装此软件包。

角色名 描述
rhel-system-roles.kdump 配置kdump崩溃恢复服务
rhel-system-roles.network 配置网络
rhel-system-roles.postfix 配置postfix服务为每个主机配置邮件传输代理
rhel-system-roles.selinux 配置和管理SELinux自定义,包括模式、文件、端口上下文、布尔值设置和SELinux用户
rhel-system-roles.timesync 使用网络时间协议配置时间同步

访问RHEL系统角色文档

安装后,这些RHEL系统角色文档存放在/usr/share/doc/rhel-system-roles中,其中还包含了如何去使用以及使用的例子。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
├── kdump
│   ├── COPYING
│   ├── README.html
│   └── README.md
├── network
│   ├── example-bond-with-vlan-playbook.yml
│   ├── example-bridge-with-vlan-playbook.yml
│   ├── example-down-profile-playbook.yml
│   ├── example-eth-simple-auto-playbook.yml
│   ├── example-eth-with-vlan-playbook.yml
│   ├── example-infiniband-playbook.yml
│   ├── example-inventory
│   ├── example-macvlan-playbook.yml
│   ├── example-remove-profile-playbook.yml
│   ├── LICENSE
│   ├── README.html
│   └── README.md
├── postfix
│   ├── COPYING
│   ├── README.html
│   └── README.md
├── selinux
│   ├── COPYING
│   ├── example-selinux-playbook.yml
│   ├── README.html
│   └── README.md
└── timesync
├── COPYING
├── example-timesync-playbook.yml
├── example-timesync-pool-playbook.yml
├── README.html
└── README.md

时间同步角色例子

如果为受控主机配置NTP时间同步服务,那么可以使用rhel-system-roles.timesync角色自动化配置。

通过/usr/share/doc/rhel-system-roles/timesync/README.md查看示例和需要用到的变量。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
---
- name: Config NTP sync service
hosts: all
vars:
timesync_ntp_servers:
- hostname: 0.rhel.pool.ntp.org
iburst: yes
- hostname: 1.rhel.pool.ntp.org
iburst: yes
timezone: Asia/Shanghai
roles:
- rhel-system-roles.timesync

tasks:
- name: Set TimeZone
timezone:
name: "{{ timezone }}"
...

也可以把在Play中定义的变量放到变量文件中。将变量文件可以放到group_varshost_vars子目录中。

配置SELinux角色

使用linux-system-roles.selinux角色控制SELinux行为。t

通过/usr/share/doc/rhel-system-roles/selinux/README.md查看示例和需要用到的变量。

设置SELinux运行模式

变量 selinux_state: enforcing。可以设置为enforing、permissive、disabled。如果不设置则不更改。

设置SELinux布尔值

例如将httpd_enable_homedirs布尔值永久设置为no

1
2
3
4
selinux_booleans:
- name: 'http_enable_homedirs'
state: 'on'
persistent: 'yes'

设置SELinux fcontext上下文

下面的例子完成了对/srv/www目录下的所有文件的默认SELinux类型设置为httpd_sys_content_t

1
2
3
4
selinux_fcontexts:
- target: '/srv/www(/.*)?'
setype: 'httpd_sys_content_t'
state: present

使用selinux_restore_dirs变量指定要对其运行restorecon目录的列表。

设置SELinux端口

使用selinux_ports变量可以对端口进行管理。

1
2
3
4
5
selinux_ports: 
- ports: '82'
setype: 'http_port_t'
proto: 'tcp'
state: 'present'

创建角色框架

创建角色不需要额外的开发工具,角色是文件目录结构和文件组成的。可以使用创建目录和编辑文件命令配合完成创建一个角色框架。为了节省时间,可以使用ansible-galaxy init来创建角色框架。

ansible-galaxy init my_role

1
2
$ ls my_role/
defaults files handlers meta README.md tasks templates tests vars

默认变量的覆盖

在以下情况中,角色中defaults目录中定义的默认变量会被覆盖:

  • 在清单文件中定义,作为主机变量或组变量
  • 在playbook项目的group_vars或hosts_vars目录下的YAML文件中定义
  • 作为变量嵌套Play的vars关键字中定义
  • 在Play的定义roles角色时的所定义的变量

安装V2ray-core服务角色示例

功能如下:

  • 自动安装最新版本
  • 按照受控节点平台自动选择platform平台
  • 可以选择从Github/Jsdelivr/用户自定义V2ray-core地址下载
  • 可以控制卸载

Tasks角色任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
---
# tasks file for v2ray
- name: Prepare to Install V2ray-core
block:
- name: V2ray download path is exist
file:
path: "{{ v2ray_download_path }}"
state: directory
mode: 0755
- set_fact:
install_error: false

when: v2ray_present

- name: Get the latest V2ray version and servers info
block:

- name: Get Server machine platform
shell: |
case "${1:-"{{ ansible_facts.machine }}"}" in
i686|i386)
echo '32'
;;
x86_64|amd64)
echo '64'
;;
*armv7*|armv6l)
echo 'arm'
;;
*armv8*|aarch64)
echo 'arm64'
;;
*mips64le*)
echo 'mips64le'
;;
*mips64*)
echo 'mips64'
;;
*mipsle*)
echo 'mipsle'
;;
*mips*)
echo 'mips'
;;
*s390x*)
echo 's390x'
;;
ppc64le)
echo 'ppc64le'
;;
ppc64)
echo 'ppc64'
;;
*)
return 1
;;
esac
register: return_machine
- name: Get the latest V2ray version and servers info
shell: >
curl -H "Accept: application/json" -H "User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:74.0) Gecko/20180101 Firefox/74.0" -s "https://api.github.com/repos/v2ray/v2ray-core/releases/latest" --connect-timeout 10| grep 'tag_name' | cut -d\" -f4
register: return_version
args:
warn: false
- set_fact:
latest_v2ray: "{{ return_version.stdout_lines[0] }}"
machine: "{{ return_machine.stdout }}"
rescue:
- name: "ERROR: Get the latest V2ray version and servers info. Please check your Network Connection and V2ray-core version"
set_fact:
install_error: true
when: v2ray_present and not install_error

- name: Download V2ray-core
block:
- name: "Download V2ray-core{{ latest_v2ray }} from jsdelivr"
get_url:
url: "https://cdn.jsdelivr.net/gh/v2ray/dist/v2ray-linux-{{ machine }}.zip"
dest: "{{ v2ray_download_path }}"
when: v2ray_download_from == "jsdelivr"
- name: "Download V2ray-core{{ latest_v2ray }} from Github"
get_url:
url: "https://github.com/v2ray/v2ray-core/releases/download/{{ latest_v2ray }}/v2ray-linux-{{ machine }}.zip"
dest: "{{ v2ray_download_path }}"
when: v2ray_download_from == "Github"
- name: "Download V2ray-core{{ latest_v2ray }} from {{ v2ray_download_from }}"
get_url:
url: "{{ v2ray_download_from }}"
dest: "{{ v2ray_download_path }}"
when: |
v2ray_download_from != "jsdelivr"
and
v2ray_download_from != "Github"
rescue:
- name: "ERROR: Download V2ray-core. Please check your Network Connection and V2ray-core version"
set_fact:
install_error: true
when: v2ray_present and not install_error


- name: Unarchive V2ray-core
block:
- name: Create unarchive V2ray-core directory
file:
path: "{{ v2ray_download_path }}/v2ray-linux-{{ machine }}"
state: directory
mode: 0755
- name: Unarchive V2ray-core
unarchive:
src: "{{ v2ray_download_path }}/v2ray-linux-{{ machine }}.zip"
dest: "{{ v2ray_download_path }}/v2ray-linux-{{ machine }}"
remote_src: true
rescue:
- name: "ERROR: Unarchive V2ray-core. Please check your platform"
set_fact:
install_error: true
when: v2ray_present and not install_error

- name: Install V2ray-core and Start V2ray-core
block:
- name: Create V2ray install directory
file:
path: "{{ item }}"
state: directory
mode: 0755
loop: "{{ v2ray_installed_dir }}"
- name: Copy binary file into directory
copy:
src: "{{ v2ray_download_path }}/v2ray-linux-{{ machine }}/{{ item.src }}"
dest: "{{ item.dest }}"
remote_src: true
mode: 0755
loop: "{{ v2ray_binary }}"
- name: Copy V2ray config and Start V2ray-core
copy:
src: "{{ v2ray_config }}"
dest: /etc/v2ray/config.json
mode: 0755
notify: Start V2ray Service
rescue:
- name: "ERROR: Install V2ray-core. Please check your permissions"
set_fact:
install_error: true
when: v2ray_present and not install_error


- name: Remove v2ray-core
block:
- name: Stop V2ray-core service
systemd:
name: v2ray.service
daemon_reload: true
enabled: false
state: stopped
ignore_errors: true
- name: Remove V2ray-core service
file:
path: /etc/systemd/system/v2ray.service
state: absent
- name: Remove v2ray-core file
file:
path: "{{ item }}"
state: absent
loop: "{{ v2ray_installed_dir }}"

when: not v2ray_present or install_error

- name: Check remove result
debug:
msg: Removed v2ray-core
when: not v2ray_present

- name: Check install result
debug:
msg: Install V2ray-core Failure
failed_when: yes
when: v2ray_present and install_error

- name: Check install result
debug:
msg: Install V2ray-core Successful
when: v2ray_present and not install_error

Default变量:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# You can download the latest V2ray-core from Github/jsdelivr/(https://yourself)
v2ray_download_from: "Github"
v2ray_download_path: "/tmp/v2ray"
v2ray_config: "files/v2ray.conf"

# user_control_boolean
v2ray_present: true

# Ansible Role Control vars (Don't change it!!!)
v2ray_installed_dir:
- /etc/v2ray
- /var/log/v2ray
- /usr/bin/v2ray
- "{{ v2ray_download_path }}"
v2ray_binary:
- src: geoip.dat
dest: /usr/bin/v2ray
- src: geosite.dat
dest: /usr/bin/v2ray
- src: v2ctl
dest: /usr/bin/v2ray
- src: v2ray
dest: /usr/bin/v2ray
- src: systemd/v2ray.service
dest: /etc/systemd/system