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. Qt信号槽

    Qt 信号槽 Qt的信号槽,除了使用信号连接槽,还可以信号连接信号,断开信号,发送(转发)信号. 一个信号可以连接一个槽,也可以一个信号连接多个槽,还可以多个信号连接一个槽.   // 信号连接槽 c ...

  2. 高并发报错too many clients already或无法创建线程

    高并发报错 too many clients already 或无法创建线程 本文出处:https://www.modb.pro/db/432236 问题现象 高并发执行 SQL,报错"so ...

  3. Java程序员常用英语整理

    基础----进阶 A. array数组accessible 可存取的 area面积audio 音频 addition 加法 action 行动 arithmetic 算法adjustment 调整 a ...

  4. 在 Google Cloud 上轻松部署开放大语言模型

    今天,我们想向大家宣布:"在 Google Cloud 上部署"功能正式上线! 这是 Hugging Face Hub 上的一个新功能,让开发者可以轻松地将数千个基础模型使用 Ve ...

  5. gRPC入门学习之旅(六)

    gRPC入门学习之旅(一) gRPC入门学习之旅(二) gRPC入门学习之旅(三) gRPC入门学习之旅(四) gRPC入门学习之旅(五) 3.3.客户端编译生成GRPC类 1. 在"解决方 ...

  6. 抓包整理————tcp 传输数据的基础概念[十一]

    前言 简单介绍一下tcp 数据传输. 正文 tcp 数据传输是怎么样子的呢? 比如我们在代码中写好了,connection 去连接. 然后我们用 write 去读取数据,这个时候呢,到底我们的操作系统 ...

  7. ActiveMQ c# 系列——进阶实例(三)

    前言 前面介绍了基本的消费者和生产者,那么看下他们之间有什么其他的api. 正文 消费者设置等待时间 生产者生产了5条消息 改一下消费者. static void Main(string[] args ...

  8. Go 单元测试之mock接口测试

    目录 一.gomock 工具介绍 二.安装 三.使用 3.1 指定三个参数 3.2 使用命令为接口生成 mock 实现 3.3 使用make 命令封装处理mock 四.接口单元测试步骤 三.小黄书Se ...

  9. web常见的攻击方式有哪些?如何防御?

    一.是什么 Web攻击(WebAttack)是针对用户上网行为或网站服务器等设备进行攻击的行为 如植入恶意代码,修改网站权限,获取网站用户隐私信息等等 Web应用程序的安全性是任何基于Web业务的重要 ...

  10. 使用C# 创建、填写、删除PDF表单域

    通常情况下,PDF文件是不可编辑的,但PDF表单提供了一些可编辑区域,允许用户填写和提交信息.PDF表单通常用于收集信息.反馈或进行在线申请,是许多行业中数据收集和交换的重要工具. PDF表单可以包含 ...