一、描述角色结构
1. 利用角色构造ansible playbook
角色(roles)是指某一段写好的通用的playbook代码。
通用简单角色:所有的角色,不管在哪里做都是一样的,不会发生改变。
不通用的用户数据、项目数据、业务数据,是针对不同用户,项目和业务的。
Ansible角色提供了一种方法,让用户能以通用的方式更加轻松地重复利用Ansible代码。我们可以在标准化目录结构中打包所有任务、变量、文件、模板,以及调配基础架构或部署应用所需的其他资源。只需通过复制相关的目录,将角色从一个项目复制到另一个项目。然后,只需从一个play调用该角色就能执行它。
Ansible角色具有下列优点:
角色可以分组内容,从而与他人轻松共享代码
可以编写角色来定义系统类型的基本要素:Web服务器、数据库服务器、Git存储库,或满足其他用途
角色使得较大型项目更容易管理
角色可以由不同的管理员并行开发(各自开发各自的,要用的时候包含进来或者列出来就可以了)
注意:除了自行编写、使用、重用和共享角色外,还可以从其他来源获取角色。
一些角色已包含在rhel-system-roles软件包中,用户也可以从Ansible Galaxy网站获取由社区提供支持的许多角色
2. 检查ansible角色结构
Ansible角色由子目录和文件的标准化结构定义。顶级目录定义角色本身的名称。文件整理到子目录中,子目录按照各个文件在角色中的用途进行命名,如tasks和handlers。files和templates子目录中包含由其他YAML文件中的任务引用的文件。
1site.yml webservers.yml fooservers.yml roles/ //角色 common/ //通用的角色 tasks/ //任务 handlers/ //处理程序 files/ //文件 templates/ //模板 vars/ //变量 defaults/ //默认的 meta/ webservers/ //部署网站的角色 tasks/ defaults/ meta/
[root@ansible roles]# tree user.example/
user.example/ //角色的名字
├── defaults //表示默认值的变量,没穿新的参数才会用到,传了新的参数就会被覆盖
│ └── main.yml //变量文件,写各种变量的默认值。main:主程序
├── files //放安装包、配置文件、脚本之类的
├── handlers //放处理程序
│ └── main.yml //写处理程序
├── meta
│ └── main.yml
├── README.md //说明文档
├── tasks //任务
│ └── main.yml //任务文件
├── templates //模板文件,带上.j2后缀
├── tests
│ ├── inventory
│ └── test.yml
└── vars //变量
└── main.yml //变量文件,变量:变量的值
Ansible角色子目录
子目录 | 功能 |
---|---|
defaults | 此目录中的main.yml文件包含角色变量的默认值,使用角色时可以覆盖这些默认值。 这些变量的优先级较低,应该在play中更改和自定义。 |
files | 此目录包含由角色任务引用的静态文件。 |
handlers | 此目录中的main.yml文件包含角色的处理程序定义。 |
meta | 此目录中的main.yml文件包含与角色相关的信息,如作者、许可证、平台和可选的角色依赖项。 |
tasks | 此目录中的main.yml文件包含角色的任务定义。 |
templates | 此目录包含由角色任务引用的Jinja2模板。 |
tests | 此目录可以包含清单和名为test.yml的playbook,可用于测试角色。 |
vars | 此目录中的main.yml文件定义角色的变量值。这些变量通常用于角色内部用途。 这些变量的优先级较高,在playbook中使用时不应更改。 |
并非每个角色都拥有所有这些目录。
并非每个角色都拥有所有这些目录。
3. 定义变量和默认值
角色变量通过在角色目录层次结构中创建含有键值对的vars/main.yml文件来定义。与其他变量一样,这些角色变量在角色YAML文件中引用:{{ VAR_NAME }}。这些变量具有较高的优先级,无法被清单变量覆盖。这些变量旨在供角色的内部功能使用。
默认变量允许为可在play中使用的变量设置默认值,以配置角色或自定义其行为。它们通过在角色目录层次结构中创建含有键值对的defaults/main.yml文件来定义。默认变量具有任何可用变量中最低的优先级。它们很容易被包括清单变量在内的任何其他变量覆盖。这些变量旨在让用户在编写使用该角色的play时可以准确地自定义或控制它将要执行的操作。它们可用于向角色提供所需的信息,以正确地配置或部署某些对象。
在vars/main.yml或defaults/main.yml中定义具体的变量,但不要在两者中都定义。有意要覆盖变量的值时,应使用默认变量。
注意:
角色不应该包含特定于站点的数据(例如网站的内容,网站的用户和密码,数据库的ip、密码、用户)。它们绝对不应包含任何机密,如密码或私钥。
这是因为角色应该是通用的,可以重复利用并自由共享。特定于站点的详细信息不应硬编码(写死)到角色中。角色代码不可改
机密应当通过其他途径提供给角色。这是用户可能要在调用角色时设置角色变量的一个原因。play中设置的角色变量可以提供机密,或指向含有该机密的Ansible Vault加密文件。
4. 在playbook中使用ansible角色
对于每个指定的角色,角色任务、角色处理程序、角色变量和角色依赖项将按照顺序导入到playbook中。角色中的任何copy、script、template或include_tasks/import_tasks任务都可引用角色中相关的文件、模板或任务文件,且无需相对或绝对路径名称。Ansible将分别在角色的files、templates或tasks子目录中寻找它们。
如果使用roles部分将角色导入到play中,这些角色会在用户为该play定义的任何任务之前运行。
1.5 控制执行顺序
对于playbook中的每个play,任务按照任务列表中的顺序来执行。执行完所有任务后,将执行任务通知的处理程序。
在角色添加到play中后,角色任务将添加到任务列表的开头。如果play中包含第二个角色,其任务列表添加到第一个角色之后。
角色处理程序添加到play中的方式与角色任务添加到play中相同。每个play定义一个处理程序列表。角色处理程序先添加到处理程序列表,后跟play的handlers部分中定义的任何处理程序。
在某些情形中,可能需要在角色之前执行一些play任务。若要支持这样的情形,可以为play配置pre_tasks部分。列在此部分中的所有任务将在执行任何角色之前执行。如果这些任务中有任何一个通知了处理程序,则这些处理程序任务也在角色或普通任务之前执行。
此外,play也支持post_tasks关键字。这些任务在play的普通任务和它们通知的任何处理程序运行之后执行。
以下play演示了一个带有pre_tasks、roles、tasks、post_tasks和handlers的示例。一个play中通常不会同时包含所有这些部分。
- name: Play to illustrate order of execution
hosts: remote.example.com
pre_tasks:
- debug:
msg: 'pre-task'
notify: my handler
roles:
- role1
tasks:
- debug:
msg: 'first task'
notify: my handler
post_tasks:
- debug:
msg: 'post-task'
notify: my handler
handlers:
- name: my handler
debug:
msg: Running my handler
在上例中,每个部分中都执行debug任务来通知my handler处理程序。my handler任务执行了三次:
在执行了所有pre_tasks任务后
在执行了所有角色任务和tasks部分中的任务后
在执行了所有post_tasks后
除了将角色包含在play的roles部分中外,也可以使用普通任务将角色添加到play中。使用include_role模块可以动态包含角色,使用import_role模块则可静态导入角色。
以下playbook演示了如何通过include_role模块来利用任务包含角色。
- name: Execute a role as a task
hosts: remote.example.com
tasks:
- name: A normal task
debug:
msg: 'first task'
- name: A task to include role2 here
include_role: role2
2.1 红帽企业Linux系统角色
自RHEL7.4开始,操作系统随附了多个Ansible角色,作为rhel-system-roles软件包的一部分。在RHEL8中,该软件包可以从AppStream中获取。以下是每个角色的简要描述:
RHEL系统角色
名称 | 状态 | 角色描述 |
---|---|---|
rhel-system-roles.kdump | 全面支持 | 配置kdump崩溃恢复服务 |
rhel-system-roles.network | 全面支持 | 配置网络接口 |
rhel-system-roles.selinux | 全面支持 | 配置和管理SELinux自定义, 包括SELinux模式、文件和端口上下文、 布尔值设置以及SELinux用户 |
rhel-system-roles.timesync | 全面支持 | 使用网络时间协议或精确时间协议配置时间同步 |
rhel-system-roles.postfix | 技术预览 | 使用Postfix服务将每个主机配置为邮件传输代理 |
rhel-system-roles.firewall | 开发中 | 配置主机的防火墙 |
rhel-system-roles.tuned | 开发中 | 配置tuned服务,以调优系统性能 |
系统角色的目的是在多个版本之间标准化红帽企业Linux子系统的配置。使用系统角色来配置版本6.10及以上的任何红帽企业Linux主机。
2.2 简化配置管理
举例而言,RHEL7的建议时间同步服务为chronyd服务。但在RHEL6中,建议的服务为ntpd服务。在混合了RHEL6和7主机的环境中,管理员必须管理这两个服务的配置文件。
借助RHEL系统角色,管理员不再需要维护这两个服务的配置文件。管理员可以使用rhel-system-roles.timesync角色来配置RHEL6和7主机的时间同步。一个包含角色变量的简化YAML文件可以为这两种类型的主机定义时间同步配置。
2.3 安装RHEL系统角色
RHEL系统角色由rhel-system-roles软件包提供,该软件包可从AppStream流获取。在Ansible控制节点上安装该软件包。
安装RHEL系统角色
yum -y install rhel-system-roles
ls -l /usr/share/ansible/roles/
[root@localhost roles]# ls
linux-system-roles.certificate linux-system-roles.ssh rhel-system-roles.metrics
linux-system-roles.crypto_policies linux-system-roles.sshd rhel-system-roles.nbde_client
linux-system-roles.ha_cluster linux-system-roles.storage rhel-system-roles.nbde_server
linux-system-roles.kdump linux-system-roles.timesync rhel-system-roles.network
linux-system-roles.kernel_settings linux-system-roles.tlog rhel-system-roles.postfix
linux-system-roles.logging linux-system-roles.vpn rhel-system-roles.selinux
linux-system-roles.metrics rhel-system-roles.certificate rhel-system-roles.ssh
linux-system-roles.nbde_client rhel-system-roles.crypto_policies rhel-system-roles.sshd
linux-system-roles.nbde_server rhel-system-roles.ha_cluster rhel-system-roles.storage
linux-system-roles.network rhel-system-roles.kdump rhel-system-roles.timesync
linux-system-roles.postfix rhel-system-roles.kernel_settings rhel-system-roles.tlog
linux-system-roles.selinux rhel-system-roles.logging rhel-system-roles.vpn
2.4 访问RHEL系统角色的文档
安装后,RHEL系统角色的文档位于/usr/share/doc/rhel-system-roles-/目录中。文档按照子系统整理到子目录中:
[root@localhost playbook]# mkdir roles/
[root@localhost playbook]# ls
httpd roles runtime
[root@localhost playbook]# cd roles/
[root@localhost roles]# cp -a /usr/share/ansible/roles/rhel-system-roles.timesync timesync
[root@localhost roles]# ls
timesync
[root@localhost roles]# ll
total 4
drwxr-xr-x. 10 root root 4096 Jun 14 22:45 timesync
安装后,RHEL系统角色的文档位于**/usr/share/doc/rhel-system-roles-/目录中。
每个角色的文档目录均包含一个README.md**文件。README.md文件含有角色的说明,以及角色用法信息。
README.md文件也会说明影响角色行为的角色变量。通常,README.md文件中含有一个playbook代码片段,用于演示常见配置场景的变量设置。
部分角色文档目录中含有示例playbook。首次使用某一角色时,请查看文档目录中的任何额外示例playbook。
RHEL系统角色的角色文档与Linux系统角色的文档相匹配。使用Web浏览器来访问位于Ansible Galaxy网站https://galaxy.ansible.com/docs/上的角色文档。
5. 时间同步角色示例
假设需要在服务器上配置NTP时间同步。我们可以自行编写自动化来执行每一个必要的任务。但是,RHEL系统角色中有一个可以执行此操作角色,那就是rhel-system-roles.timesync。
该角色的详细记录位于/usr/share/doc/rhel-system-roles/timesync目录下的README.md中。此文件说明了影响角色行为的所有变量,还包含演示了不同时间同步配置的三个playbook代码片段。
为了手动配置NTP服务器,该角色具有一个名为timesync_ntp_servers的变量。此变量取一个要使用的NTP服务器的列表作为值。列表中的每一项均由一个或多个属性构成。两个关键属性如下:
timesync_ntp_servers属性
根据这一信息,以下示例play使用rhel-system-roles.timesync角色将受管主机配置为利用快速初始同步从三个NTP服务器获取时间。此外,还添加了一个任务,以使用timezone模块将主机的时区设为UTC。
[root@localhost roles]# cat tiem.yml
---
- hosts: all
vars:
timesync_ntp_servers:
- hostname: time1.aliyun.com
iburst: yes
roles:
- timesync
[root@localhost roles]# ansible-playbook -C tiem.yml
PLAY [all] **********************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************
ok: [web01.example.com]
TASK [timesync : Set version specific variables] ********************************************************************
ok: [web01.example.com]
TASK [timesync : Populate service facts] ****************************************************************************
ok: [web01.example.com]
TASK [Set variable `timesync_services` with filtered uniq service names] ********************************************
ok: [web01.example.com]
TASK [Check that variable 'timesync_services' is defined] ***********************************************************
ok: [web01.example.com] => {
"changed": false,
"msg": "All assertions passed"
}
TASK [timesync : Check if only NTP is needed] ***********************************************************************
ok: [web01.example.com]
此示例在play的vars部分中设置角色变量,但更好的做法可能是将它们配置为主机或主机组的清单变量。
例如一个playbook项目具有以下结构:
[root@localhost playbook-project]# tree
.
├── ansible.cfg
├── group_vars
│ └── servers
│ └── timesync.yml
├── inventory
└── timesync_playbook.yml
timesync.yml定义时间同步变量,覆盖清单中servers组内主机的角色默认值。此文件看起来类似于:
timesync_ntp_servers:
- hostname: 0.rhel.pool.ntp.org
iburst: yes
- hostname: 1.rhel.pool.ntp.org
iburst: yes
- hostname: 2.rhel.pool.ntp.org
iburst: yes
timezone: UTC
timesync_playbook.yml的内容简化为:
- name: Time Synchronization Play
hosts: servers
roles:
- rhel-system-roles.timesync
tasks:
- name: Set timezone
timezone:
name: "{{ timezone }}"
该结构可清楚地分隔角色、playbook代码和配置设置。Playbook代码简单易读,应该不需要复杂的重构。角色内容由红帽进行维护并提供支持。所有设置都以清单变量的形式进行处理。
该结构还支持动态的异构环境。具有新的时间同步要求的主机可能会放置到新的主机组中。相应的变量在YAML文件中定义,并放置到相应的group_vars(或host_vars)子目录中。
2.6 SELINUX角色示例
rhel-system-roles.selinux角色可以简化SELinux配置设置的管理。它通过利用SELinux相关的Ansible模块来实施。与自行编写任务相比,使用此角色的优势是它能让用户摆脱编写这些任务的职责。取而代之,用户将为角色提供变量以对其进行配置,且角色中维护的代码将确保应用用户需要的SELinux配置。
此角色可以执行的任务包括:
- 设置enforcing或permissive模式
- 对文件系统层次结构的各部分运行restorecon
- 设置SELinux布尔值
- 永久设置SELinux文件上下文
- 设置SELinux用户映射
2.7 调用SELinux角色
有时候,SELinux角色必须确保重新引导受管主机,以便能够完整应用其更改。但是,它本身从不会重新引导主机。如此一来,用户便可以控制重新引导的处理方式。
其工作方式为,该角色将一个布尔值变量selinux_reboot_required设为True,如果需要重新引导,则失败。你可以使用block/rescure结构来从失败中恢复,具体操作为:如果该变量未设为true,则让play失败,如果值是true,则重新引导受管主机并重新运行该角色。Play中的块看起来应该类似于:
- name: Apply SELinux role
block:
- include_role:
name: rhel-system-roles.selinux
rescue:
- name: Check for failure for other reasons than required reboot
fail:
when: not selinux_reboot_required
- name: Restart managed host
reboot:
- name: Reapply SELinux role to complete changes
include_role:
name: rhel-system-roles.selinux
2.8 配置SELinux角色
用于配置rhel-system-roles.selinux角色的变量的详细记录位于其README.md文件中。以下示例演示了使用此角色的一些方法。
selinux_state变量设置SELinux的运行模式。它可以设为enforcing、permissive或disabled。如果未设置,则不更改模式。
[root@localhost selinux]# cp -a /usr/share/ansible/roles/rhel-system-roles.selinux .
[root@localhost roles]# cat test.yml
---
- hosts: all
vars:
selinux_state: disabled
tasks:
- name: selinux
block:
- include_role:
name: selinux
rescue:
- name: if failed reason require reboot
fail:
when: not selinux_reboot_required
- name: config selinux
include_role:
name: selinux
[root@localhost ~]# cat /etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
//重启一下执行
[root@apache ~]# getenforce
Enforcing
配置SELinux角色
selinux_ports变量取应当具有特定SELinux类型的端口的列表作为值。
[root@ansible playbook]# cp test.yl httpd.yml
[root@ansible files]# scp 192.168.80.13:/etc/httpd/conf/httpd.conf httpd.conf.j2
httpd.conf 100% 12KB 11.8MB/s 00:00
[root@ansible files]# vim httpd.conf.j2
44 #Listen 12.34.56.78:80
45 Listen {{ PORT }}
[root@apache ~]# semanage port -l|grep http //确保没有82端口,如果有给它删掉
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
pegasus_https_port_t tcp 5989
[root@ansible playbook]# cat httpd.yml
---
- hosts: apache
vars:
selinux_state: enforcing
selinux_ports: //加入规则
- ports: '82'
setype: 'http_port_t'
proto: 'tcp'
state: 'present'
PORT: 82 //通过传变量的方式
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: config httpd
template:
src: files/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
- name: selinux for httpd
block:
- include_role:
name: selinux
rescue:
- name: if failed reason require reboot
fail:
when: not selinux_reboot_required
- name: reboot
reboot:
- name: config selinux
include_role:
name: selinux
- name: service for httpd
service:
name: httpd
state: started
enabled: yes
[root@localhost roles]# ansible-playbook httpd.ym
[root@localhost ~]# semanage port -l|grep http
http_cache_port_t tcp 8080, 8118, 8123, 10001-10010
http_cache_port_t udp 3130
http_port_t tcp 82, 80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t tcp 5988
pegasus_https_port_t tcp 5989
[root@localhost ~]# ss -ant
LISTEN 0 128 *:82 *:*