• Ansible之template模板


    模板是一个文本文件,可以做为生成文件的模版,并且模板文件中还可嵌套jinja2语法

    Jinja2 是一个现代的,设计者友好的,仿照 Django 模板的 Python 模板语言。 它速度快,被广泛使用,并且提供了可选的沙箱模板执行环境保证安全:

    特性:

    沙箱中执行
    强大的 HTML 自动转义系统保护系统免受 XSS
    模板继承
    及时编译最优的 python 代码
    可选提前编译模板的时间
    易于调试。异常的行数直接指向模板中的对应行。
    可配置的语法
    

    官方网站:

    http://jinja.pocoo.org/
    https://jinja.palletsprojects.com/en/2.11.x/
    

    官方中文文档

    http://docs.jinkan.org/docs/jinja2/
    https://www.w3cschool.cn/yshfid/
    

    jinja2 语言支持多种数据类型和操作:

    字面量,如: 字符串:使用单引号或双引号,数字:整数,浮点数
    列表:[item1, item2, ...]
    元组:(item1, item2, ...)
    字典:{key1:value1, key2:value2, ...}
    布尔型:true/false
    算术运算:+, -, *, /, //, %, **
    比较操作:==, !=, >, >=, <, <=
    逻辑运算:and,or,not
    流表达式:For,If,When
    
    字面量:

    表达式最简单的形式就是字面量。字面量表示诸如字符串和数值的 Python 对象。如"Hello World" 双引号或单引号中间的一切都是字符串。无论何时你需要在模板中使用一个字符串(比如函数调用、过滤器或只是包含或继承一个模板的参数),如42,42.23数值可以为整数和浮点数。如果有小数点,则为浮点数,否则为整数。在 Python 里, 42 和 42.0 是不
    一样的

    算术运算:

    Jinja 允许用计算值。支持下面的运算符

    +:把两个对象加到一起。通常对象是素质,但是如果两者是字符串或列表,你可以用这 种方式来衔接 它们。无论如何这不是首选的连接字符串的方式!连接字符串见 ~ 运算符。 {{ 1 + 1 }} 等于 2
    
    -:用第一个数减去第二个数。 {{ 3 - 2 }} 等于 1
    
    /:对两个数做除法。返回值会是一个浮点数。 {{ 1 / 2 }} 等于 0.5
    
    //:对两个数做除法,返回整数商。 {{ 20 // 7 }} 等于 2
    
    %:计算整数除法的余数。 {{ 11 % 7 }} 等于 4
    
    *:用右边的数乘左边的操作数。 {{ 2 * 2 }} 会返回 4 。也可以用于重 复一个字符串多次。 {{ '=' * 80 }}
    会打印 80 个等号的横条
    
    **:取左操作数的右操作数次幂。 {{ 2**3 }} 会返回 8
    

    比较操作符

    == 比较两个对象是否相等
    
    != 比较两个对象是否不等
    
    > 如果左边大于右边,返回 true
    
    >= 如果左边大于等于右边,返回 true
    
    < 如果左边小于右边,返回 true
    
    <= 如果左边小于等于右边,返回 true
    

    逻辑运算符

    对于 if 语句,在 for 过滤或 if 表达式中,它可以用于联合多个表达式
    
    and 如果左操作数和右操作数同为真,返回 true
    
    or 如果左操作数和右操作数有一个为真,返回 true
    
    not 对一个表达式取反
    
    (expr)表达式组
    
    true / false true 永远是 true ,而 false 始终是 false
    

    template

    template功能:可以根据和参考模块文件,动态生成相类似的配置文件

    template文件必须存放于templates目录下,且命名为 .j2 结尾
    yaml/yml 文件需和templates目录平级,目录结构如下示例:

    ./
    ├── temnginx.yml
    └── templates
    └── nginx.conf.j2
    

    范例:利用template 同步nginx配置文件

    # 准备templates/nginx.conf.j2文件
    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: template config to remote hosts
          template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
    

    执行

    [root@centos8 ~]# ansible-playbook tempngix.yml
    

    template变更替换 范例:

    # 修改文件nginx.conf.j2
    
    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: install nginx
          yum: name=nginx
        - name: template config to remote hosts
          template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
        - name: start service
          service: name=nginx state=started enabled=yes
    

    执行

    [root@centos8 ~]# ansible-playbook temnginx2.yml
    
    template算术运算

    范例:

    vim nginx.conf.j2
    worker_processes {{ ansible_processor_vcpus**2 }};
    worker_processes {{ ansible_processor_vcpus+2 }};
    

    范例:

    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: install nginx
          yum: name=nginx
        - name: template config to remote hosts
          template: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf
          notify: restart Nginx
        - name: start service
          service: name=nginx state=started enabled=yes
    
      handlers:
        - name: restart Nginx
          service: name=nginx state=restarted
    

    执行:目标主机只执行某一台

    [root@centos8 ~]# ansible-playbook temp2nginx.yml  --limit 172.31.0.38
    

    template中使用流程控制 for 和 if

    template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

    for 循环

    格式

    {% for i in EXPR %}
      ...
    {% endfor %}
    示例:
    {% for i in range(1,10) %}
      server_name web{{i}};
    {% endfor %}
    

    范例

    # tem3nginx.yml
    ---
    - hosts: websrvs
      remote_user: root
      vars:
        nginx_vhosts:
          - 81  
          - 82
          - 83
      tasks:
        - name: template config
          template: src=nginx.conf2.j2 dest=/data/nginx.conf
    
    # templates/nginx.conf2.j2
    {% for vhost in nginx_vhosts %}
    server {
        listen {{ vhost }}
    }
    {% endfor %}
    
    # 执行
    [root@centos8 ~]# ansible-playbook tem3nginx.yml --limit 172.31.0.48
    
    # 效果
    [root@centos8 ~]# cat /data/nginx.conf 
    server {
        listen 81
    }
    server {
        listen 82
    }
    server {
        listen 83
    }
    

    范例:

    # tem4nginx.yml
    ---
    - hosts: websrvs
      remote_user: root
      vars:
        nginx_vhosts:
          - listen 8080
      tasks:
        - name: config file
          template: src=nginx.conf3.j2 dest=/data/nginx3.conf
    
    # templates/nginx.conf3.j2
    {% for vhost in nginx_vhosts %}
    server{
      listen {{vhost.listen}}
    }
    {% endfor %}
    
    # 执行 注意:说是某台目标主机ip,但是必须是主机清单这个文件指定的这个组的ip才可以
    [root@centos8 ~]# ansible-playbook tem4nginx.yml --limit 172.31.0.38
    

    范例

    - hosts: websrvs
      remote_user: root
      vars:
        nginx_vhosts:
          - listen: 8080
            server_name: "web1.longxuan.vip"
            root: "/var/www/nginx/web1/"
          - listen: 8081
            server_name: "web2.longxuan.vip"
            root: "/var/www/nginx/web2/"
          - {listen: 8082, server_name: "web3.longxuan.vip", root: "/var/www/nginx/web3/"}
      tasks:
        - name: template config
          template: src=nginx.conf4.j2 dest=/data/nginx4.conf
    
    [root@centos8 /etc/ansible]# vim /root/templates/nginx.conf4.j2
    {% for vhost in nginx_vhosts %}
    server{
        listen {{ vhost.listen }}
        server_name {{ vhost.server_name }}
        root {{ vhost.root }}
    }
    {% endfor %}
    
    # 执行
    [root@centos8 /etc/ansible]# ansible-playbook tem5nginx.yml --limit 172.31.0.48
    
    # 效果
    [root@centos8 ~]# cat /data/nginx4.conf 
    server{
        listen 8080
        server_name web1.longxuan.vip
        root /var/www/nginx/web1/
    }
    server{
        listen 8081
        server_name web2.longxuan.vip
        root /var/www/nginx/web2/
    }
    server{
        listen 8082
        server_name web3.longxuan.vip
        root /var/www/nginx/web3/
    }
    

    范例:

    [root@centos8 /etc/ansible]# vim templates/nginx.conf5.j2
    upstream webserver{
    {% for in range(1,11) %}
      server 172.31.0.{{i}}:{{http_port}}
    {% endfor %}
    }
    
    server{
       listen {{http_port}};
       server_name {{server_name}};
       location / {
          proxy_pass http://webserver;
       }
    }
    
    [root@centos8 /etc/ansible]# vim tem6nginx.yml
    - hosts: websrvs
      vars:
        http_port: 80
        server_name: www.longxuan.vip
      tasks:
        - name: install nginx
          yum: name=nginx
        - name: config file
          template: src=nginx.conf5.j2 dest=/etc/nginx/conf.d/web_proxy.conf
        - name: start nginx
          service: name=nginx state=started
    
    # 执行
    [root@centos8 /etc/ansible]# ansible-playbook tem6nginx.yml
    

    范例

    # nginx.conf6.j2
    upstream webservers {
    {% for in groups['webservers] %}
      server {{i}}:{{http_port}}
    {% endfor %}
    vim hosts
    [webservers]
    172.31.0.101
    172.31.0.102
    

    if 条件判断

    在模版文件中还可以使用if条件判断,决定是否生成相关的配置信息

    范例:

    #templnginx6.yml
    - hosts: websrvs
      remote_user: root
      vars:
        nginx_vhosts:
          - web1:
            listen: 8080
            root: "/var/www/nginx/web1/"
          - web2:
            listen: 8080
            server_name: "web2.magedu.com"
            root: "/var/www/nginx/web2/"
          - web3:
            listen: 8080
            server_name: "web3.magedu.com"
            root: "/var/www/nginx/web3/"
      tasks:
        - name: template config to
          template: src=nginx.conf5.j2 dest=/data/nginx5.conf
    
    #templates/nginx.conf6.j2
    {% for vhost in nginx_vhosts %}
    server {
         listen {{ vhost.listen }}
         {% if vhost.server_name is defined %}
    server_name {{ vhost.server_name }} #注意缩进
         {% endif %}
    root {{ vhost.root }} #注意缩进
    }
    {% endfor %}
    
    #生成的结果
    server {
    listen 8080
    root /var/www/nginx/web1/
    }
    server {
    listen 8080
    server_name web2.magedu.com
    root /var/www/nginx/web2/
    }
    server {
    listen 8080
    server_name web3.magedu.com
    root /var/www/nginx/web3/
    }
    

    范例: 生成keepalived配置文件

    vrrp_instrance VI_1 {
    {% if ansible_fqdn == "ka1" %}
      state MASTER
      priority 100
    {% elif ansible_fqdn == "ka2" %}
      state SLAVE
      priority 80
    {% endif% }
    ......
    }
    

    使用循环迭代

    迭代:当有需要重复性执行的任务时,可以使用迭代机制

    迭代 with_items(loop)

    对迭代项的引用,固定内置变量名为"item"

    要在task中使用with_items给定要迭代的元素列表

    注意: ansible2.5版本后,可以用loop代替with_items

    列表元素格式:
    字符串
    字典

    范例:

    [root@centos8 /etc/ansible]# cat item.yml 
    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: add serveral user
          user: name={{item}} state=present group=wheel
          with_items:
            - testuser1
            - testuser2
            - testuser3
            
    # 执行
    [root@centos8 /etc/ansible]# ansible-playbook item.yml
    

    范例:卸载 mariadb

    ---
    # remove mariadb server
    - hosts: appsrvs:!10.0.0.8
      remote_user: root
      tasks:
        - name: stop service
          shell: /etc/init.d/mysqld stop
        - name: delete files and dir
          file: path={{item}} state=absent
          with_items:
            - /usr/local/mysql
            - /usr/local/mariadb-10.2.27-linux-x86_64
            - /etc/init.d/mysqld
            - /etc/profile.d/mysql.sh
            - /etc/my.cnf
            - /data/mysql
        - name: delete user
          user: name=mysql state=absent remove=yes
    

    范例:

    ---
    - hosts:websrvs
      remote_user: root
      tasks
        - name: install some packages
          yum: name={{ item }} state=present
          with_items:
            - nginx
            - mysql
            - php-fpm
    

    范例:

    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: copy file
          copy: src={{ item }} dest=/tmp/{{ item }}
          with_items:
            - file1
            - file2
            - file3
        - name: yum install httpd
          yum: name={{ item }} state=present
          with_items:
            - apr
            - apr-util
            - httpd
    

    迭代嵌套子变量

    在迭代中,还可以嵌套子变量,关联多个变量在一起使用

    示例:

    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: add some groups
          group: name={{ item }} state=present
          with_items:
            - nginx
            - mysql
            - apache
        - name: add some users
          user: name={{ item.user }} group={{ item.group }} uid={{item.uid}} state=present
          with_items:
            - { user: 'nginx', group: 'nginx',uid: "80" }
            - { user: 'mysql', group: 'mysql' ,uid: "306" }
            - { user: 'apache', group: 'apache',uid: "8080" }
    

    执行

    [root@centos8 /etc/ansible]# ansible-playbook with_item.yml
    

    范例:

    [root@ansible ~]# cat with_item2.yml
    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: add some groups
          group: name={{ item }} state=present
          with_items:
            - g1
            - g2
            - g3
        - name: add some users
          user: name={{ item.name }} group={{ item.group }} home={{ item.home }} create_home=yes state=present
          with_items:
            - { name: 'user1', group: 'g1', home: '/data/user1' }
            - { name: 'user2', group: 'g2', home: '/data/user2' }
            - { name: 'user3', group: 'g3', home: '/data/user3' }
    

    范例:

    # ansible-doc file
    - name: Create two hard links
      file:
        src: '/tmp/{{ item.src }}'
        dest: '{{ item.dest }}'
        state: hard
      loop:
        - { src: x, dest: y }
        - { src: m, dest: n }
    

    范例:

    - hosts: websrvs
      vars:
        rsyncd_conf: /etc/rsync.conf
        rsync_pass: /etc/rsync.pass
      tasks:
        - name: Configure Rsyncd Service
          template: src={{ item.src }} dest={{ item.dest }} mode={{ item.mode }}
          with items:
            - {src: './rsyncd.conf.j2', dest: {{ rsyncd_conf }}, mode: 0644 }
            - {src: './rsync.pass.j2', dest: {{ rsync_pass }}, mode: 0600 }
    

    范例: 批量修改用户密码

    ---
    - hosts: ssh-host    #这个主机清单一定要存在
      gather_facts: false
      tasks:
        - name: change user passwd
          user: name={{ item.name }} password={{ item.chpass | password_hash('sha512')}} update_pass
    word=always
          with_items:
            - { name: "root",chpass: '123456' }
            - { name: "app",chpass: "654321" }
    

    执行

    [root@centos8 /etc/ansible]# ansible-playbook ssh-host.yml
    

    until 循环

    范例: until 循环

    # until为false时才会执行循环,为true则退出循环
    [root@centos8 /etc/ansible]# vim until.yml
    - hosts: websrvs
      gather_facts: false
      tasks:
        - debug: msg="until"
          until: false
          retries: 3  # 默认值即3次
          delay: 1
    

    with_lines 逐行处理

    范例: with_lines 逐行处理

    [root@ansible ansible]#cat with_lines.yml
    - hosts: localhost
      tasks:
        - debug: msg={{ item }}
          with_lines: ps aux
    

    playbook使用 when

    when语句可以实现条件测试。如果需要根据变量、facts或此前任务的执行结果来做为某task执行与否的前提时要用到条件测试,通过在task后添加when子句即可使用条件测试,jinja2的语法格式

    范例:条件判断

    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: "shutdown RedHat flavored systems"
          command: /sbin/shutdown -h now
          when: ansible_os_family=="RedHat"
    

    范例: 判断服务状态决定是否重新启动

    [root@localhost ~]# vim when2.yml
    ---
    - hosts: websrvs
      tasks:
        - name: check nginx service  # 检查nginx服务是否是活动的
          command: systemctl is-active nginx
          ignore_errors: yes
          register: check_nginx
        - name: httpd restart     # 如果check nginx执行命令结果成功,即check_nginx.rc等于0,则执
    行重启nginx,否则跳过
          service: name=nginx state=restarted
          when: check_nginx.rc == 0
    

    范例: when的列表形式表示 and 关系

    ---
    - hosts: all
      tasks:
        - name: "shutdown centos 7 systems"
          reboot:
          when:   
            - ansible_facts['distribution'] == "CentOS"
            - ansible_facts["distribution_major_version"] == "7"
    

    范例: 和循环一起使用

    - hosts: websrvs
      tasks:
        - debug: msg="item > 3"
          with_items: [1,2,3,4,5,6]
          when: item > 3
    

    范例: failed_when 满足条件时,使任务失败,和when功能相反

    tasks:
      - command: echo failed
        register: result
        failed_when: "'failed' in result.stdout"
        #failed_when: false 不满足条件,任务正常执行
        #failed_when: true 满足条件,使用任务失败
      - debug: msg="echo failed_when"
    

    范例:

    ---
    - hosts: websrvs
      remote_user: root
      tasks:
        - name: install conf file to centos7
          template: src=nginx.conf.c7.j2 dest=/etc/nginx/nginx.conf
          when: ansible_distribution_major_version == "7"
        - name: install conf file to centos6
          template: src=nginx.conf.c6.j2 dest=/etc/nginx/nginx.conf
          when: ansible_distribution_major_version == "6"
    

    分组 block

    当想在满足一个条件下,执行多个任务时,就需要分组了。而不再每个任务都是用when

    [root@ansible ansible]# cat block.yml
    ---
    - hosts: localhost
      tasks:
        - block:
            - debug: msg="first"
            - debug: msg="second"
          when:
            - ansible_facts['distribution'] == "CentOS"
            - ansible_facts['distribution_major_version'] == "8"
    

    changed_when

    利用 changed_when 检查task返回结果

    changed_when 检查task返回结果,决定是否继续向下执行

    [root@ansible ansible]# cat test_changed_when.yml
    ---
    - hosts: websrvs
      tasks:
        - name: install nginx
          yum: name=nginx
        - name: config file
          template: src="nginx.conf.j2" dest="/etc/nginx/nginx.conf"
          notify: restart nginx
        - name: check config
          shell: /usr/sbin/nginx -t
          register: check_nginx_config
          changed_when:
            - (check_nginx_config.stdout.find('successful'))  #如果执行结果中有successful字符串,则继续执行,如果没有则停止向下执行
            - false   #nginx -t 每次成功执行是changed状态,关闭此changed状态
        - name: start service
          service: name=nginx state=started enabled=yes
      handlers:
        - name: restart nginx
          service: name=nginx state=restarted
    

    关闭 changed 状态

    当确定某个task不会对被控制端做修改时但执行结果却显示是黄色的changed状态,可以通过
    changed_when: false 关闭changed状态

    [root@ansible ansible]# cat test_changed.yml
    ---
    - hosts: websrvs
      tasks:
        - name: check sshd service
          shell: ps aux| grep sshd
          changed_when: false  #关闭changed状态
    

    滚动执行

    管理节点过多导致的超时问题解决方法
    默认情况下,Ansible将尝试并行管理playbook中所有的机器。对于滚动更新用例,可以使用serial关键字定义Ansible一次应管理多少主机,还可以将serial关键字指定为百分比,表示每次并行执行的主机数占总数的比例

    范例:

    [root@ansible ansible]# vim test_serial.yml
    ---
    - hosts: all
      serial: 2    #每次只同时处理2个主机,将所有task执行完成后,再选下2个主机再执行所有task,直至所有主机
      gather_facts: False
      tasks:
        - name: task one
          comand: hostname
        - name: task two
          command: hostname
    

    范例:

    - name: test serail
      hosts: all
      serial: "20%"  #每次只同时处理20%的主机
    

    范例:

    [root@ansible ansible]# cat test_serial.yml
    ---
    - hosts: websrvs
      serial: 1
      tasks:
        - name: task1
          shell: wall "{{ansible_nodename}} is running task1"
        - name: task2
          shell: wall "{{ansible_nodename}} is running task2"
        - name: task3
          shell: wall "{{ansible_nodename}} is running task3"
    

    委派至其它主机执行

    利用委托技术,可以在非当前被控主机的其它主机上执行指定操作

    范例:

    [root@ansible ~]# cat delegate.yml
    #在172.31.0.8上执行hostname -I,而非当前主机localhost
    - hosts: localhost
      tasks:
        - name: show ip address
          command: hostname -I
          delegate_to: 172.31.0.8
    

    范例:

    #在本地执行ifconfig,而非172.31.0.8
    [root@ansible ~]# cat delegate2.yml
    - hosts: 172.31.0.8
      tasks:
        - name: show ip address
          local_action: command ifconfig
    

    只执行一次

    利用 run_once 指令可以只执行一次,而非在所有被控主机都执行

    [root@ansible ~]# cat run_once.yml
    - hosts: websrvs
      tasks:
        - command: hostname
          run_once: true
          
    [root@ansible ~]# ansible-playbook run_once.yml --list-hosts
    playbook: run_once.yml
      play       #1 (websrvs): websrvs TAGS: []
        pattern: ['websrvs']
        hosts (2):
          172.31.0.8
          172.31.0.7
    [root@ansible ~]# ansible-playbook run_once.yml
    

    环境变量

    临时修改环境变量

    [root@ansible ~]# cat environment.yml
    - hosts: localhost
      tasks:
        - shell: echo $PATH
          environment:
            PATH: /usr/local/app/bin:{{ ansible_env.PATH }}
            
    [root@ansible ~]# ansible-playbook environment.yml -v
    

    wait_for 等待条件再执行

    #等待端口可用,才能执行任务
    #暂停10s等待端口80打开,否则出错
    wait_for: port=80 delay=10
    #等待直到锁定文件被删除
    wait_for: path=/var/lock/file.lock state=absent
    

    yaml文件的相互调用

    利用include 或 include_tasks可以在某个task中调用其它的只有task内容的yaml文件

    [root@ansible ansible]# cat a.yml
    ---
    - hosts: websrvs
      tasks:
        - name: run a job
          command: wall run a job
        - name: excute b.yml
          include: b.yml       #调用另一个yaml文件
          #include_tasks: b.yml #另一种写法
          
    [root@ansible ansible]# cat b.yml
    - name: run b job
      command: wall run b job
    

    也可以将多个包含完整内容的yml文件由一个yml统一调用

    [root@ansible ansible]# cat total_tasks.yml
    - import_playbook: testks1.yml
    - import_playbook: testks2.yml
    
    [root@ansible ansible]# cat testks1.yml
    ---
    - hosts: websrvs
      tasks:
        - name: run testk1 job
          command: wall run testk1 job
    
    [root@ansible ansible]# cat testks2.yml
    ---
    - hosts: websrvs
      tasks:
        - name: run testk2 job
          command: wall run testk2 job
    
  • 相关阅读:
    samba安装和配置
    linux下打包命令的使用
    Linux目录结构简析
    Linux服务器的安装
    linux下定时任务设置
    创建表空间并授权
    selenium2.0(WebDriver) API
    selenium + python之元素定位
    Linux实战教学笔记13:定时任务补充
    Linux实战教学笔记11:linux定时任务
  • 原文地址:https://www.cnblogs.com/xuanlv-0413/p/14815170.html
Copyright © 2020-2023  润新知