Ansible 模板,清单管理 ,并行方式
1. 使用jinjia2 模板部署自定义文件
1.1简介
jinjia模板是在ansible中建立的一类模板文件,通常以.j2结尾标识。模板的内容含有多个变量,使原本固定的某个文件配置,通过参数的改变,变得可以复用,提高了使用效率、
1.2 jinjia2模板的组成
模板的组成:
-
模板一般由多个元素组成,包含:数据、变量、表达式
-
变量:通常在play中的vars中进行标识,
-
表达式为: {% %} 表达式或者逻辑;{{}}最终向用户输出表达式的结果; {# #}注释。
1.3 部署jinjia模板
//模板
{ #春风随我作狮子鸣# }
{{ ansible_facts['default_ipv4']['address'] }} {{ ansible_facts['fqdn'] }}
//playbook
---
- hosts: 192.168.200.145
tasks:
- name:
template:
src: hosts.j2
dest: /etc/hosts
//查看
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.200.145 localhost
1.4 使用循环
[root@localhost opt]# cat vars_file/user.yml //定义变量
users:
- 123
- 456
- 789
- qwe
//for循环
{% for user in users %}
{{ user }}
{% endfor %}
//编写playbook
---
- hosts: 192.168.200.145
vars_files:
vars_file/user.yml
tasks:
- name:
template:
src: jinjia2/for.j2
dest: /opt/zzz
//查看
[root@localhost opt]# cat zzz
123
456
789
qwe
//开除qwe
{% for user in users if not user == "456" %}
{{ user }}
{% endfor %}
//查看
[root@localhost opt]# cat zzz
123
456
789
//使用条件语句if
{% if users %}
{{ users }}
{% endif%}
---
- hosts: 192.168.200.145
vars_files:
vars_file/user.yml
tasks:
- name:
template:
src: jinjia2/if.j2
dest: /opt/zzz
//查看
[root@localhost opt]# cat zzz
[123, 456, 789, 'qwe']
1.5 变量过滤器
jinja2提供了过滤器,更改模板表达式的输出格式(例如,输出到果JSON)。有适用于YAML和JSON等语言的过滤器。to_json过滤器使用JSON格式化表达式输出,to_yaml过滤器则使用YAML格式化表达式输出。
{{ output | to_json }}
{{ output | to_yaml }}
1.6 模板示例
//建立模板
This is the system {{ ansible_facts['fqdn'] }}
This is a {{ ansible_facts ['distribution']}}
{{ ansible_facts ['distribution_version']}}
System owner is {{ system_owner }}.
//
---
- hosts: 192.168.200.145
vars:
- system_owner: LPL@linux.com
tasks:
- name:
template:
src: jinjia2/test.j2
dest: /opt/zzz
//查看
[root@localhost opt]# cat zzz
This is the system localhost.localdomain
This is a RedHat
8.2
System owner is LPL@linux.com.
2.清单管理
//清单文件
[root@localhost opt]# cat inventory
[httpd]
192.168.200.147
[mysql]
192.168.200.145
[php]
192.168.200.146
[lamp:children]
httpd
mysql
php
2.1使用组指定主机
当组名称用作主机模式时,它指定Ansible将对属于该组的成员的主机执行操作。
---
- hosts: httpd
记住,有一个名为all的特别组,它匹配清单中的所有受管主机。
---
- hosts: all
还有一个名为ungrouped的特别组,它包括清单中不属于任何其他组的所有受管主机:
---
- hosts: ungrouped
2.2 使用通配符匹配多个主机
若要达成与all主机模式相同的目标,另一种方法是使用*
通配符,它将匹配任意字符串。如果主机模式只是带引号的星号,则清单中的所有主机都将匹配。
---
- hosts: '*'
重要
一些在主机模式中使用的字符对shell也有意义。通过ansible使用主机模式从命令行运行临时命令时,这可能会有问题。建议大家在命令行中使用单引号括起使用的主机模式,防止它们被shell意外扩展。
类似的,如果在Ansible Playbook中使用了任何特殊通配符或列表字符,必须将主机模式放在单引号里,确保能够正确解析主机模式。
---
- hosts: '!httpd,mysql'
也可使用*
字符匹配包含特定子字符串的受管主机或组。
以下示例使用通配符主机模式来匹配开头为**192.168.200.**的主机或主机组的名称:
---
- hosts: '192.168.200.*'
以下示例使用通配符主机模式来匹配开头为http的主机或主机组的名称。
---
- hosts: 'http*'
重要
通配符主机模式匹配所有清单名称、主机和主机组。它们不区别名称是DNS名、IP地址还是组,这可能会导致一些意外的匹配。
例如,根据示例清单,比较上一示例中指定httpd结果
---
- hosts: 'httpd*'
2.3 列表
可以通过逻辑列表来引用清单中的多个条目。主机模式的逗号分隔列表匹配符合任何这些主机模式的所有主机。
如果提供受管主机的逗号分隔列表,则所有这些受管主机都将是目标:
---
- hosts: 192.168.200.147,,192.168.200.145
如果提供组的逗号分隔列表,则属于任何这些组的所有主机都将是目标:
---
- hosts: mysql,httpd
也可以混合使用受管主机、主机组和通配符,如下所示:
---
- hosts: 'httpd,,192.168.200.145'
注意
也可以用冒号(:)取代逗号。不过,逗号是首选的分隔符,特别是将IPv6地址用作受管主机名称时。
如果列表中的某一项以与符号(&)开头,则主机必须与该项匹配才能匹配主机模式。它的工作方式类似于逻辑AND。
通过在主机模式的前面使用感叹号(!)表示从列表中排除匹配某一模式的主机。它的工作方式类似于逻辑NOT。
根据示例清单,以下示例匹配datacenter组中定义的所有主机,但mysql除外:
---
- hosts: lamp,!mysql
也可以使用模式**’!’**来获得相同的结果。
最后一个示例演示了使用匹配测试清单中的所有主机的主机模式,datacenter1组中的受管主机除外。
---
- hosts: all,!httpd
2.4 动态清单文件管理
[root@localhost opt]# ansible-inventory -i inventory --list
{
"_meta": {
"hostvars": {
"192.168.200.145": {
"get_url": [
null
],
"package": "httpd"
},
"192.168.200.147": {
"package": "git"
}
}
},
"all": {
"children": [
"lamp",
"ungrouped"
]
},
"httpd": {
"hosts": [
"192.168.200.147"
]
},
"lamp": {
"children": [
"httpd",
"mysql",
"php"
]
},
"mysql": {
"hosts": [
"192.168.200.145"
]
},
"php": {
"hosts": [
"192.168.200.146"
]
}
}
//配置清单批处理的个数
在企业部署时,防止所有服务器在更新等操作时,全部宕机,故在配置时,可分批次处理。默认参数为5台
root@contral progreammer]# grep forks /etc/ansible/ansible.cfg
#forks = 5
[root@contral progreammer]# ansible-config dump | grep -i forks
DEFAULT_FORKS(default) = 5
//命令行中的操作
在命令行使用 -f 或者 --forks 指定同时并行的主机个数
[root@contral progreammer]# ansible-playbook -f 2 test.yml
//play中的参数
---
- hosts: all
serial: 2
3.forks与serial
3.1 使用分叉在ansible中配置并行
当Ansible处理playbook时,会按顺序运行每个play。确定play的主机列表之后,Ansible将按顺序运行每个任务。通常,所有主机必须在任何主机在play中启动下一个任务之前成功完成任务。
理论上,Ansible可以同时连接到play中的所有主机以执行每项任务。这非常适用于小型主机列表。但如果该play以数百台主机为目标,则可能会给控制节点带来沉重负担。
Ansible所进行的最大同时连接数由Ansible配置文件中的forks参数控制。默认情况下设为5,这可通过以下方式之一来验证。
[root@localhost ~]# grep forks /etc/ansible/ansible.cfg
#forks = 5
[root@localhost ~]# ansible-config dump|grep -i forks
DEFAULT_FORKS(default) = 5
[root@localhost ~]# 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
3.2 管理滚动更新
通常,当Ansible运行play时,它会确保所有受管主机在启动任何主机进行下一个任务之前已完成每个任务。在所有受管主机完成所有任务后,将运行任何通知的处理程序。
但是,在所有主机上运行所有任务可能会导致意外行为。例如,如果play更新负载均衡Web服务器集群,则可能需要在进行更新时让每个Web服务器停止服务。如果所有服务器都在同一个play中更新,则它们可能全部同时停止服务。
避免此问题的一种方法是使用serial关键字,通过play批量运行主机。在下一批次启动之前,每批主机将在整个play中运行。
在下面的示例中,Ansible一次在两个受管主机上执行play,直至所有受管主机都已更新。Ansible首先在前两个受管主机上执行play中的任务。如果这两个主机中的任何一个或两个都通知了处理程序,则Ansible将根据这两个主机的需要运行处理程序。在这两个受管主机上执行完play时,Ansible会在接下来的两个受管主机上重复该过程。Ansible继续以这种方式运行play,直到所有受管主机都已更新
---
- name: Rolling update
hosts: lamp
serial: 2
tasks:
- name: latest apache httpd package is installed
yum:
name: httpd
state: latest
notify: restart apache
handlers:
- name: restart apache
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或以上。