ansible学习日记-playbook(4)

一、初识playbook

前文中,我们介绍了一些ansible的常用模块,聪明如你,一定已经掌握了这些模块的使用方法。

那么现在,我们来想象一个工作场景:

假设,我们想要在所有主机上安装nginx并启动,我们可以在ansible主机中执行如下3条命令

ansible all -m yum_repository -a 'name=aliEpel description="alibaba EPEL" baseurl=https://mirrors.aliyun.com/epel/$releasever\Server/$basearch/'

ansible all -m yum -a 'name=nginx disable_gpg_check=yes enablerepo=aliEpel'

ansible all -m service -a "name=nginx state=started"

我们通过上述3条命令,先确定配置了对应的yum源,然后使用yum模块安装了nginx,最后使用service模块启动了nginx,最终达到了我们的目的。

但是实际工作中,每次都要执行三次太麻烦了。如果命令越多,后期每次执行命令就越多条。我们可以把这么多条命令整合成一个脚本。直接执行这个脚本就行。这个脚本就是playbook.虽然playbook的功能与脚本类似,但是剧本并不是简单的将ad-hoc命令按照顺序堆砌在一个可执行文件中,编写剧本需要遵循YAML语法.

先看一个示例:

这是两条命令,使用ping模块去ping主机,然后再用file模块在主机上创建目录

ansible all -m ping

ansible all -m file -a "path=/testdir/test state=directory"

转换成playbook为:

[root@ansible-master ansible]# cat ceshi.yml
---
 - hosts: slave
   remote_user: root
   tasks:
   - name: ping slave hosts
     ping:
   - name: mkdir directory
     file:
#除下面path,state冒号形式,也可以使用键值对方式,列如file: path=/testdir/teststate=directory
      path: /testdir/test
      state: directory
[root@ansible-master ansible]#

注:(1)第一行使用三个横杠作为开始,在YAML语法中,”—“表示文档开始

       (2)第二行使用”- “作为开头(注意:横杠后面有空格)YAML使用”- “表示一个块序列的节点

       (3)第三行,使用remote_user关键字可以指定在进行远程操作时使用哪个用户进行操作

       (4)在YAML语法中进行缩进时,不能使用tab键进行缩进,必须使用空格

         (5)每个任务的name都写在前面,这个不分先后,也可以放在这个任务的后面也可以。顺    序没有要求,但是缩进有严格要求

执行结果:


[root@ansible-master ansible]# ansible-playbook ceshi.yml

PLAY [slave] ************************************************************************************

TASK [Gathering Facts] **************************************************************************
ok: [192.168.174.145]
ok: [192.168.174.144]

TASK [ping slave hosts] *************************************************************************
ok: [192.168.174.145]
ok: [192.168.174.144]

TASK [mkdir directory] **************************************************************************
changed: [192.168.174.144]
changed: [192.168.174.145]

PLAY RECAP **************************************************************************************
192.168.174.144            : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.174.145            : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

可以使用模拟执行来看看结果:
ansible-playbook --check test.yml

但是模拟执行的结果报错不能全信。playbook中,可能前后存在依赖关系。模拟执行会报错

二、handlers的用法

应用场景:

当我们修改了某些程序的配置文件以后,可能需要重启应用程序,如果使用playbook来实现这个简单的功能,该怎样编写playbook呢?以nginx作为示例。

假设我们想要将nginx中的某个server的端口从8080改成8088,并且在修改配置以后重启nginx,那么我们可以编写如下剧本:

---
- hosts: slave
  remote_user: root
  tasks:
  - name: Modify the configuration
    lineinfile:
      path=/etc/nginx/conf.d/test.zsythink.net.conf
      regexp="listen(.*) 8080 (.*)"
      line="listen\1 8088 \2"
      backrefs=yes
      backup=yes
  - name: restart nginx
    service:
      name=nginx
      state=restarted

第一次执行playbook后,文件被修改,服务重启,第二次执行playbook,由于幂等性,文件修改将被跳过,但是服务仍然重启了。我们想要达到的效果是只有配置文件被修改时才会重启服务。handlers就是来解决这种问题的。

---
- hosts: test70
  remote_user: root
  tasks:
  - name: Modify the configuration
    lineinfile:
      path=/etc/nginx/conf.d/test.zsythink.net.conf
      regexp="listen(.*) 8080(.*)"
      line="listen\1 8088\2"
      backrefs=yes
      backup=yes
    notify:
      restart nginx
 
  handlers:
  - name: restart nginx
    service:
      name=nginx
      state=restarted

有当tasks中的任务”真正执行”以后(真正的进行实际操作,造成了实际的改变),handlers中被调用的任务才会执行

默认情况下,所有task执行完毕后,才会执行各个handler,并不是执行完某个task后,立即执行对应的handler,如果你想要在执行完某些task以后立即执行对应的handler,则需要使用meta模块,示例如下:

---
- hosts: test70
  remote_user: root
  tasks:
  - name: task1
    file: path=/testdir/testfile
          state=touch
    notify: handler1
  - name: task2
    file: path=/testdir/testfile2
          state=touch
    notify: handler2
 
  - meta: flush_handlers
 
  - name: task3
    file: path=/testdir/testfile3
          state=touch
    notify: handler3
 
  handlers:
  - name: handler1
    file: path=/testdir/ht1
          state=touch
  - name: handler2
    file: path=/testdir/ht2
          state=touch
  - name: handler3
    file: path=/testdir/ht3
          state=touch

在task2后面有meta,表示执行到这里的时候就立即执行前面两个任务的handlers。

我们还可以在一个task中一次性notify多个handler,怎样才能一次性notify多个handler呢

则需要借助另一个关键字,它就是’listen’,你可以把listen理解成”组名”,我们可以把多个handler分成”组”,当我们需要一次性notify多个handler时,只要将多个handler分为”一组”,使用相同的”组名”即可

示例:

---
- hosts: test70
  remote_user: root
  tasks:
  - name: task1
    file: path=/testdir/testfile
          state=touch
    notify: handler group1
 
  handlers:
  - name: handler1
    listen: handler group1
    file: path=/testdir/ht1
          state=touch
  - name: handler2
    listen: handler group1
    file: path=/testdir/ht2
          state=touch

作业:使用ansible的playbook写一个剧本。内容为:

task1:ping两个slave主机

task2:安装httpd,如果安装成功就启动httpd服务,停止httpd服务,再启动httpd服务,需要立即执行

task3:查看80端口是否被监听

答案如下:

这里添加dns服务器,因为幂等性,重复执行会跳过(通过校验文件md5值)

[root@ansible-master ansible]# cat httpd.yml
---
  - hosts: slave
    remote_user: root
    tasks:
    - name: add dns server1
      shell: echo 'nameserver 114.114.114.114' >> /etc/resolv.conf

    - name: add dns server2
      shell: echo 'nameserver 8.8.8.8' >> /etc/resolv.conf

#    - name: clean yum cache
#      shell: yum clean all

#    - name: remake yum cache
#      shell: yum makecache

    - name: ping all host to check connection
      ping:

    - name: install the httpd service
      yum:
        name: httpd
        state: installed
      notify: group1
    - meta: flush_handlers

    - name: check port 80 state
      shell: netstat -anp |grep 80

    handlers:
    - name: stop httpd
      listen: group1
      service : name=httpd state=stopped
    - name: start httpd
      listen: group1
      service : name=httpd state=started
    - name: enable httpd
      listen: group1
      service : name=httpd enabled=yes

[root@ansible-master ansible]#

        
  

执行结果:

可见meta已经生效了。http安装任务结束后就立即进行handlers。后续再继续未完成的task

[root@ansible-master ansible]# ansible-playbook  httpd.yml

PLAY [slave] ************************************************************************************

TASK [Gathering Facts] **************************************************************************
ok: [192.168.174.144]
ok: [192.168.174.145]

TASK [add dns server1] **************************************************************************
changed: [192.168.174.144]
changed: [192.168.174.145]

TASK [add dns server2] **************************************************************************
changed: [192.168.174.144]
changed: [192.168.174.145]

TASK [ping all host to check connection] ********************************************************
ok: [192.168.174.145]
ok: [192.168.174.144]

TASK [install the httpd service] ****************************************************************
changed: [192.168.174.144]
changed: [192.168.174.145]

RUNNING HANDLER [stop httpd] ********************************************************************
ok: [192.168.174.144]
ok: [192.168.174.145]

RUNNING HANDLER [start httpd] *******************************************************************
changed: [192.168.174.145]
changed: [192.168.174.144]

RUNNING HANDLER [enable httpd] ******************************************************************
changed: [192.168.174.144]
changed: [192.168.174.145]

TASK [check port 80 state] **********************************************************************
changed: [192.168.174.144]
changed: [192.168.174.145]

PLAY RECAP **************************************************************************************
192.168.174.144            : ok=9    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
192.168.174.145            : ok=9    changed=6    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

三、tags用法

场景:

你写了一个很长的playbook,其中有很多的任务,不过在实际使用这个剧本时,你可能只是想要执行其中的一部分任务而已,或者,你只想要执行其中一类任务而已,而并非想要执行整个剧本中的全部任务,这个时候我们该怎么办呢?我们可以借助tags实现这个需求。

见名知义,tags可以帮助我们对任务进行’打标签’的操作,当任务存在标签以后,我们就可以在执行playbook时,借助标签,指定执行哪些任务,或者指定不执行哪些任务了,这样说可能不够直观,我们来看一个小示例:

给任务打上标签(这里理解为任务与任务组的关系。具有相同标签的task为一个组。和主机清单文件中类似,一个任务可以赋予多个标签====一个主机可以加入多个主机组)

---
- hosts: slave
  remote_user: root
  tasks:
  - name: task1
    file:
      path: /testdir/t1
      state: touch
    tags: t1
  - name: task2
    file: path=/testdir/t2
          state=touch
    tags: t2
  - name: task3
    file: path=/testdir/t3
          state=touch
    tags: t3

执行命令:

只执行t2标签的task

ansible-playbook --tags=t2 testtag.yml

借助标签,除了能够指定”需要执行的任务”,还能够指定”不执行的任务”,示例命令如下。

ansible-playbook --skip-tags='t2' testtag.yml

当tags写在play中而非task中时,play中的所有task会继承当前play中的tags,而上例中,两个任务都会继承httpd标签,同时还有拥有自己的标签,如下所示。标签被下面所有task继承了。

---
- hosts: slave
  remote_user: root
  tags: t1
  tasks:
  - name: task1
    file:
      path: /testdir/t1
      state: touch
  
  - name: task2
    file: path=/testdir/t2
          state=touch

  - name: task3
    file: path=/testdir/t3
          state=touch

ansible自带标签:

1.always关键字,所以即使task3对应的标签没有被调用,task3也会执行,这就是always的作用。

2.从字面上理解,never的作用应该与always正好相反

还有剩余的三个特殊标签分别为 tagged、untagged、all

这三个特殊标签并非像always一样,always作为标签值存在,而这三个特殊标签则是在调用标签时使用,示例如下

ansible-playbook --tags tagged testtag.yml

上述命令表示只执行有标签的任务,没有任何标签的任务不会被执行。

ansible-playbook --skip-tags tagged testtag.yml

上述命令表示跳过包含标签的任务,即使对应的任务包含always标签,也会被跳过。

ansible-playbook --tags untagged testtag.yml

上述命令表示只执行没有标签的任务,但是如果某些任务包含always标签,那么这些任务也会被执行。

ansible-playbook --skip-tags untagged testtag.yml

上述命令表示跳过没有标签的任务。

特殊标签all表示所有任务会被执行,不用指定,默认情况下就是使用这个标签。

参考文章:ansible笔记(14):变量(一)-朱双印博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值