美文网首页
ansible使用笔记(三)Jinja2模板及playbook简

ansible使用笔记(三)Jinja2模板及playbook简

作者: Bigyong | 来源:发表于2020-11-20 16:41 被阅读0次

    ansible playbook编写

    目录
    一、Jinja2模板简介
    二、playbook简介
    三、playbook编写
    四、playbook进阶

    • 4.1 变量
    • 4.2 error处理
    • 4.3 tags标签
    • 4.4 handlers
    • 4.5 when条件判断
    • 4.6 register返回值
    • 4.7 with_items 循环
    • 4.8 include
    • 4.9 debug调试

    一、Jinja2模板简介
    Jinja2是什么
    Jinja2是基于Python的模板引擎,包含变量和表达式两部分,两者在模板求值时会被替换为值,模板中还有标签,控制模板的逻辑

    为什么要学习Jinja2模板
    因为playbook的模板使用Python的Jinja2模块来处理

    Jinja2模版的基本语法

    • 模板的表达式都是包含在他要分隔符"{{}}"内的
    • 控制的语句都是包含在分隔符"{% %}"内的
    • 模板支持注释,都是包含在分隔符'{# #}'内,支持块注释
    • 调用变量
      {{varname}}
    • 计算
      {{2+2}}
    • 判断
      {{1 in {{1,2,3}}
    • Jinja2模版控制语句
    {% if name == '诗仙' %}
      李白
    {% elif name == '诗圣' %}
      杜甫
    {% elif name == '诗魔' %}
      白居易
    {% else %}
      李贺
    {% endif %}
    

    Jinja2过滤器
    变量可以通过过滤器修改,过滤器与变量用管道符号( | )分割,也可以用圆括号传递可选参数,多个过滤器可以链式调用,前一个过滤器的输出会被作业后一个过滤器的输入

    例如:
    加密一个字符串:{{'astr'|password_hash('sha512')}}

    二、playbook简介
    playbook是什么
    playbook是ansible用于配置,部署和管理托管主机剧本,通过playbook的详细描述,执行其中一系列tasks,可以让远端主机达到预期的状态

    也可以说 playbook字面意思即剧本,现实中由演员按剧本表演,在ansible中由计算机进行安装,部署应用,提供对外服务,以及组织计算机处理各种各样的事情

    为什么要使用palybook

    • 执行一些简单的任务,使用ad-hoc命令可以方便的解决问题,但有时一个设施过于复杂时,执行ad-hoc命令是不合适的,最好使用playbook

    • playbook可以反复使用编写的代码,可以放到不同机器上面,像函数一样,最大化的利用代码,在使用ansible的过程中,处理的大部分操作都是在编写playbook

    playbook语法基础(1)

    • playbook由YAML语文编写,遵循YAML标准
    • 在同一行中,#之后的内容表示注释
    • 同一个列表中元素应该保持相同缩进
    • playbook由一个或多个play组成
    • play中host,variables,roles,tasks等对角表示方法都是键值中间以": "分隔表示
    • YAML还有一个小的怪癖,它的文件开始行都是以 ---,这是YAML格式的一部分,表明一个文件的开始

    playbook构成

    • hosts: 定义交要执行playbook的远程主机级
    • vars: 定义playbook运行时需要使用的变量
    • tasks: 定义将要远程主机上执行的任务列表
    • handlers: 定义task执行完成以后需要调用的任务

    playbook执行结果
    使用ansible-playbook运行playbook文件,输出内容为JSON格式,由不同颜色组成便于识别

    • 绿色代表执行成功
    • 黄色 代表系统状态发生改变
    • 红色代表执行失败

    ansible具有幂等性,幂等性能够保证我们重复的执行一项操作时,得到的结果是相同的,我们再来回顾一下幂等性的概念

    "幂等性"是什么意思呢?举个例子,你想把一个文件拷贝到目标主机的某个目录上,但是你不确定此目录中是否已经存在此文件,当你使用ansible完成这项任务时,就非常简单了,因为如果目标主机的对应目录中已经存在此文件,那么ansible则不会进行任何操作,如果目标主机的对应目录中并不存在此文件,ansible就会将文件拷贝到对应目录中,说白了,ansible是"以结果为导向的",我们指定了一个"目标状态",ansible会自动判断,"当前状态"是否与"目标状态"一致,如果一致,则不进行任何操作,如果不一致,那么就将"当前状态"变成"目标状态",这就是"幂等性","幂等性"可以保证我们重复的执行同一项操作时,得到的结果是一样的。

    有了幂等性的概念上面显示颜色代表的不同结果就比较好理解了

    • 绿色 代表执行成功 结果已经和指定"目标状态"一致不需要修改
    • 黄色 执行成功,系统状态发生改变,修改过"目标状态"
    • 红色代表执行失败

    三、playbook编写
    使用ping模块编写 第一个playbook

    [root@ansible default]# cat ping.yml 
    ---                   #第一行,表示开始
    - hosts: all          #远程主机,多个可以用逗号孙隔开
      remote_user: root   #远程执行的用户名
      tasks:
      - name: ping test   #任务名称,你也可以理解为备注信息,会在执行中显示,方便阅读
        ping:             #模块名ping
    
    [root@ansible default]# ansible-playbook ping.yml -f 5    #-f 并发进程数量,默认是5
    
    PLAY [all] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [cache]
    ok: [web1]
    ok: [web2]
    ok: [db2]
    ok: [db1]
    
    TASK [ping test] ************************************************************************************
    ok: [cache]
    ok: [web1]
    ok: [web2]
    ok: [db1]
    ok: [db2]
    
    PLAY RECAP ******************************************************************************************
    cache                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    db1                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    db2                        : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    playbook语法基础(2)

    • tasks
      命令的集合
      每一个play包含一个task列表(任务列表)
      一个task在其所对应的所有主机上(通过hosts pattern匹配的所有主机) 执行完毕之后,下一个task才执行
    • hosts
      主机的集合
      定义要执行的主机

    案例1:
    实现 给web主机添加用户james
    设置默认密码123456,并把james用户添加到users组

    [root@ansible default]# cat user.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
        - name: Add the user 'james'
          user:
            name: james
            groups: users 
        - name: set passwd
          shell: echo 123456|passwd --stdin james
    
    [root@ansible default]# ansible-playbook user.yml 
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [Add the user 'james'] *************************************************************************
    changed: [web1]
    changed: [web2]
    
    TASK [set passwd] ***********************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0
    

    案例2:
    要求:
    1.所以web主机安装Apache
    2.修改配置文件的监听端口为8080
    3.设置默认页面hello world
    4.启动服务
    5.设置开机自启

    1) 先在本面准备默认访问

    [root@ansible default]# cat /root/index.htm
    hello world
    

    2)编号playbook

    [root@ansible default]# cat http.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:                                         
         - name: install one specific version of Apache   //tasks01.安装 
           yum:
             name: httpd
             state: installed
         - lineinfile:                               //tasks02.修改监听端口
               path: /etc/httpd/conf/httpd.conf
               regexp: '^Listen'
               line: 'Listen 8080'
         - copy:                                  //tasks03替换主页index.html
             src: /root/index.html
             dest: /var/www/html/index.html
         - service:                             //tasks04.开启服务 
             name: httpd
             enabled: yes
             state: restarted
    [root@ansible default]# ansible-playbook http.yml 
    
    PLAY [web] ***********************************************************************************************************************
    
    TASK [Gathering Facts] ***********************************************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [install one specific version of Apache] ************************************************************************************
    
    changed: [web2]
    changed: [web1]
    
    TASK [lineinfile] ****************************************************************************************************************
    changed: [web1]
    changed: [web2]
    
    TASK [copy] **********************************************************************************************************************
    changed: [web2]
    changed: [web1]
    
    TASK [service] *******************************************************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP ***********************************************************************************************************************
    web1                       : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=5    changed=4    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    [root@ansible default]# curl web1:8080    //测试
    holle world
    

    四、playbook进阶
    4.1 变量
    案例3:

    要求:添加用户 使用变量username代替
    给web主机添加用户james2,设置默认密码123456

    [root@ansible default]# cat user2.yml 
    ---
    - hosts: web
      remote_user: root
      vars:
        username: james2
      tasks:
        -
          name: Add the user  "{{username}}"
          user: 
            name: "{{username}}"
        -
          shell: echo 123456|passwd --stdin "{{username}}"
    
    [root@ansible default]# ansible-playbook user2.yml 
    
    PLAY [web] ************************
    
    ......
    

    用户设密码
    作完以上的实验你肯定已经发现为什么不用user模块直接设置密码,而且用shell模块单独设置,这是因为user模块是把Password字符串直接写入shadow,并没有改变,而Linux的shadow密码是经过加密的,所以明文密码不能直接使用

    解决方案
    -使用变量过滤器password_hash
    {{'urpassword'|password_hash('sha512')}}

    最后的playbook如下

    [root@ansible default]# cat user3.yml 
    ---
    - hosts: web
      remote_user: root
      vars:
        username: james2
      tasks:
        - name: Add the user "{{username}}"
          user: 
            name: "{{username}}"
            group: root
            password: "{{'123qqq...A'|password_hash('sha512')}}"
    

    变量参数
    -e 传递变量或文件参数
    -e @文件
    文件的格式必须是YAML或JSON格式

    [root@ansible default]# ansible-playbook user3.yml -e username=james4
    
    PLAY [web] *******************************************************************************************
    
    TASK [Gathering Facts] *******************************************************************************
    ok: [web2]
    ok: [web1]
    
    TASK [Add the user "james4"] *************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP *******************************************************************************************
    web1                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0 
    web2                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0 
    
    [root@ansible default]# ssh web1 id james4
    uid=1007(james4) gid=0(root) 组=0(root)
    
    [root@ansible default]# cat username.yml 
    ---
    username:
      james5
    
    [root@ansible default]# ansible-playbook user3.yml -e @username.yml
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [Add the user "james5"] ************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    [root@ansible default]# cat username.yml 
    ---
    username:
      james5
    [root@ansible default]# ssh web1 id james5
    uid=1008(james5) gid=0(root) 组=0(root)
    

    4.2 error 处理 ansible-playbook对错误的处理
    因为playbook是顺序执行,当遇到错误就会停止往下执行,默认情况判断上一个任务$?,如果值不为0就停止执行
    但某些情况我们需要忽略错误继续执行

    案例4:
    要求:
    创建缓存目录,然后重启 apache
    1.因为 /tmp/web 之前已经存在 shell模块 mkdir报错playbook停止继续执行,但其实这个错误是不影响下面的任务执行

    [root@ansible default]# cat Restart.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
      - shell: mkdir /tmp/web
      - name: ReStart service httpd
        service:
          name: httpd
          state: restarted
    
    [root@ansible default]# ansible-playbook Restart.yml 
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web2]
    ok: [web1]
    
    TASK [shell] ****************************************************************************************
    [WARNING]: Consider using the file module with state=directory rather than running 'mkdir'.  If you
    need to use command because file is insufficient you can add 'warn: false' to this command task or
    set 'command_warnings=False' in ansible.cfg to get rid of this message.
    fatal: [web2]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.008765", "end": "2020-11-19 16:55:04.967697", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 16:55:04.958932", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
    fatal: [web1]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.007319", "end": "2020-11-19 16:55:05.751981", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 16:55:05.744662", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
    web2                       : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
    

    错误处理方法:
    添加错误选项:ignore_errors
    True 表示忽略错误继续执行
    False 表示遇到错误就停止执行(默认)

    [root@ansible default]# cat Restart.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
      - shell: mkdir /tmp/web
        ignore_errors: True
      - name: ReStart service httpd
        service:
          name: httpd
          state: restarted
    
    [root@ansible default]# ansible-playbook Restart.yml 
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [shell] ****************************************************************************************
    [WARNING]: Consider using the file module with state=directory rather than running 'mkdir'.  If you
    need to use command because file is insufficient you can add 'warn: false' to this command task or
    set 'command_warnings=False' in ansible.cfg to get rid of this message.
    fatal: [web2]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.007426", "end": "2020-11-19 17:01:57.077906", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 17:01:57.070480", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
    ...ignoring
    fatal: [web1]: FAILED! => {"changed": true, "cmd": "mkdir /tmp/web", "delta": "0:00:00.014932", "end": "2020-11-19 17:01:57.853702", "msg": "non-zero return code", "rc": 1, "start": "2020-11-19 17:01:57.838770", "stderr": "mkdir: 无法创建目录\"/tmp/web\": 文件已存在", "stderr_lines": ["mkdir: 无法创建目录\"/tmp/web\": 文件已存在"], "stdout": "", "stdout_lines": []}
    ...ignoring
    
    TASK [ReStart service httpd] ************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
    web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=1   
    

    4.3 tags标签
    tags:给指定的任务定义一个调用标识 有时把多个模块写在一个playbook中.但只想用到其中一个或其中几个模块

    -使用方法在模块里添加tags标签
    -playbook调用方式
    -t TAGS, --tags=TAGS
    案例5:
    要求:调用任务 task03 创建文件

    [root@ansible default]# cat tags2.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
        - name: task01
          file:
            path: /tmp/web/task01
            state: touch
          tags: t1
        - name: task02
          file:
            path: /tmp/web/task02
            state: touch
          tags: t2
        - name: task03
          file:
            path: /tmp/web/task03
            state: touch
          tags: t3
    
    [root@ansible default]# ansible-playbook tags2.yml -t t3
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web2]
    ok: [web1]
    
    TASK [task03] ***************************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    [root@ansible default]# ssh web1 ls /tmp/web/
    task03
    

    4.4 handlers
    当关注的资源发生变化时采取的操作
    notify这个action可用于每个play的最后触发,这样就可以避免有多次改变发生时每次都执行指定的操作,取而代之仅在所有的变化发生完成后一次性执行指定操作

    在notify中列出的操作称为handler,即notify调用handler中定义的操作

    我们还是拿上面的httpd服务举例
    案例6:
    要求:
    修改httpd 默认index.html 然后重启httpd服务

    [root@ansible default]# cat RestartHttp.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
      - copy:
          src: /root/index.html
          dest: /var/www/html/index.html
        ignore_errors: True
      - name: ReStart service httpd
        service:
          name: httpd
          state: restarted
    
    [root@ansible default]# ansible-playbook RestartHttp.yml 
    
    PLAY [web] *******************************************************************************************************************************************************************************************************
    
    TASK [Gathering Facts] *******************************************************************************************************************************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [copy] ******************************************************************************************************************************************************************************************************
    changed: [web2]
    changed: [web1]
    
    TASK [ReStart service httpd] *************************************************************************************************************************************************************************************
    changed: [web2]
    changed: [web1]
    
    PLAY RECAP *******************************************************************************************************************************************************************************************************
    web1                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    第二次执行相同操作

    [root@ansible default]# ansible-playbook RestartHttp.yml 
    

    第二次和第一次执行的区别是没有在拷贝文件,因为第一次已经拷贝过了,但服务还是重启过两次,看上去好像没问题,但细想第二次文件没有改动过,和我们修改配置文件后重启服务的实际需求是有区别的,或者说第二次服务重次是完全没有必要的

    这时就要用的notify调用handler中定义的操作
    简单说就是当文件发生过改动后,才重启服务

    修改配置后

    [root@ansible default]# cat RestartHttp.yml
    ---
    - hosts: web
      remote_user: root
      tasks:
      - copy:
          src: /root/index.html
          dest: /var/www/html/index.html
        ignore_errors: True
        notify:
        - restart "ReStart service httpd"
        
      handlers:
      - name: ReStart service httpd
        service:
          name: httpd
          state: restarted
    
    [root@ansible default]# ansible-playbook RestartHttp.yml 
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web2]
    ok: [web1]
    
    TASK [copy] *****************************************************************************************
    ok: [web1]
    ok: [web2]
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    web2                       : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    从执行结果来看 并没有重启httpd服务

    4.5 when条件判断
    有些时候需要在满足特定条件后再触发某一项操作,或在特定的条件下终止某个行为,这时候需要进行条件判断,when正是解决这个问题的最佳选择,行程中的系统变量facts作为when的条件,可以通过setup模块查看

    案例7:
    我们用debug模块做个测试 debug模块我们后面会讲到
    通过两个when判断条件如果成立,则输出"System release is centos7"

    [root@ansible default]# cat when.yml 
    ---
    - hosts: cache
      remote_user: root
      tasks:
      - debug:
          msg: "System release is centos7"
        when:
        - ansible_distribution == "CentOS"
        - ansible_distribution_major_version == "7"
    
    [root@ansible default]# ansible-playbook when.yml 
    
    PLAY [cache] ****************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [cache]
    
    TASK [debug] ****************************************************************************************
    ok: [cache] => {
        "msg": "System release is centos7"
    }
    
    PLAY RECAP ******************************************************************************************
    cache                      : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    

    4.6 register返回值
    有时候我们还需要更复杂的例子,如判断前一个命令的执行结果去处理后面的操作,这时候就需要register模块来保存前一个命令的返回状态,在后面进行调用

    案例8:
    要求:把系统负载太高的Apache服务停止
    当系统负载超过0.7时,则关掉httpd

    [root@web2 ~]# awk 'BEGIN{while(1){}}'    //先用awk对web2提高系统负载,为测试创建条件
    
    [root@ansible default]# ssh web2 uptime   //已经满足测试条件
     11:10:11 up 24 days, 17:47,  2 users,  load average: 0.88, 0.30, 0.14
    
    root@all (5)[f:5]$ sys
    [root@ansible default]# ansible-console web   //通过ansible-console 查看httpd状态
    Welcome to the ansible console.
    Type help or ? to list commands.
    
    root@web (2)[f:5]$ systemctl status httpd
    web1 | CHANGED | rc=0 >>
    ● httpd.service - The Apache HTTP Server
       Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
       Active: active (running) since 四 2020-11-19 17:58:04 CST; 17h ago
    ......
    
    web2 | CHANGED | rc=0 >>
    ● httpd.service - The Apache HTTP Server
       Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
       Active: active (running) since 四 2020-11-19 17:58:03 CST; 17h ago
    ....
    
    root@web (2)[f:5]$ exit
    
    [root@ansible default]# cat when.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
      - shell: uptime|awk '{printf("%.2f\n",$(NF-2))}'
        register: result                                      //返回shell执行结果到变量result
      - name: stop  service
        service:
          name: httpd
          state: stopped
        when: result.stdout|float > 0.7                //对result 结果进行判断
    
    [root@ansible default]# ansible-playbook when.yml 
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [shell] ****************************************************************************************
    changed: [web1]
    changed: [web2]
    
    TASK [stop  service] ********************************************************************************
    skipping: [web1]
    changed: [web2]
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
    web2                       : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
    
    [root@ansible default]# ssh web2 systemctl status httpd
    ● httpd.service - The Apache HTTP Server
       Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
       Active: inactive (dead) since 五 2020-11-20 11:24:23 CST; 41s ago    //httpd服务已关闭
    ......
    

    4.7 with_items 循环
    with_items是playbook标准循环,可以用于迭代一个列表或字典,通过{{item}}获取每次迭代的值
    案例9:
    要求:一次性创建多个用户nb、aa、plj、lx

    [root@ansible default]# cat adduser.yml 
    ---
    - hosts: cache
      remote_user: root
      tasks:
      - name: add users
        with_items: ["nb","aa","plj","lx"]
        user: group=wheel password={{'123456'|password_hash('sha512')}} name={{item}}
    [root@ansible default]# ansible-playbook adduser.yml 
    
    PLAY [cache] ****************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [cache]
    
    TASK [add users] ************************************************************************************
    changed: [cache] => (item=nb)
    changed: [cache] => (item=aa)
    changed: [cache] => (item=plj)
    changed: [cache] => (item=lx)
    
    PLAY RECAP ******************************************************************************************
    cache                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
    

    4.8 include
    在编写playbook的时候随随着项目越来越大,playbook越来越复杂,修改也很麻烦,这时可以把一些paly、task或handler放到其他文件中,通过include指令包含进来是一个不错的选择
    包含项包括

    • vars:变量层
    • tasks:任务层
    • handlers:触发条件
    • files:文件
    • template:模板
    • default:默认,优先级最低

    案例10:
    把任务层独立出来

    [root@ansible default]# cat include1.yml 
    ---
    - hosts: cache
     remote_user: root
     tasks:
     - include: in3.yml    
       when: 2 > 1
    
    [root@ansible default]# cat in3.yml 
    - debug:
       msg: "task1 in in3.yml"
    - debug:
       msg: "task2 in in3.yml"
    
    [root@ansible default]# ansible-playbook include1.yml
    

    4.9 debug调试
    如果对于Python语法不熟悉的,playbook书写起来容易出错,且排错困难,这里介绍几种简单的排错调试方式

    检测语法

    • ansible-playbook --syntax-check playbook.ymal
      显示受到影响的主机
    • --list-hosts
      显示工作的task
    • --list-tasks
      显示将要运行的tag
    • --list-tags

    测试运行
    模拟运行结果,但如果在任务列表中,任务2 需要任务1执行的结果,那么任务2可能会报错,因为任务1没有实际执行

    • ansible-playbook -C playbook.yaml

    还可以在运行时输出更为详细的信息,帮助排错 比如:变量的值

    案例11:
    以之前when.yml为例,查看result变量中的内容

    [root@ansible default]# cat  when.yml 
    ---
    - hosts: web
      remote_user: root
      tasks:
      - shell: uptime|awk '{printf("%.2f\n",$(NF-2))}'
        register: result
      - name: stop  service
        service:
          name: httpd
          state: stopped
        when: result.stdout|float > 0.7
      - name: Show debug info
        debug:
          var: result
    
    [root@ansible default]# ansible-playbook when.yml 
    
    PLAY [web] ******************************************************************************************
    
    TASK [Gathering Facts] ******************************************************************************
    ok: [web1]
    ok: [web2]
    
    TASK [shell] ****************************************************************************************
    changed: [web1]
    changed: [web2]
    
    TASK [stop  service] ********************************************************************************
    skipping: [web1]
    ok: [web2]
    
    TASK [Show debug info] ******************************************************************************
    ok: [web1] => {
        "result": {
            "changed": true, 
            "cmd": "uptime|awk '{printf(\"%.2f\\n\",$(NF-2))}'", 
            "delta": "0:00:00.010118", 
            "end": "2020-11-20 15:12:05.959884", 
            "failed": false, 
            "rc": 0, 
            "start": "2020-11-20 15:12:05.949766", 
            "stderr": "", 
            "stderr_lines": [], 
            "stdout": "0.04", 
            "stdout_lines": [
                "0.04"
            ]
        }
    }
    ok: [web2] => {
        "result": {
            "changed": true, 
            "cmd": "uptime|awk '{printf(\"%.2f\\n\",$(NF-2))}'", 
            "delta": "0:00:00.010133", 
            "end": "2020-11-20 15:12:05.484865", 
            "failed": false, 
            "rc": 0, 
            "start": "2020-11-20 15:12:05.474732", 
            "stderr": "", 
            "stderr_lines": [], 
            "stdout": "2.04", 
            "stdout_lines": [
                "2.04"
            ]
        }
    }
    
    PLAY RECAP ******************************************************************************************
    web1                       : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
    web2                       : ok=4    changed=1    unreachable=0    failed=0    skipped=0    rescued=
    

    相关文章

      网友评论

          本文标题:ansible使用笔记(三)Jinja2模板及playbook简

          本文链接:https://www.haomeiwen.com/subject/vdkxiktx.html