1. Ansible Jinja2

Jinja2Python 的全功能模板引擎

Ansible 需要使用 Jinja2 模板来修改被管理主机的配置文件。

ansible 使用 jinja2 模板需要借助 template 模块实现。

template 模块和 copy 模块完全一样,都是拷贝文件至远程主机,与copy的语法基本完全一致,区别在于template 模块会自动解析要拷贝的文件中变量的值,而 copy模块则是原封不动的将文件拷贝至被控端。

1.1 jinja2语法结构

  • 要想在配置文件中使用 jinj2playbook 中的 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使用jinja2if判断表达式渲染出keepalivedMasterSlave的配置文件。并推送至被控主机,实现方案如下:

  • 使用 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,检查 lvs01 Master 节点的 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语法及应用的更多相关文章

  1. ansible使用jinja2管理配置文件以及jinja2语法简介

    一.Jinja2介绍 Jinja2是基于python的模板引擎,功能比较类似于PHP的smarty,J2ee的Freemarker和velocity.它能完全支持unicode,并具有集成的沙箱执行环 ...

  2. Ansible系列(二):选项和常用模块

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  3. Ansible系列(五):playbook应用和roles自动化批量安装示例

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  4. Ansible系列(六):各种变量定义方式和变量引用

    本文目录:1.1 ansible facts1.2 变量引用json数据的方式 1.2.1 引用json字典数据的方式 1.2.2 引用json数组数据的方式 1.2.3 引用facts数据1.3 设 ...

  5. Ansible系列(四):playbook应用和roles自动化批量安装示例

    Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html playbook是ansible实现批量自动化最重要的手段.在其中可以使用变 ...

  6. Ansible系列(五):各种变量定义方式和变量引用

    Ansible系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 1.1 ansible facts facts组件是用来收集被管理节点信息的 ...

  7. Ansible系列(一):基本配置和使用

    本文目录:1.1 安装Ansible1.2 配置Ansible 1.2.1 环境配置 1.2.2 SSH互信配置 1.2.3 简单测试1.3 inventory Ansible是一种批量.自动部署工具 ...

  8. Ansible系列(三):YAML语法和playbook写法

    html { font-family: sans-serif } body { margin: 0 } article,aside,details,figcaption,figure,footer,h ...

  9. Ansible系列(六):循环和条件判断

    本文目录:1. 循环 1.1 with_items迭代列表 1.2 with_dict迭代字典项 1.3 with_fileglob迭代文件 1.4 with_lines迭代行 1.5 with_ne ...

  10. Ansible系列(七):执行过程分析、异步模式和速度优化

    本文目录:1.1 ansible执行过程分析1.2 ansible并发和异步1.3 ansible的-t选项妙用1.4 优化ansible速度 1.4.1 设置ansible开启ssh长连接 1.4. ...

随机推荐

  1. 学习Source Generators之输出生成的文件

    上一篇文章学习了通过获取和解析swagger.json的内容,来生成API的请求响应类. 但是其中无法移动与编辑. 那么本文将介绍如何输出生成的文件. EmitCompilerGeneratedFil ...

  2. #斯坦纳树,状压dp#洛谷 3264 [JLOI2015]管道连接

    题目 分析 如果对于每一个频道单独跑斯坦纳树可能会存在两种频道共用一条道路而重复统计的情况, 考虑状压dp,设\(f[s]\)表示选择频道二进制状态为\(s\)的最小贡献,那么对于每个状态跑斯坦纳树然 ...

  3. #树状数组,离散#C 波动序列

    分析 设\(dp[i][j][0/1/2/3]\)表示前\(i\)个位置当前选的数为\(j\), 且选择的是第一行/第二行/第三行不下降/第三行不上升, 状态转移方程显然,用线段树或者树状数组维护一下 ...

  4. #Splay#洛谷 1486 [NOI2004]郁闷的出纳员

    题目 分析 考虑加减工资直接打标记,查询第\(k\)多可以用平衡树, 删除有点恶心,这里考虑Splay,将需要删除的部分的后继splay到根节点并将左子树断边 代码 #include <cstd ...

  5. OpenHarmony亮相MTSC 2023 | 质量&效率共进,赋能应用生态发展

      11月25日,MTSC 2023第十二届中国互联网测试开发大会在深圳登喜路国际大酒店圆满举行.大会以"软件质量保障体系和测试研发技术交流"为主要目的,旨在为行业搭建一个深入探讨 ...

  6. 【开源三方库】crypto-js加密算法库的使用方法

     OpenAtom OpenHarmony(简称"OpenHarmony")三方库,是经过验证可在OpenHarmony系统上可重复使用的软件组件,可帮助开发者快速开发OpenHa ...

  7. Docker学习路线11:Docker命令行

    Docker CLI (命令行界面) 是一个强大的工具,可让您与 Docker 容器.映像.卷和网络进行交互和管理.它为用户提供了广泛的命令,用于在其开发和生产工作流中创建.运行和管理 Docker ...

  8. SpringBoot使用@Value注入静态属性

    说明:SpringBoot中使用yml文件配置自定义属性,读取配置文件属性注入到实体类中,属性值都为静态属性 配置文件:yml #用户信息 userMag: userName: "王小波&q ...

  9. HMS Core机器学习服务,高效助力跨语种沟通

    5月24日, HUAWEI Developer Day(简称HDD)线上沙龙·创新开发专场活动成功举办.HMS Core机器学习服务(ML Kit)产品经理在会上围绕机器翻译的技术优势.使用场景和接入 ...

  10. ssm 创建bean的三种方式和spring依赖注入的三种方式

    <!--创建bean的第一种方式:使用默认无参构造函数 在默认情况下: 它会根据默认无参构造函数来创建类对象.如果 bean 中没有默认无参构造函数,将会创建失败--> <bean ...