大项目
一、利用主机模式选择主机
1、引用清单主机
主机模式用于指定要作为play或临时命令的目标的主机。在最简单的形式中,清单中受管主机或主机组的名称就是指定该主机或主机组的主机模式。
在play
中,hosts
指定要针对其运行play的受管主机。对于临时命令,以命令行参数形式将主机模式提供给ansible命令。
示例:
[root@master project] ~]# cat myinventory
web.example.com
data.example.com
[lab]
labhost1.example.com
labhost2.example.com
[test]
test1.example.com
test2.example.com
[datacenter1]
labhost1.example.com
test1.example.com
[datacenter2]
labhost2.example.com
test2.example.com
[datacenter:children]
datacenter1
datacenter2
[new]
192.168.129.135
192.168.129.137
要演示如何解析主机模式,我们将执行Ansible Playbook的playbook.yml
,使用不同的主机模式来以此示例清单中受管主机的不同子集作为目标。
2、受管主机
最基本的主机模式是单一受管主机名称列在清单中。这将指定该主机是清单中ansible命令要执行操作的唯一主机。
在该playbook运行时,第一个Gathering Facts任务应在与主机模式匹配的所有受管主机上运行。此任务期间的故障可能导致受管主机从play中移除。
如果清单中明确列出了IP地址,而不是主机名,则可以将其用作主机模式。如果IP地址未列在清单中,我们就无法用它来指定主机,即使该IP地址会在DNS中解析到这个主机名。
以下示例演示了如何使用主机模式来引用清单中包含的IP地址。
[root@master project] ~]# vim playbook.yml
---
- hosts: 192.168.129.135
[root@master project] ~]# ansible-playbook playbook.yml
PLAY [192.168.129.135] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.135]
PLAY RECAP *********************************************************************************************************************************
192.168.129.135 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
注意:
在清单中通过IP地址引用受管主机存在一个问题,那就是难以记住play或临时命令所针对的主机使用了哪个IP地址。但是,如果没有可解析的主机名,我们可能必须按IP地址指定主机以进行连接。
可以通过设置ansible_host
主机变量,在清单中将某一别名指向特定的IP地址。例如,你的清单中可以有一个名为dummy.example
的主机,然后通过创建含有以下主机变量的host_vars/dummy.example
文件,将使用该名称的连接指向IP地址192.168.129.135:
ansible_host: 192.168.129.135
3、使用组指定主机
- 当组名称用作主机模式时,它指定Ansible将对
属于该组的成员的主机执行操作
。
---
- hosts: lab
- 有一个名为all的特别组,它匹配清单中的
所有受管主机
。
---
- hosts: all
- 名为ungrouped的特别组,它包括清单中
不属于任何其他组
的所有受管主机
---
- hosts: ungrouped
4、使用通配符匹配主机
若要达成与all主机模式相同的目标,另一种方法是使用*
通配符,它将匹配任意字符串。如果主机模式只是带引号的星号,则清单中的所有主机都将匹配。
---
- hosts: '*'
重要:
- 一些在主机模式中使用的字符对shell也有意义。通过ansible使用主机模式从命令行运行临时命令时,这可能会有问题。建议大家在命令行中使用单引号括起使用的主机模式,防止它们被
shell
意外扩展。
类似的,如果在Ansible Playbook
中使用了任何特殊通配符或列表字符,必须将主机模式放在单引号里,确保能够正确解析主机模式。
---
- hosts: '!test1.example.com,development'
- 也可使用
*
字符匹配包含特定子字符串的受管主机或组。
例如,以下通配符主机模式匹配以.example.com
结尾的所有清单名称:
---
- hosts: '*.example.com'
- 以下示例使用通配符主机模式来匹配开头为
192.168.129.
的主机或主机组的名称:
---
- hosts: '192.168.129.*'
- 以下示例使用通配符主机模式来匹配开头为
datacenter
的主机或主机组的名称。(不建议使用,最好是具体一点)
---
- hosts: 'datacenter*'
重要:
- 通配符主机模式匹配所有清单名称、主机和主机组。它们不区别名称是DNS名、IP地址还是组,这可能会导致一些意外的匹配。
例如,根据示例清单,比较上一示例中指定datacenter*
主机模式的结果和data*
主机模式的结果:(不建议使用,具体一点)
---
- hosts: 'data*'
5、列表
可以通过逻辑列表来引用清单中的多个条目。主机模式的逗号分隔列表匹配符合任何这些主机模式的所有主机。
- 如果提供受管主机的
逗号分隔
列表,则所有这些受管主机
都将是目标:
---
- hosts: labhost1.example.com,test2.example.com,192.168.129.135
- 如果提供组的
逗号分隔
列表,则属于任何这些组的所有主机
都将是目标:
---
- hosts: lab,datacenter1
- 也可以混合使用受管主机、主机组和通配符,如下所示:
---
- hosts: 'lab,data*,192.168.129.135'
注意:
也可以用冒号(:)
取代逗号。不过,逗号是首选的分隔符,特别是将IPv6地址用作受管主机名称时。
如果列表中的某一项以与符号(&)
开头,则主机必须与该项匹配才能匹配主机模式。它的工作方式类似于逻辑AND。
例如,根据我们的示例清单,以下主机模式将匹配lab
组中同时也属于datacenter1
组的计算机:
---
- hosts: lab,&datacenter1
我们也可以通过主机模式&lab,datacenter1
或datacenter
,&lab
指定datacenter1
组中的计算机只有在同时也属于lab
组时才匹配。
通过在主机模式的前面使用感叹号(!)
表示从列表中排除匹配某一模式的主机
。它的工作方式类似于逻辑NOT。
- 根据示例清单,以下示例匹配
datacenter
组中定义的所有主机,但test2.example.com
除外:
---
- hosts: datacenter,!test2.example.com
也可以使用模式**’!test2.example.com,datacenter’**来获得相同的结果。
- 最后一个示例演示了使用匹配测试清单中的
所有主机的主机模式
,datacenter1
组中的受管主机除外。
---
- hosts: all,!datacenter1
二、管理清单
1 、管理多个清单
Ansible支持在同一运行中使用多个清单。如果清单的位置是一个目录(不论是由-i选项设置的、是inventory
参数的值,还是以某种其他方式设置的),将组合该目录中包含的所有清单文件(不论是静态还是动态)来确定清单。该目录中的可执行文件将用于检索动态清单,其他文件则被用作静态清单。
- 清单文件不应依赖于其他清单文件或脚本来解析。例如,如果静态清单文件指定某一个组应当是另一个组的子级,则它也需要具有该组的占位符条目,即使该组的所有成员都来自动态清单。
[cloud-east]
[servers]
test.demo.example.com
[servers:children]
cloud-east
这可以确保不论清单文件以什么顺序解析,它们在内部都一致。
注意:
清单文件的解析顺序不是由文档指定的
。目前,如果存在多个清单文件,它们会按照字母顺序进行解析
。如果一个清单源依赖于另一个清单源的信息,则它们的加载顺序可能会确定清单文件是按预期工作还是引发错误。因此,务必要确保所有文件都自相一致,从而避免意外的错误。
Ansible会忽略
清单目录中以特定后缀结尾的文件。这可以通过在Ansible配置文件中的inventory_ignore_extensions
指令来控制。有关更多信息,请参阅Ansible官方文档。
三、配置并行
1、使用分叉在ansible中配置并行
当Ansible处理playbook时,会按顺序运行每个play。确定play的主机列表之后,Ansible将按顺序运行每个任务。通常,所有主机必须在任何主机在play中启动下一个任务之前成功完成任务。
理论上,Ansible可以同时连接到play中的所有主机以执行每项任务。这非常适用于小型主机列表。但如果该play以数百台主机为目标,则可能会给控制节点带来沉重负担。
- Ansible所进行的最大同时连接数由Ansible配置文件中的forks参数控制。默认情况下设为5,这可通过以下方式之一来验证。
[root@master project]# grep forks /etc/ansible/ansible.cfg
#forks = 5
[root@master project]# ansible-config dump|grep -i forks
DEFAULT_FORKS(default) = 5
[root@master project]# ansible-config list|grep -i forks
DEFAULT_FORKS:
description: Maximum number of forks Ansible will use to execute tasks on target
- {name: ANSIBLE_FORKS}
- {key: forks, section: defaults}
name: Number of task forks
例如,假设Ansible控制节点配置了5个forks的默认值,并且play具有10个受管主机
。Ansible将在前5个受管主机
上执行play中的第一个任务,然后在其他
5个受管主机上对第一个任务执行第二轮。在所有受管主机上执行第一个任务后,Ansible将继续一次在5受管主机的组中的所有受管主机上执行下一个任务。Ansible将依次对每个任务执行此操作,直到play结束。
forks的默认值设置得非常保守。如果你的控制节点正在管理Linux主机,则大多数任务将在受管主机上运行,并且控制节点的负载较少。在这种情况下,通常可以将forks的值设置得更高,可能接近100,然后性能就会提高。
如果playbook在控制节点上运行很多代码,则应明智地提高forks限值。如果使用Ansible管理网络路由器和交换机,则大多数模块在控制节点上运行而不是在网络设备上运行。由于这会增加控制节点上的负载,因此其支持forks数量增加的能力将显著低于仅管理Linux主机的控制节点。
可以从命令行覆盖Ansible配置文件中forks的默认设置。ansible
和ansible-playbook
命令均提供-f
或--forks
选项以指定要使用的forks
数量。
2 、管理滚动更新
通常,当Ansible运行play时,它会确保所有受管主机在启动任何主机进行下一个任务之前已完成每个任务。在所有受管主机完成所有任务后,将运行任何通知的处理程序。
但是,在所有主机上运行所有任务可能会导致意外行为。例如,如果play更新负载均衡Web服务器集群,则可能需要在进行更新时让每个Web服务器停止服务。如果所有服务器都在同一个play中更新,则它们可能全部同时停止服务。
避免此问题的一种方法是使用serial
关键字,通过play批量运行主机。在下一批次启动之前,每批主机将在整个play中运行。
在下面的示例中,Ansible一次在两个受管主机上执行play,直至所有受管主机都已更新。Ansible首先在前两个受管主机上执行play中的任务。如果这两个主机中的任何一个或两个都通知了处理程序,则Ansible将根据这两个主机的需要运行处理程序。在这两个受管主机上执行完play时,Ansible会在接下来的两个受管主机上重复该过程。Ansible继续以这种方式运行play,直到所有受管主机都已更新。
---
- hosts: httpd
serial: 2
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: add VirtualHost
template:
src: files/httpd-vhosts.j2
dest: /etc/httpd/conf.d/httpd-vhosts.conf
notify:
- restart httpd
- name: start httpd
service:
name: httpd
state: started
enabled: yes
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
假设上一示例中的webservers
组包含5个Web服务器
,它们位于负载均衡器后面。将serial
参数设置为2后,play一次将运行两台Web服务器。因此,5台Web服务器中的大多数服务器将始终可用。
相反,如果不使用serial
关键字,将同时在5台Web服务器上执行play和生成的处理程序。这可能会导致服务中断,因为Web服务将在所有Web服务器上同时重新启动。
重要:
出于某些目的,每批主机算作在主机子集上运行的完整play。这意味着,如果整个批处理失败,play就会失败,这将导致整个playbook运行失败。
在设置了serial: 2
的上一个场景中,如果出现问题并且处理的前2个主机的play失败
,则playbook将中止,其余3个主机将不会通过play运行
。这是一个有用的功能,因为只有一部分服务器会不可用,使服务降级而不是中断。
serial关键字也可以指定为百分比
。此百分比应用于play中的主机总数,以确定滚动更新批处理大小。无论百分比为何,每一工序的主机数始终为1
或以上
。
四、包含和导入文件
1、管理大型playbook
如果playbook很长或很复杂,我们可以将其分成较小的文件以便于管理。可采用模块化方式将多个playbook组合为一个主要playbook,或者将文件中的任务列表插入play。这样可以更轻松地在不同项目中重用play或任务序列。
2、包含或导入文件
Ansible可以使用两种操作将内容带入playbook。可以包含内容,也可以导入内容。
包含内容是一个动态操作。在playbook运行期间,Ansible会在内容到达时处理所包含的内容。
导入内容是一个静态操作。在运行开始之前,Ansible在最初解析playbook时预处理导入的内容。
3、导入playbokok
import_playbook指令允许将包含play列表的外部文件导入playbook。换句话说,可以把一个或多个额外playbook导入到主playbook中。
由于导入的内容是一个完整的playbook,因此import_playbook功能只能在playbook的顶层使用,不能在play内使用。如果导入多个playbook,则将按顺序导入并运行它们。
导入两个额外playbook的主playbook的简单示例如下所示:
[root@master project]# tree playbook/test/
playbook/test/
|-- config.yml //配置服务的playbook
|-- files
| `-- httpd.conf.j2
|-- install.yml //安装服务的playbook
`-- main.yml //主playbook
传jianjia2 模板(受管主机传到主机上)
scp
+数据存在受管主机的位置
+复制到哪个位置
[root@master files]# scp httpd:/etc/httpd/conf/httpd.conf.rpmsave httpd.conf.j2
[root@master files]# ls
httpd.conf.j2
修改端口
[root@master test]# vim files/httpd.conf.j2
#Listen 12.34.56.78:80
Listen {{ port }}
[root@master test]# cat install.yml config.yml main.yml
---
- hosts: httpd
tasks:
- name: install httpd
yum:
name: httpd
state: present
- name: start httpd
service:
name: httpd
state: started
---
- hosts: httpd
vars:
- port: 8080 //定义的变量
tasks:
- name: change configuration
template:
src: files/httpd.conf.j2 //创建模板
dest: /etc/httpd/conf/httpd.conf
notify: //触发通知
- restart httpd
handlers:
- name: restart httpd
service:
name: httpd
state: restarted
- name: import install
import_playbook: install.yml
- name: import config
import_playbook: config.yml
执行playbook
[root@master project]# ansible-playbook playbook/test/main.yml -C //在执行的时候,只需要指定主playbook即可
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.133]
TASK [install httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [start httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
[WARNING]: Found variable using reserved name: port
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.133]
TASK [change configuration] *********************************************************************************************************************************
changed: [192.168.129.133]
RUNNING HANDLER [restart httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
PLAY RECAP *********************************************************************************************************************************
192.168.129.133 : ok=6 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
还可以在主play中手动写新的任务,在执行的时候Ansible会按照顺序执行。
[root@master project]# cat playbook/test/main.yml
- name: import install
import_playbook: install.yml
- name: import config
import_playbook: config.yml
- hosts: httpd
tasks:
- name: restart httpd
service:
name: httpd
state: restarted
[root@master project]# ansible-playbook playbook/test/main.yml -C
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.133]
TASK [install httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [start httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
[WARNING]: Found variable using reserved name: port
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.133]
TASK [change configuration] *********************************************************************************************************************************
changed: [192.168.129.133]
RUNNING HANDLER [restart httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.133]
TASK [restart httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
PLAY RECAP *********************************************************************************************************************************
192.168.129.133 : ok=8 changed=5 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4、导入和包含任务
可以将任务文件中的任务列表导入或包含在play中。任务文件是包含一个任务平面列表的文件
[root@master test]# cat tasks/install.yml tasks/config.yml
- name: install httpd
yum:
name: httpd
state: present
- name: change configuration
template:
src: files/httpd.conf.j2
dest: /etc/httpd/conf/httpd.conf
1.导入任务文件 (可以看见文件里的内容的名称)
导入任务文件时,在解析该playbook时将直接插入该文件中的任务。Playbook中的import_tasks
的位置控制插入任务的位置以及运行多个导入的顺序
。
[root@master test]# cat main.yml
- hosts: httpd
gather_facts: no
vars:
port: 80
tasks:
- import_tasks: tasks/install.yml
- import_tasks: tasks/config.yml
- name: start service
service:
name: httpd
state: started
enabled: yes
[root@master project]# ansible-playbook playbook/test/main.yml -C
[WARNING]: Found variable using reserved name: port
PLAY [httpd] *********************************************************************************************************************************
TASK [install httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [change configuration] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [start service] *********************************************************************************************************************************
changed: [192.168.129.133]
PLAY RECAP *********************************************************************************************************************************
192.168.129.133 : ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
导入任务文件时,在解析该playbook时将直接插入该文件中的任务。由于import_tasks在解析playbook时静态导入任务,因此对其工作方式有一些影响。
- 使用import_tasks功能时,导入时设置的
when等条件语句将应用于导入
的每个任务 无法将循环用于import_tasks
功能- 如果使用变量来指定要导入的文件的名称,则将
无法使用主机或组清单变量
2.包含任务文件 (不能看见文件里的内容的名称)
可以使用include_tasks
功能将任务文件动态
导入playbook内的play中
[root@master test]# cat main.yml
- hosts: httpd
gather_facts: no
vars:
port: 80
tasks:
- include_tasks: tasks/install.yml
- include_tasks: tasks/config.yml
- name: start service
service:
name: httpd
state: started
enabled: yes
[root@master project]# ansible-playbook playbook/test/main.yml -C
[WARNING]: Found variable using reserved name: port
PLAY [httpd] *********************************************************************************************************************************
TASK [include_tasks] *********************************************************************************************************************************
included: /opt/project/playbook/test/tasks/install.yml for 192.168.129.133
TASK [install httpd] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [include_tasks] *********************************************************************************************************************************
included: /opt/project/playbook/test/tasks/config.yml for 192.168.129.133
TASK [change configuration] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [start service] *********************************************************************************************************************************
changed: [192.168.129.133]
PLAY RECAP *********************************************************************************************************************************
192.168.129.133 : ok=5 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Playbook内容的处理顺序会影响包含任务功能的工作方式。
- 使用include_tasks功能时,包含时设置的
when等条件语句将确定任务是否包含在play中
- 如果运行ansible-playbook --list-tasks以列出playbook中的任务,则
不会显示已包含任务文件中的任务
。将显示包含任务文件的任务
。相比之下,import_tasks功能不会列出导入任务文件的任务,而列出已导入任务文件中的各个任务 - 不能使用ansible-playbook --start-at-task从已包含任务文件中的任务开始执行playbook
不能使用notify语句触发
已包含任务文件中的处理程序名称。可以在包含整个任务文件的主playbook中触发处理程序,在这种情况下,已包含文件中的所有任务都将运行
**建议:**为方便管理,可以创建专门用于任务文件的目录,并将所有任务文件保存在该目录中。然后playbook就可以从该目录包含或导入任务文件。这样就可以构建复杂的playbook,同时简化其结构和组件的管理。
3.导入与包含的区别:
ansible-playbook --list-tasks
导入:
[root@master test]# ansible-playbook --list-tasks main.yml
playbook: main.yml
play #1 (httpd): httpd TAGS: []
tasks:
install httpd TAGS: [] //可以看见文件里的内容的名称
change configuration TAGS: []
start service TAGS: []
包含:
[root@master test]# ansible-playbook --list-tasks main.yml
playbook: main.yml
play #1 (httpd): httpd TAGS: []
tasks:
include_tasks TAGS: [] //不能看见文件里的内容的名称
include_tasks TAGS: []
start service TAGS: []
5、为外部play和任务定义变量
使用Ansible的导入和包含功能将外部文件中的play或任务合并到playbook中极大地增强了在Ansible环境中重用任务和playbook的能力。为了最大限度地提高重用可能性,这些任务和play文件应尽可能通用。变量可用于参数化play和任务元素,以扩大任务和play的应用范围。
[root@master test]# cat tasks/install.yml tasks/config.yml
- name: install {{ packname}}
yum:
name: "{{ packname}}"
state: present
- name: start {{ sername}}
service:
name: "{{ sername}}"
state: started
[root@master test]# cat main.yml
- hosts: httpd
vars: //在这里定义变量将会影响所有剧本
packname: vsftpd
sername: vsftpd
tasks:
- include_tasks: tasks/install.yml
- include_tasks: tasks/config.yml
[root@master project]# ansible-playbook playbook/test/main.yml -C
PLAY [httpd] *********************************************************************************************************************************
TASK [Gathering Facts] *********************************************************************************************************************************
ok: [192.168.129.133]
TASK [install vsftpd] *********************************************************************************************************************************
changed: [192.168.129.133]
TASK [include_tasks] *********************************************************************************************************************************
included: /opt/project/playbook/test/tasks/config.yml for 192.168.129.133
TASK [start vsftpd] *********************************************************************************************************************************
changed: [192.168.129.133]
PLAY RECAP *********************************************************************************************************************************
192.168.129.133 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
||
[root@master test]# cat main.yml
- hosts: httpd
tasks:
- include_tasks: tasks/install.yml
vars: //在这里定义变量只会影响这一个剧本
packname: vsftpd
sername: vsftpd
- include_tasks: tasks/config.yml