目录
使用jinja2模板部署自定义文件
一Ansible如何使用jinja2模版
二,jinja2常用语法
三,jinja2基本语法
1,注释
2,赋值
3,变量
四,条件判断
1,单分支
2,双分支
3,多分支
五,循环语句
六,空白控制
七,jinja2构建文件模板
八,template模块
项目管理
一,并行处理forks serial
1, Aniable运行play机制---forks
2, serial--Ansible运行滚动机制
二,playbook的文件导入
1,管理大型的playbook
2,包含或导入任务文件
Ansible使用jinja3模版,也就是template模版,该模块和copy模块一样,都是将文件复制到目标机器上,但是区别在于template模块可以获取要复制文件中的变量的值,而copy则是原封不动的把文件内容复制过去。
实际运用:比如,针对不同的主机定义不同的变量,template会在文件分发前读取变量到jinja2模版,之后分发到不同的被管理主机上。
Jinja2是基于python书写的模版引擎,功能比较类似于PHP的smarty模版
1)要想在配置文件中使用jinja2,playbook中的tasks必须使用template模块。
2)模版配置文件里面使用变量,比如{{ port }} 或者{{ facts 变量 }}
Jinja2文件以.j2为后缀,也可以不写后缀
在jinja2中,存在三种语法:
{#......#} 要把模版中一行或多行注释掉,默认的注释语法
为变量赋值,优先级高于playbook中的优先级。
{% set username = 'zhang' % }
{% set navigation = [('index.html','Index'),('about.html','About')] %}
{{…….}} 把表达式的结果打印到模版上
你可以使用(.)来访问变量的属性,作为替代,也可以使用所谓的下标语法([]),如下示例:
{{ foo.bar }}
{{ foo['bar'] }}
花括号不是变量的一部分,而是打印语句的重要的一部分
{% if 条件表达式 %}
…….
{% endif %}
{% if 条件表达式 %}
…….
{% else %}
…….
{% endif %}
{% if 条件表达式 %}
…….
{% elif 条件表达式 %}
…….
{% else %}
…….
{% endif %}
示例:
{% if idc is definded %}
{{ idc }}
{{% else %}}
没有定义
{% endif %}
{% for user in users %}
{{ user }}
{% endfor %}
列出myhosts中的所有主机
{% for myhost in groups['myhosts'] %}
{{ myhosts }}
{% endfor %}
案例:列出test中的所有主机
(1)此时的主机清单文件如下:
[root@server var_test]# cat inventory
(2)编辑ex1.j2文件
[root@server var_test]# vim ex1.j2
{% for myhost in groups.test %}
{{ myhost }}
{% endfor %}
(3)编辑ex1.yml文件
---
- name: play1
hosts: all
tasks:
- name: task1
template:
src: ./ex1.j2
dest: /opt/host1
(4)执行文件ex1.yml
[root@server var_test]# ansible-playbook ex1.yml
(5)在受控端主机查看结果
[root@node1 ~]# cat /opt/host1
[root@node2 ~]# cat /opt/host1
默认配置中,模版引擎不会对空白做进一步修改,所以每个空白(空格,换行符 等等)都会原封不动返回。
此外,你也可以手动剥离模版中的空白。当你在块(比如一个for标签,一段注释或变量表达式)的开始或结束放置一个减号(-),可以一出块前或块后的空白。
案例:
1,没放置空白块前:
(1)编辑文件ex2.j2
{% for item in range(1,9) %}
{{ item }}
{% endfor %}
(2)编辑ex2.yml文件
---
- name: play1
hosts: all
tasks:
- name: task1
template:
src: ./ex2.j2
dest: /opt/ex2
(3)执行文件ex2.yml
[root@server var_test]# ansible-playbook ex2.yml
(4)在受控端主机查看结果
[root@node1 ~]# cat /opt/ex2
2,放置空白块后
(1)编辑ex3.j2文件
{% for item in range(1,9) -%}
{{ item }}
{%- endfor %}
(2)编辑ex3.yml文件
---
- name: play1
hosts: all
tasks:
- name: task1
template:
src: ./ex3.j2
dest: /opt/ex3
(3)执行文件ex3.yml
[root@server var_test]# ansible-playbook ex3.yml
(4)在受控端主机上查看结果
[root@node1 ~]# cat /opt/ex3
文本文件,嵌套有脚本(使用模板编写语言编写)
管理文件的一种更强大的方法是为其构建模板。通过此方法,您可以使用ansible变量和事实便捷一个模板配置文件,在部署该文件时自动为受管主机自定义此模板配置文件。这样更容易控制,也更不易出错。
使用分隔符
变量和逻辑表达式至于标记或分隔符之间。例如,jinja2模板将{% EXPR %}用于表达式或逻辑(如循环),而{{ EXPR }} 则用于向最终用户输出表达式或变量的结果。后一标记在呈现时将被替换为一个或多个值,最终用户可见。使用 {# COMMENT #}语法括起来不应出现在最终文件中的注释。
在下例中第一行中含有不会包含于最终文件中的注释。第二行中引用的变量被替换为所引用的系统事实的值。
{ # /etc/hosts line #} |
{{ ansible_facts'default_ipv4'] }} {{ ansible_facts['hostname'] }} |
{% for item in all_items %} {{ item }} {% endfor %} {% for finished %} {{ result }} {% endif %} |
template模块
template使用了Jinjia2格式作为文件模版,进行文档内变量的替换的模块。它的每次使用都会被ansible标记为”changed”状态。
参数名 |
是否必须 |
默认值 |
选项 |
说明 |
backup |
no |
no |
yes/no |
建立个包括timestamp在内的文件备份,以备不时之需. |
dest |
yes |
远程节点上的绝对路径,用于放置template文件。 |
||
group |
no |
设置远程节点上的的template文件的所属用户组 |
||
mode |
no |
设置远程节点上的template文件权限。类似Linux中chmod的用法 |
||
owner |
no |
设置远程节点上的template文件所属用户 |
||
src |
yes |
本地Jinjia2模版的template文件位置。 |
案例:制作hosts模板文件
在受控主机中会按照jinja2动态模板文件,生成相对应的主机信息。
(1)编辑文件hosts.j2
[root@server var_test]# vim hosts.j2
{% for host in groups['all'] %}
{{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }} {{ hostvars[host]['ansible_facts']['fqdn'] }} {{ hostvars[host]['ansible_facts']['hostname'] }}
{% endfor %}
(2)编辑hosts.yml 文件
---
- name: play1
hosts: all
tasks:
- name: task1
template:
src: ./hosts.j2
dest: /etc/myhosts
(3)检查是否有语法错误
[root@server var_test]# ansible-playbook hosts.yml --syntax-check
(4)执行hosts.yml
[root@server var_test]# ansible-playbook hosts.yml
(5)在受控端主机node1上查看结果
[root@node1 ~]# cat /etc/myhosts
1)当Ansible处理playbook时,会按顺序运行每个play。确定play的主机列表之后,Ansible将按
顺序运行每个任务
2)通常,所有主机必须在任何主机在play中启动下一个任务之前成功完成任务
3) 注意:
理论上,Ansible可以同时连接到play中的所有主机以执行每项任务。这非常适用于小型主机
列表。但如果该play以数百台主机为目标,则可能会给控制节点带来沉重负担
4) Ansible所进行的最大同时连接数由Ansible配置文件中的forks参数控制,默认情况下设为
5(forks:分叉)
通过以下方式之一来验证:[root@localhost ~]# grep forks /etc/ansible/ansible.cfg #forks = 5
5) 例如,假设Ansible控制节点配置了5个forks的默认值,并且play具有10个受管主机。
Ansible将在前5个受管主机上执行play中的第一个任务,然后在其他5个受管主机上对第一个
任务执行第二轮。
在所有受管主机上执行第一个任务后,Ansible将继续一次在5受管主机的组中的所有受管主
机上执行下一个任务。Ansible将依次对每个任务执行此操作,直到play结束。
6)forks的默认值设置得非常保守。如果你的控制节点正在管理Linux主机,则大多数任务将在受
管主机上运行,并且控制节点的负载较少。在这种情况下,通常可以将forks的值设置得更高
, 可能接近100,然后性能就会提高
7)如果playbook在控制节点上运行很多代码,则应明智地提高forks限值。如果使用Ansible管理
网络路由器和交换机,则大多数模块在控制节点上运行而不是在网络设备上运行。
由于这会增加控制节点上的负载,因此其支持forks数量增加的能力将显著低于仅管理Linux
主机的控制节点
8)可以从命令行覆盖Ansible配置文件中forks的默认设置。ansible和ansible-playbook命令均提
供-f或--forks选项以指定要使用的forks数量
滚动更新:
方法一: 设置固定批量大小
Serial:2
方法二: 设置批量大小为百分比
Serial:20%
方法三: 将批量大小设置为可更改
Serial:
- 1
- 10%
- 100 %
(如果第一台机器失败,就停止;若成功,则继续后面的10%)
1)通常,当Ansible运行play时,它会确保所有受管主机在启动任何主机进行下一个任务之前已
完成每个任务。在所有受管主机完成所有任务后,将运行任何通知的处理程序
2)但是,在所有主机上运行所有任务可能会导致意外行为。
例如,如果play更新负载均衡Web服务器集群,则可能需要在进行更新时让每个Web服务器
停止服务。如果所有服务器都在同一个play中更新,则它们可能全部同时停止服务
3)避免此问题的一种方法是使用serial关键字,通过play批量运行主机。在下一批次启动之前,
每批主机将在整个play中运行
4)演示实例:
[root@localhost project]# cat playbook.yml
---
- hosts: all
serial: 2
tasks:
- name: install httpd
yum:
name: httpd
state: present
notify:
- start httpd
handlers:
- name: start httpd
service:
name: httpd
state: started
在上面的示例中,Ansible一次在两个受管主机上执行play,直至所有受管主机都已更新
5)更新机制:
6)假设上一示例中的webservers组包含5个Web服务器,它们位于负载均衡器后面。将serial参
数设置为2后,play一次将运行两台Web服务器。因此,5台Web服务器中的大多数服务器将
始终可用
7)重要:
在设置了serial: 2 的上一个场景中,如果出现问题并且处理的前2个主机的play失败,
则 playbook将中止,其余3个主机将不会通过play运行。这是一个有用的功能,因为只有
一部分服务器会不可用,使服务降级而不是中断
serial关键字也可以指定为百分比。此百分比应用于play中的主机总数,以确定滚动更新批
处理大小。无论百分比为何,每一工序的主机数始终为1或以上
1) 如果playbook很长很复杂,我们可以将其分成较小的文件以便于管理
2)可采用模块化方式将多个playbook组合为一个主要playbook,或者将文件中的任务列表
插入play import_playbook
1,Import_playbook示例:安装bind并启动
(1)创建目录
[root@server ~]# mkdir /day06/playbook -pv
(2)创建inventory文件与ansible.cfg文件
[root@server playbook]# cp /day05/var_test/inventory inventory
[root@server playbook]# cp /day05/var_test/ansible.cfg ansible.cfg
(3)创查看nventory文件与ansible.cfg文件
[root@server playbook]# cat inventory
[root@server playbook]# cat ansible.cfg
(4)此时的node1主机上没有bind软件包
[root@node1 ~]# rpm -q bind
(5)编辑文件import_playbook.yml文件,安装bind服务
---
- name: play1
hosts: node1
tasks:
- name: task1
yum:
name: bind
state: present
(6)检测有无语法问题
[root@server playbook]# ansible-playbook import_playbook.yml --syntax-check
(7)编辑playbook.yml文件,开启上面安装的bind服务
---
- name: import
import_playbook: ./import_playbook.yml
- name: play1
hosts: node1
tasks:
- name: task1
service:
name: named
state: started
(8)检测有无语法问题:
[root@server playbook]# ansible-playbook playbook.yml --syntax-check
(8)执行文件playbook.yml
[root@server playbook]# ansible-playbook playbook.yml
(9)在node1主机上查看结果
[root@node1 ~]# rpm -q bind
[root@node1 ~]# systemctl status named
2,Import_tasks示例:停止bind并卸载
(1)编辑文件tasks.yml,把停止bind并卸载bind写入次文件中
---
- name: stop
service:
name: named
state: stopped
- name: absent
yum:
name: named
state: absent
(2)检查是否有无语法错误
[root@server playbook]# ansible-playbook tasks.yml --syntax-check
(3)编辑playbook2.yml文件,将上述任务导入并执行
---
- hosts: node1
tasks:
- name:
import_tasks: ./tasks.yml
(4)检查是否有无语法错误
[root@server playbook]# ansible-playbook playbook2.yml --syntax-check
(5)执行playbook2.yml文件
[root@server playbook]# ansible-playbook playbook2.yml
(6)在node1主机上查看结果
[root@node1 ~]# systemctl status named