ansible系列(29)--ansible的Jinja2语法及应用
1. Ansible Jinja2
Jinja2
是 Python
的全功能模板引擎
Ansible
需要使用 Jinja2
模板来修改被管理主机的配置文件。
ansible
使用 jinja2
模板需要借助 template
模块实现。
template
模块和 copy
模块完全一样,都是拷贝文件至远程主机,与copy
的语法基本完全一致,区别在于template
模块会自动解析要拷贝的文件中变量的值,而 copy
模块则是原封不动的将文件拷贝至被控端。
1.1 jinja2语法结构
- 要想在配置文件中使用
jinj2
,playbook
中的tasks
必须使用template
模块。 - 配置文件里面使用变量,比如
{{ PORT }}
或使用{{ facts 变量 }}
。 - {% %} :用来装载控制语句,比如
if
控制结构,for
循环控制结构。 - {# #} :用来装载注释,模板文件被渲染后,注释不会包含在最终生成的文件中。
jinja2
文件的后缀一般为.j2
。
jinja2
的判断和循环的语法如下:
if
判断:{% if EXPR %}
...
{% endif %} 或:
{% if EXPR %}
...
{% else %}
...
{% endif %} 或:
{% if EXPR %}
...
{% elif EXPR %}
...
{% endif %} 或:
{% if EXPR %}
...
{% elif EXPR %}
...
{% else %}
...
{% endif %}
循环:
{% for i in EXPR %}
...
{% endfor %}
循环示例如下:
# cat test.j2
jinja2 test
{% for i in [3,1,7,8,2] %}
{{ i }}
{% endfor %} 渲染效果如下:
# cat /opt/test
jinja2 test
3
1
7
8
2
在
jinja2
中,波浪符”~”
就是字符串连接符,它会把所有的操作数转换为字符串,并且连接它们:# cat test.j2
jinja2 test
{% for i in [3,1,7,8,2] -%}
{{ i~' ' }}
{%- endfor %} 渲染效果如下:
# cat test
jinja2 test
3 1 7 8 2
1.2 jinja2中{{ }}中的运算符
比较表达式的相关示例如下:
#模板文件内容如下:
# cat test.j2
jinja2 test
{{ 1 == 1 }}
{{ 2 != 2 }}
{{ 2 > 1 }}
{{ 2 >= 1 }}
{{ 2 < 1 }}
{{ 2 <= 1 }} #生成文件内容如下:
# cat test
jinja2 test
True
False
True
True
False
False
逻辑运算的相关示例如下:
#模板文件内容
# cat test.j2
jinja2 test
{{ (2 > 1) or (1 > 2) }}
{{ (2 > 1) and (1 > 2) }} {{ not true }}
{{ not True }}
{{ not false }}
{{ not False }} #生成文件内容
# cat test
jinja2 test
True
False False
False
True
True
算数运算的相关示例如下:
模板文件内容
# cat test.j2
jinja2 test
{{ 3 + 2 }}
{{ 3 - 4 }}
{{ 3 * 5 }}
{{ 2 ** 3 }}
{{ 7 / 5 }}
{{ 7 // 5 }}
{{ 17 % 5 }} 生成文件内容
# cat test
jinja2 test
5
-1
15
8
1.4
1
2
成员运算的相关示例如下:
模板文件内容
# cat test.j2
jinja2 test
{{ 1 in [1,2,3,4] }}
{{ 1 not in [1,2,3,4] }} 生成文件内容
# cat test
jinja2 test
True
False
向{{ }}中传递变量:
#jinja2文件如下:
jinja2 test
{{ teststr }}
{{ testnum }}
{{ testlist[1] }}
{{ testlist1[1] }}
{{ testdic['name'] }} #playbook文件如下:
# cat temptest.yml
---
- hosts: test70
remote_user: root
gather_facts: no
vars:
teststr: 'tstr'
testnum: 18
testlist: ['aA','bB','cC']
testlist1:
- AA
- BB
- CC
testdic:
name: bob
age: 18
tasks:
- template:
src: /testdir/ansible/test.j2
dest: /opt/test #最终生成后的文件如下:
# cat test
jinja2 test
tstr
18
bB
BB
bob
1.3 jinja2中for循环和if判断示例
目标:生成如下的配置文件:
{
server_name www.example.com;
listen 80;
}
{
server_name app.example.com;
listen 81;
}
{
server_name blog.example.com;
listen 82;
}
首先要定义一个模板文件,在模板文件中来调用这些值,例如上例中的
server
名字和端口各不相同,需要通过定义变量将不同的值区分出来,我们首先来解决端口的问题:[root@xuzhichao playbook]# cat jinja2_example1.yml
- hosts: localhost
vars:
ports:
- 81
- 82
- 83
tasks:
- name:
template:
src: file/jinja2_test1
dest: /tmp/jinja2_test1
模板文件如下:
[root@xuzhichao playbook]# cat file/jinja2_test1.j2
{% for p in ports %} <==此处的ports需要与定义的变量名保持一致
server {
listen {{ p }}
}
{% endfor %}
运行
playbook
,最终得到的文件如下:[root@xuzhichao playbook]# ansible-playbook jinja2_example1.yml [root@xuzhichao playbook]# cat /tmp/jinja2_test1
server {
listen 81
}
server {
listen 82
}
server {
listen 83
}
然后我们再来达到最终的效果,修改一下
playbook
文件,变量定义使用字典的形式:[root@xuzhichao playbook]# cat jinja2_example1.yml
- hosts: localhost
vars:
host:
- server: www.example.com
port: 81
- server: app.example.com
port: 82
- server: blog.example.com
port: 83 tasks:
- name:
template:
src: file/jinja2_test1.j2
dest: /tmp/jinja2_test1
模板文件如下:
[root@xuzhichao playbook]# cat file/jinja2_test1.j2
{% for var in host %}
server {
server_name {{ var.server }};
listen {{ var.port }};
}
{% endfor %}
运行
playbook
,最终得到的文件如下:[root@xuzhichao playbook]# ansible-playbook jinja2_example1.yml [root@xuzhichao playbook]# cat /tmp/jinja2_test1
server {
server_name www.example.com;
listen 81;
}
server {
server_name app.example.com;
listen 82;
}
server {
server_name blog.example.com;
listen 83;
}
这样得到了最终的目标,此时若某一个
nginx
虚拟主机需要使用默认的端口80
(即没有定义port
这个变量),或者虚拟主机没有定义server_name
,这样上面的模板就无法实现了,此时我们可以修改一下模板文件,增加判断机制,如下:[root@xuzhichao playbook]# cat file/jinja2_test1.j2
{% for var in host %}
server {
{% if var.server is defined %} <==判断一下变量是否定义,只有定义了才会写到配置文件中
server_name {{ var.server }};
{% endif %}
{% if var.port is defined %}
listen {{ var.port }};
{% endif %}
}
{% endfor %}
测试,修改
playbook
文件如下:[root@xuzhichao playbook]# cat jinja2_example1.yml
- hosts: localhost
vars:
host:
- server: www.example.com
- server: app.example.com
port: 82
- port: 83 tasks:
- name:
template:
src: file/jinja2_test1.j2
dest: /tmp/jinja2_test1
运行
playbook
,生成的文件如下:[root@xuzhichao playbook]# ansible-playbook jinja2_example1.yml [root@xuzhichao playbook]# cat /tmp/jinja2_test1
server { server_name www.example.com;
}
server { server_name app.example.com;
listen 82;
}
server {
listen 83;
}
1.4 Jinja2管理Nginx负载均衡
需求:在
nginx
的负载均衡场景中,配置文件中会定义后端WEB主机列表,如果新增加了一个后端服务器,就需要为ansible添加一个主机清单,并且手动去配置文件中添加这个WEB主机,我们需要使用模板功能实现在ansible的添加一个主机清单后,nginx的配置文件就自动把这个主机添加到后端WEB服务器中。首先定义
playbook
文件:[root@xuzhichao playbook]# cat proxy_test.yml
- hosts: localhost
tasks:
- name: Copy Template Nginx Configure
template:
src: conf/proxy.conf.j2
dest: /tmp/proxy.conf
notify: Restart Nginx handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
模板文件如下:
upstream ansible_php {
{% for i in groups['NginxWebs'] %}
server {{ i }}:80;
{% endfor %}
} server {
listen 80;
server_name ansible.example.com;
location / {
proxy_pass http://ansible_php;
proxy_set_header Host $http_hosts;
}
}
运行
playbook
,生成的文件如下:[root@xuzhichao playbook]# ansible-playbook jinja2_example1.yml [root@xuzhichao playbook]# cat /tmp/proxy.conf
upstream ansible_php { server 192.168.20.22:80; server 192.168.20.23:80; } server {
listen 80;
server_name ansible.example.com;
location / {
proxy_pass http://ansible_php;
proxy_set_header Host $http_hosts;
}
}
1.5 Jinja2管理Keepalived
ansible
使用jinja2
的if
判断表达式渲染出keepalived
的Master
和Slave
的配置文件。并推送至被控主机,实现方案如下:
使用
playbook
推送keeplaived
配置文件:[root@xuzhichao playbook]# cat keepalived.yml
- hosts: lvs
tasks:
- name: Copy Template Keepalived Configure
template:
src: keepalived.conf.j2
dest: /etc/keepalived/keepalived.conf
notify: Restart Keepalived Server handlers:
- name: Restart Keepalived Server
service:
name: keepalived
state: restarted
准备
keepalived.conf.j2
配置文件:[root@xuzhichao playbook]# cat keepalived.conf.j2
global_defs {
router_id {{ ansible_fqdn }}
}
vrrp_instance VI_1 {
{% if ansible_fqdn == 'lvs01' %} #如果主机名为lb01则使用如下配置
state MASTER
priority 150
{% elif ansible_fqdn == 'lvs02' %} #如果主机名为lb02则使用如下配置
state Backup
priority 100
{% endif %}
#相同配置
interface eth0
virtual_router_id 51
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3
}
}
运行
palybook
,检查 lvs01Master
节点的keepalived
配置文件:[root@lvs01 playbook]# cat keepalived.conf.j2
global_defs {
router_id {{ ansible_fqdn }}
}
vrrp_instance VI_1 {
state MASTER
priority 150
interface eth0
virtual_router_id 51
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3
}
}
检查 lvs02
Backup
节点的keepalived
配置文件:[root@lvs02 playbook]# cat keepalived.conf.j2
global_defs {
router_id {{ ansible_fqdn }}
}
vrrp_instance VI_1 {
state Backup
priority 100
interface eth0
virtual_router_id 51
advert_int 1
authentication {
auth_type PASS
auth_pass 1111
}
virtual_ipaddress {
10.0.0.3
}
}
ansible系列(29)--ansible的Jinja2语法及应用的更多相关文章
- ansible使用jinja2管理配置文件以及jinja2语法简介
一.Jinja2介绍 Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity.它能完全支持unicode,并具有集成的沙箱执行环 ...
- Ansible系列(二):选项和常用模块
html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...
- Ansible系列(五):playbook应用和roles自动化批量安装示例
html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...
- Ansible系列(六):各种变量定义方式和变量引用
本文目录:1.1 ansible facts1.2 变量引用json数据的方式 1.2.1 引用json字典数据的方式 1.2.2 引用json数组数据的方式 1.2.3 引用facts数据1.3 设 ...
- Ansible系列(四):playbook应用和roles自动化批量安装示例
Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html playbook是ansible实现批量自动化最重要的手段.在其中可以使用变 ...
- Ansible系列(五):各种变量定义方式和变量引用
Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1.1 ansible facts facts组件是用来收集被管理节点信息的 ...
- Ansible系列(一):基本配置和使用
本文目录:1.1 安装Ansible1.2 配置Ansible 1.2.1 环境配置 1.2.2 SSH互信配置 1.2.3 简单测试1.3 inventory Ansible是一种批量.自动部署工具 ...
- Ansible系列(三):YAML语法和playbook写法
html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...
- Ansible系列(六):循环和条件判断
本文目录:1. 循环 1.1 with_items迭代列表 1.2 with_dict迭代字典项 1.3 with_fileglob迭代文件 1.4 with_lines迭代行 1.5 with_ne ...
- Ansible系列(七):执行过程分析、异步模式和速度优化
本文目录:1.1 ansible执行过程分析1.2 ansible并发和异步1.3 ansible的-t选项妙用1.4 优化ansible速度 1.4.1 设置ansible开启ssh长连接 1.4. ...
随机推荐
- C++中结构体的各种用法,详细版
C++中的结构体是一种用户自定义的数据类型,可以存储不同类型的数据成员.以下是一些结构体的常见用法: 1. 定义结构体类型 结构体类型的定义可以放在函数内部或外部,例如: ``` struct Per ...
- GPTCache使用
1.概述 传统应用开发中,为了提升系统的查询性能,往往会在系统架构设计中加入缓存机制.在AI大模型领域,虽然功能非常强大,但是使用成本也是非常昂贵的,比如OpenAI的GPT-4按照token的个数来 ...
- C++设计模式 - 原型模式(Prototype)
对象创建模式 通过"对象创建" 模式绕开new,来避免对象创建(new)过程中所导致的紧耦合(依赖具体类),从而支持对象创建的稳定.它是接口抽象之后的第一步工作. 典型模式 Fac ...
- Docker学习路线11:Docker命令行
Docker CLI (命令行界面) 是一个强大的工具,可让您与 Docker 容器.映像.卷和网络进行交互和管理.它为用户提供了广泛的命令,用于在其开发和生产工作流中创建.运行和管理 Docker ...
- Numpy结构化数组
Numpy结构化数组 Numpy的结构化数组和记录数组为复合的.异构的的数据提供了非常有效的存储. 结构化数组 In [1]: import numpy as np In [2]: name = [' ...
- HarmonyOS卡片刷新服务,信息实时更新一目了然
如今衣食住行娱乐影音等App占据了大多数人的手机,一部手机可以满足日常大多需求,但对需要经常查看或进行简单操作的场景来说,总需要用户点开App操作未免过于繁琐. 针对该问题, HarmonyOS SD ...
- centos部署Django一:环境搭建
前言: 参考文档: https://www.cnblogs.com/djangocn/p/9538551.html https://www.icode9.com/content-3-546765.ht ...
- 前端vue+elementUI如何实现记住密码功能
我们这回使用纯前端保存密码 既然是记住密码,前端也就是使用cookie保存,访问时用cookie读取 先来了解下cookie的基本使用吧 Cookie 所有的cookie信息都在document.co ...
- identity4 系列————用户数据持久化篇[六]
前言 前面的例子已经将各种情形下的例子已经介绍了一遍,那么后面就是用户数据持久化该如何处理了. 正文 例子位置: https://github.com/IdentityServer/IdentityS ...
- APISIX 简单的自定义插件开发步骤
本文基于 APISIX 3.2 版本进行插件开发并运行通过. APISIX 目前开发插件比较简单,只需要编写 Lua 源代码并放到默认的插件目录下,然后通过配置文件开启插件即可,我们如果使用 Dock ...