RHCE9学习指南 第33章 角色
33.1 了解角色
正常情况下,配置一个服务如apache时要做一系列的操作:安装、拷贝模板、启动服务等等操作。如果要在不同的机器上重复配置此服务,需要重新执行这些操作。
为了简化这些重复劳动,可以把安装、拷贝、启动服务等这些操作打包成一个整体,这个整体称角色,角色包括了的安装、拷贝、启动服务等操作,如图33-1所示。
图33-1 角色
如果在其他机器上如果想安装并配置apache,只要调用此角色即可,这样就可以实现一次劳动,永久回报的效果。
本质上一个角色就是一个文件夹,此文件夹名就是角色名,在此文件夹中包含一大堆文件,有的是用于执行各种模块,有的是用于拷贝到被管理主机的jinj2模板文件,有的是定义的变量文件。
为了防止文件太多太乱,则在此角色文件夹中再创建一个个的子目录用于存放不同的文件。例如,jinja2模板就放在templates目录中,普通的文件就放在files目录中,变量文件就放在vars中,执行模块的各个task放在tasks目录中等。角色目录中每个子目录的作用总结如表33-1所示。
表33-1 角色子目录的名称及作用
所有的角色都是放在一个目录中等待被调用,默认为ansible.cfg所在目录中的roles目录,如果要修改路径可以在ansible.cfg中用roles_path选项指定。
本章实验都在~lduan下的demo5下面练习,先把demo5创建出来并把ansible.cfg和hosts拷贝到demo5目录中,命令如下。
[lduan@server ~]$ mkdir demo5
[lduan@server ~]$ cp ansible.cfg hosts demo5/
[lduan@server ~]$ cd demo5/
[lduan@server demo5]$
修改ansible.cfg添加roles_path = ./roles,命令如下。
[lduan@server demo5]$ cat ansible.cfg
[defaults]
inventory = ./hosts
roles_path = ./roles
...输出...
[lduan@server demo5]$ mkdir roles
[lduan@server demo5]$
33.2 手把手创建一个角色
创建一个名称叫作web的角色,命令如下。
[lduan@server demo5]$ ansible-galaxy init roles/apache
- Role roles/apache was created successfully
[lduan@server demo5]$ ls roles/
apache
[lduan@server demo5]$
这里apache就是一个角色,看下apache下的内容。
[lduan@server demo5]$ ls roles/apache/
defaults files handlers meta README.md tasks templates tests vars
[lduan@server demo5]$
里面有不少目录,如前面介绍,这些目录分别用于存放不同的东西。
回顾在demo4目录中写好的hand-1.yaml的内容。
[lduan@server demo5]$ cat ../demo4/hand-1.yaml
---
- hosts: server2
vars:
myport: 808
tasks:
- name: task1安装httpd
yum: name=httpd state=installed
- name: task2拷贝配置文件
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: restart httpd1
- name: task3启动httpd服务
service: name=httpd state=started
handlers:
- name: restart httpd1
service: name=httpd state=restarted
- name: restart httpd2
service: name=httpd state=restarted
[lduan@server demo5]$
这个文件中包含了以下内容。
(1)vars中是定义变量的。
(2)tasks中的代码是正常要执行的。
(3)handler中的代码是被触发才会执行的。
(4)httpd.conf.j2是被引用的jinja2模板。
下面把这个yaml文件中的内容拆分放在apache角色不同的文件中,把这里的tasks下面的代码放在tasks目录中,把handlers下的代码放在handlers目录中等。
把这里tasks的内容写入roles/apache/tasks/main.yml中,内容如下。
[lduan@server demo5]$ cat roles/apache/tasks/main.yml
---
- name: task1安装httpd
yum: name=httpd state=installed
- name: task2拷贝配置文件
template: src=httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf
notify: restart httpd1
- name: task3启动httpd服务
service: name=httpd state=started
[lduan@server demo5]$
把这里handlers的内容写入roles/apache/handlers/main.yml中,内容如下。
[lduan@server demo5]$ cat roles/apache/handlers/main.yml
---
- name: restart httpd1
service: name=httpd state=restarted
- name: restart httpd2
service: name=httpd state=restarted
[lduan@server demo5]$
在task中用template拷贝的jinj2模板文件httpd.conf.j2拷贝到roles/apache/templates/中。
[lduan@server demo5]$ cp ../demo4/httpd.conf.j2 roles/apache/templates/
[lduan@server demo5]$ ls roles/apache/templates/
httpd.conf.j2
[lduan@server demo5]$
把变量myport写入roles/apache/vars/main.yml中,命令如下。
[lduan@server demo5]$ cat roles/apache/vars/main.yml
---
myport: 8080
[lduan@server demo5]$
这里把myport的值改为8080,原来的值是808,会使得httpd.conf.j2中的端口会发生变化,从而会触发handler。
也可以不在roles/apache/vars/main.yml中定义变量,而是在playbook中定义myport变量,如果在角色的vars中和playbook中都定义了myport变量,且变量值不同,则角色的vars中定义的变量生效。
下面查看下apache这个角色的结构,如下所示。
[lduan@server demo5]$ tree roles/apache/
roles/apache/
├── defaults
│ └── main.yml
├── files
├── handlers
│ └── main.yml
├── meta
│ └── main.yml
├── README.md
├── tasks
│ └── main.yml
├── templates
│ └── httpd.conf.j2
├── tests
│ ├── inventory
│ └── test.yml
└── vars
└── main.yml
8 directories, 9 files
[lduan@server demo5]$
这样,apache这个角色我们就算是最终写好了。
33.3 使用角色
角色写好之后,只要在playbook中直接调用角色即可,在playbook中roles下调用即可,调用的语法如下。
roles:
- name: 名称1
role: rolename1
- name: 名称2
role: rolename1
或者
roles:
- role: rolename1
- role: rolename1
下面写一个名称为test-role1.yaml的playbook,里面调用apache这个角色,命令如下。
[lduan@server demo5]$ cat test-role1.yaml
---
- hosts: server2
roles:
- role: apache
[lduan@server demo5]$
执行此playbook,结果如下。
[lduan@server demo5]$ ansible-navigator -m stdout run test-role1.yaml
PLAY [server2] ***************************************
TASK [Gathering Facts] ********************************
ok: [server2]
TASK [apache : task1安装httpd] ************************
ok: [server2]
TASK [apache : task2拷贝配置文件] *********************
changed: [server2]
TASK [apache : task3启动httpd服务] ********************
ok: [server2]
RUNNING HANDLER [apache : restart httpd1] **************
changed: [server2]
PLAY RECAP *****************************************
server2 : ok=5 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[lduan@server demo5]$
这里是运行test-role1.yaml之后的完整结果,可以看到执行的结果跟前面运行的结果一样。
变量在角色的defaults、vars中定义,也可以在playbook中定义,优先级的顺序是:角色的vars定义的变量→playbook中定义的变量→角色的defaults定义的变量。
所以,如果同一个变量如果同时在这三个地方都定义了,则角色的vars目录中定义的变量生效。
先把在roles/apache/vars/main.yml定义变量myport那行注释掉,这个变量将在playbook中定义,如下所示。
[lduan@server demo5]$ cat roles/apache/vars/main.yml
---
#myport: 8080
[lduan@server demo5]$
修改test-role1.yaml的内容如下。
[lduan@server demo5]$ cat test-role1.yaml
---
- hosts: server2
vars:
myport: 8080
roles:
- role: apache
[lduan@server demo5]$
运行这个playbook,命令如下。
[lduan@server demo5]$ ansible-navigator -m stdout run test-role1.yaml
PLAY [server2] ********************************************
TASK [Gathering Facts] **************************************
ok: [server2]
...输出...
[lduan@server demo5]$
到server2上验证httpd开启的端口是多少。
[root@server2 ~]# netstat -ntulp | grep httpd
tcp6 0 0 :::8080 :::* LISTEN 48719/httpd
[root@server2 ~]#
这里可以看到,httpd现在使用的端口是8080。
33.4 系统自带的角色
除我们自己创建角色外,系统中也包含了一些内置的角色。
在server上切换到root用户,然后安装软件包rhel-system-roles.noarch,命令如下。
[lduan@server demo5]$ sudo yum install rhel-system-roles -y
...输出...
已安装:
rhel-system-roles-1.16.2-1.el9_0.noarch
完毕!
[root@server ~]#
[root@server ~]# exit
注销
[lduan@server demo5]$
安装好这个软件包之后在/usr/share/ansible/roles目录中会有许多角色,如图33-2所示。
图33-2目录中的角色(显示部分)
下面演示rhel-system-roles.selinux这个角色,使用lduan用户把rhel-system-roles.selinux拷贝到demo5下的roles目录中,命令如下。
[lduan@server demo5]$ cp -r /usr/share/ansible/roles/rhel-system-roles.selinux/ roles/
[lduan@server demo5]$ ls roles/
apache rhel-system-roles.selinux
[lduan@server demo5]$
前面在讲解handlers时,为httpd配置了其他端口808,但是因为selinux的问题我们临时把selinux关闭了,如下所示。
[root@server2 ~]# getenforce
Permissive
[root@server2 ~]#
这里可以看到,server2上selinux的模式是Permissive。下面我们利用角色rhel-system-roles.selinux把server2的selinux改为Enforcing模式。
查看rhel-system-roles.selinux角色中默认的变量,命令如下。
[lduan@server demo5]$ cat roles/rhel-system-roles.selinux/defaults/main.yml
---
selinux_state: null
selinux_policy: null
...输出...
[lduan@server demo5]$
其中第一个变量是selinux_state,这个变量用于指定selinux模式的,默认值设置为了null。可以在playbook定义这个变量,覆盖这个默认变量的值,命令如下。
[lduan@server demo5]$ cat test-role2.yaml
---
- hosts: server2
vars:
selinux_state: enforcing
roles:
- role: rhel-system-roles.selinux
[lduan@server demo5]$
运行这个playbook,命令如下。
[lduan@server demo5]$ ansible-navigator -m stdout test-role2.yaml
...输出...
PLAY RECAP *********************************************
server2 : ok=7 changed=2 unreachable=0 failed=0 skipped=15 rescued=0 ignored=0
[lduan@server demo5]$
到server2上查看验证,命令如下。
[root@server2 ~]# getenforce
Enforcing
[root@server2 ~]#
这里已经把server2的selinux的模式改为了Enforcing。
33.5 修改端口上下文
在介绍handler时,可以通过变量myport随意修改端口。但是端口上下文不对,那么httpd是启动不起来的,所以当初把server2上的selinux临时关闭了。
下面介绍如何使用角色rhel-system-roles.selinux修改端口上下文。
查看角色rhel-system-roles.selinux中默认的变量,命令如下。
[lduan@server demo5]$ cat roles/rhel-system-roles.selinux/defaults/main.yml
---
selinux_state: null
selinux_policy: null
...输出...
selinux_ports: []
...输出...
[lduan@server demo5]$
这里变量selinux_ports是一个列表,里面的元素需要定义多个变量,但是变量名是什么我们现在还不清楚。
用vim编辑打开roles/rhel-system-roles.selinux/tasks/main.yml,在大概116行中是用于定义端口上下文的,命令如下。
[lduan@server demo5]$ vim roles/rhel-system-roles.selinux/tasks/main.yml
- name: Set an SELinux label on a port
seport:
ports: "{{ item.ports }}"
proto: "{{ item.proto | default('tcp') }}"
setype: "{{ item.setype }}"
state: "{{ item.state | default('present') }}"
with_items: "{{ selinux_ports }}"
这里只截取部分代码,可以看到这里循环列表selinux_ports中的4个变量。其中proto和state都有默认值,ports和setype没有默认值,所以我们在定义列表selinux_ports时至少要列表的元素中定义ports和setype这两个变量。
修改test-role1.yaml的内容如下。
[lduan@server demo5]$ cat test-role1.yaml
---
- hosts: server2
vars:
myport: 808
selinux_ports:
- ports: "{{myport}}"
setype: http_port_t
roles:
- role: rhel-system-roles.selinux
- role: apache
[lduan@server demo5]$
这里定义了一个变量myport的值为808,然后定义一个列表selinux_ports。这个列表中只有一个元素,元素中有两个变量ports和setype。其中ports这个变量引用myport的值,记得要用双引号引起来,setype的值被设置为了http_port_t。
运行这个playbook,命令如下。
[lduan@server demo5]$ansible-navigator -m stdout test-role1.yaml
...输出...
[lduan@server demo5]$
然后到server2上检查httpd所使用的端口,命令如下。
[root@server2 ~]# netstat -ntulp | grep :808
tcp6 0 0 :::808 :::* LISTEN 46936/httpd
[root@server2 ~]#
可以看到,httpd此时使用的是808端口。
33.6 使用ansible Galaxy安装角色
ansible Galaxy是ansible的官方社区中心,这里存有大量的ansible所能用到的角色。在浏览器中打开这个站点(https://galaxy.ansible.com)之后,单击左侧"角色"后面的">",然后点击"角色"首页如图33-3所示。
图33-3 官方社区首页
进入搜索页面,如图33-4所示。
图33-4 搜索页面
在搜索框中输入我们要查找的角色名,例如,输入“vsftpd”之后按【Enter】键,会看到一系列和vsftpd相关的角色,如图33-5所示。
图33-5 搜索结果
这里单击第一个,可以看到安装方法,复制这个命令即可把这个角色安装在机器上。如图33-6所示。
图33-6 复制命令
在从国内访问国外这点的速度会有些慢,所以为了练习方便可以使用如下链接的角色:ftp://ftp.rhce.cc/auto/web.tar.gz。
下面我们安装这个角色,命令如下。
[lduan@server demo5]$ ansible-galaxy install ftp://ftp.rhce.cc/auto/web.tar.gz
- downloading role from ftp://ftp.rhce.cc/auto/web.tar.gz
- extracting web to /home/lduan/demo5/roles/web
- web was installed successfully
[lduan@server demo5]$
这样就把这个角色安装到当前目录中的roles目录中去了,如下所示。
[lduan@server demo5]$ ls roles/
apache rhel-system-roles.selinux web
[lduan@server demo5]$
这里多的一个web文件就是一个名称叫作web的角色,如果要安装到其他目录,可以加"-p /path"指定安装目录,例如,安装在/opt目录中,可以用如下命令。
ansible-galaxy install ftp://ftp.rhce.cc/auto/web.tar.gz -p /opt
除这种安装方式外,还可以把要安装的角色写入一个yaml文件中。
下面创建一个aa.yaml,内容如下。
[lduan@server demo5]$ cat aa.yaml
---
- src: ftp://ftp.rhce.cc/auto/web.tar.gz
name: webx
[lduan@server demo5]$
这里src指定了角色所在的URL,name指定是在本地安装好之后角色名称是webx。
下面开始利用aa.yaml这个文件安装角色,命令如下。
[lduan@server demo5]$ ansible-galaxy install -r aa.yaml -p roles/
- downloading role from ftp://ftp.rhce.cc/auto/web.tar.gz
- extracting webx to /home/lduan/demo5/roles/webx
- webx was installed successfully
[lduan@server demo5]$
这里显示安装成功了,这里-p roles可以不写,不写就是当前目录下roles目录。查看roles中的内容,命令如下。
[lduan@server demo5]$ ls roles/
apache rhel-system-roles.selinux web webx
[lduan@server demo5]$
这里可以看到,已经安装成功了,安装的角色被命名为了webx。
33.7 使用ansible Galaxy安装collection
在前面讲了很多的模块并没有集成在ansible-core里,而是通过模块的方式来安装,这个模块就叫做collection(集合)。要查看系统里已经安装了多少collection,可以通过如下命令来查看:
ansible-navigator collections
然后以【ctrl+c】组合键结束。
如果想额外安装collection的话,我们也可以到ansible Galaxy里找到我们所需要的collection。点击左侧的集合后面的">",然后点击“集合”。这里我们就选择安装第一个,myc的这个collection,如图33-7。
图33-7 官方社区首页
点击进去之后看到的界面如图33-8所示。
图33-8 要安装的集合
这里提示我们可以通过命令ansible-galaxy collection install shavitavizemer.myc安装,也可以单独下载tarball包,我们这里把tarball下载下来上传到server上。
因为在ansible.cfg里指定了collection安装路径,所以这里这里先把mycollection创建出来。
[lduan@server demo5]$ mkdir ./mycollection/
[lduan@server demo5]$
编写aa.yaml,内容如下
[lduan@server demo5]$ cat aa.yaml
---
collections:
- name: ./shavitavizemer-myc-1.0.0.tar.gz
[lduan@server demo5]$
这里通过--name指定了tarball的路径,下面开始安装,这里-r指定aa.yaml的路径,-p指定collection安装到哪里。
[lduan@server demo5]$ ansible-galaxy collection install -r aa.yaml -p mycollection/
Starting galaxy collection install process
...输出...
shavitavizemer.myc:1.0.0 was installed successfully
[lduan@server demo5]$
从这里可以看到,这个collection已经安装成功了。
作业:
下面的练习均在/home/lduan/demo5里练习。
作业1:以lduan用户登陆到server,进入demo5目录(/home/lduan/demo5)里,请判断当前已经安装了哪些角色。
答案:
通过命令ansible-galaxy list可以获取当前目录下安装了哪些角色,命令如下。
[lduan@server demo5]$ ansible-galaxy list
# /home/lduan/demo5/roles
- apache, (unknown version)
- rhel-system-roles.selinux, (unknown version)
- web, (unknown version)
- webx, (unknown version)
- role1, (unknown version)
[lduan@server demo5]$
可以看到这里已经安装了apache、rhel-system-roles.selinux、web、webx和role1这些角色。
作业2:从ftp://ftp.rhce.cc/auto/vsftpd-test.tar.gz下载并安装角色,安装在/home/lduan/demo5/roles里,安装之后角色的名字为vsftpd。
答案:
创建一个yaml文件,名字随便取,这里取名为xx.yaml,内容如下。
[lduan@server demo5]$ cat xx.yaml
---
- src: ftp://ftp.rhce.cc/auto/vsftpd-test.tar.gz
name: vsftpd
[lduan@server demo5]$
开始安装角色,用-r指定刚才写的yaml文件,-p选项指定安装路径,命令如下。
[lduan@server demo5]$ ansible-galaxy install -r xx.yaml -p roles/
- downloading role from ftp://ftp.rhce.cc/auto/vsftpd-test.tar.gz
- extracting vsftpd to /home/lduan/demo5/roles/vsftpd
- vsftpd was installed successfully
[lduan@server demo5]$
作业3:写一个名字为install-vsftpd.yaml的playbook,调用作业2所创建的角色vsftpd,要求此角色仅仅在server2上执行。
答案
编写install-vsftpd.yaml内容如下。
[lduan@server demo5]$ cat install-vsftpd.yaml
---
- hosts: server2
roles:
- role: vsftpd
[lduan@server demo5]$