83.学习Ansible[6]:playbook

文章目录

  • 关于Playbook
  • 第一个Playbook例子
    • 主机和用户
    • 任务列表
    • 处理器
    • 执行playbook与其他

后续此博客不再更新,欢迎大家搜索关注微信公众号“测开之美”,测试开发工程师技术修炼小站,持续学习持续进步。

关于Playbook

学习playbook前,推荐先阅读:学习Ansible[5]:YAML文件格式浅析。
Playbook是Ansible的配置、部署、编排语言,可以描述远端机器的执行策略,或一般IT流程中的一组步骤。如果Ansible的模块是车间里的工具,playbook就是操作手册,资源清单中的主机就是操作的原材料。
playbook的基本功能是管理远端机器的配置、部署,更高级点可以对涉及滚动更新的多层发布任务进行排序,将操作委派给其他主机,同时与监视服务器和负载平衡器进行交互。
Github上的ansible/ansible-examples示例是Ansible提供的官方示例,推荐阅读。

第一个Playbook例子

一个playbook,是一个或多个play的列表。一个play,建立起一组机器和一些任务的映射。一个任务,是对Ansible模块的一次调用。组合多个play成为一个playbook,可以实现复杂的功能,比如在webservers组上执行某些任务,再在dbservers组上执行另一些任务,最后在webservers组上执行剩下的任务,等等。一个简单的包含一个play的playbook示例:

---
- hosts: webservers
  vars:
    http_port: 80
    max_clients: 200
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum:
      name: httpd
      state: latest
  - name: write the apache config file
    template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf
    notify:
    - restart apache
  - name: ensure apache is running
    service:
      name: httpd
      state: started
  handlers:
    - name: restart apache
      service:
        name: httpd
        state: restarted

包含多个play的playbook例子:

---
- hosts: webservers
  remote_user: root
  tasks:
  - name: ensure apache is at the latest version
    yum:
      name: httpd
      state: latest
  - name: write the apache config file
    template:
      src: /srv/httpd.j2
      dest: /etc/httpd.conf
- hosts: databases
  remote_user: root
  tasks:
  - name: ensure postgresql is at the latest version
    yum:
      name: postgresql
      state: latest
  - name: ensure that postgresql is started
    service:
      name: postgresql
      state: started

play和任务的执行顺序,与在playbook中的定义顺序一样,都是从上到下,所以上面的例子可以实现在不同的机器组间切换不同的任务。下面深入介绍playbook的基础。

主机和用户

每个play,都要明确针对哪些机器(hosts)、以何种身份(remote_user)完成指定的任务。
hosts的值,是一个或多个机器组或机器pattern的列表,用冒号分割。remote_user是登录远端机器的用户名。一个play级的主机配置片段举例:

# YAML snippet
--- 
- hosts: webservers
  remote_user: root

remote_user可以在每个任务中单独定义:

# YAML snippet
---
- hosts: webservers
  remote_user: root
  tasks:
    - name: test connection
      ping:
      remote_user: mars

play级的提升权限:

# YAML snippet
---
- hosts: webservers
  remote_user: mars
  become: yes

任务级的提升权限(可以同时设定提升权限的方法,比如su):

# YAML snippet
---
- hosts: webservers
  remote_user: mars
  tasks:
    - service:
        name: nginx
        state: started
      become: yes
      become_method: sudo

play级的切换到其他用户:

# YAMl snippet
---
- hosts: webservers
  remote_users: mars
  become: yes
  become_user: loo

如果切换用户或sudo需要密码,执行ansible-playbook命令时要加--ask-become-pass参数。运行有用户切换场景的playbook,ansible-book程序hang住很有可能是切换用户或sudo时鉴权出现问题,直接Ctrol+C杀死ansible-playbook,重新提供--ask-become-pass参数即可。

play级的order参数控制任务在所有机器的执行顺序:

# YAMl snippet
---
- hosts: all
  order: sorted
  gather_facts: False
  tasks:
    - debug:
        var: inventory_hostname

order参数取值范围:

  • inventory:默认,按照hosts参数列表中的顺序执行。
  • reverse_inventery:按照hosts参数列表中的反序执行。
  • sorted:按照hosts参数中机器名字典序执行。
  • reverse_sorted:按照hosts参数中机器名字反字典序执行。
  • shuffle:按照hosts参数中机器随机序执行。

任务列表

playbook执行过程中,如果一个机器运行任务失败,这个机器将不再参与后续的任务执行。
模块应该是幂等的,要实现幂等,可以检查模块的最终状态是否符合预期。如果playbook使用的所有模块都是幂等的,整个playbook就是幂等的,多次运行playbook就是安全的。
一个简单的任务定义的示例片段:

# YAML snippet
tasks:
  - name: make sure apache is running
    service:
      name: httpd
      state: started

name参数描述这个任务的功能,执行playbook时会输出到日志中。
大多数模块(比如上例中的service模块)接受key=value格式的参数,对于commandshell这种直接接收参数列表的模块,可以按照如下格式定义:

# YAML snippet
tasks:
  - name: enable selinux
    command: /sbin/setenforce 1

commandshell模块关注命令的返回值,如果命令成功执行时的返回值不是0,用如下方法规避:

# YAML snippet
tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand || /bin/true

或者:

# YAML snippet
tasks:
  - name: run this command and ignore the result
    shell: /usr/bin/somecommand
    ignore_errors: True

如果参数过长,可以在任意空格处换行,在下一行缩进继续定义参数:

# YAML snippet
tasks:
  - name: Copy ansible inventory file to client
    copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts
            owner=mars group=mars mode=0644

任务的定义可以使用play级定义的变量,比如假设在play的vars部分提前定义了一个变量vhost

# YAML snippet
tasks:
  - name: use variable {{ vhost }}
    template:
        src: somefile.j2
        dest: /etc/conf/{{ vhost }}

旧版本的Ansible定义任务使用action: module arguments的形式,现在已经不推荐使用这种形式,例如:

# YAML snippet
action: template src=somefile.j2 dest=/etc/conf/somefile.j2

推荐使用上面的module: arguments形式:

# YAML snippet
 - name: copy files
     template:
         src: somefile.j2
         dest: /etc/conf/somefile.j2

处理器

playbook的通知机制(notify),可以在一个play结束时执行指定的任务(即使被多个不同的任务多次通知)。例如,多个任务都修改了Apache的配置并通知Apache重启,Apache仅在这个play结束时重启一次,例如:

# YAML snippet
tasks:
 - name: template configuration file
   template:
     src: template.j2
     dest: /etc/apache.conf
   notify:
     - restart apache
handlers:
    - name: restart apache
      service:
        name: apache
        state: restarted

notify中定义的任务列表是处理器(handler)的列表。处理器也是任务,有全局唯一的名字,被通知触发执行,如果没有被通知则不会执行。
除了通过处理器名字触发处理器,处理器可以监听topic消息,被topic消息触发:

# YAML snippet
handlers:
    - name: restart memcached
      service:
        name: memcached
        state: restarted
      listen: "restart web services"
    - name: restart apache
      service:
        name: apache
        state: restarted
      listen: "restart web services"
tasks:
    - name: restart everything
      command: echo "this task will restart the web services"
      notify: "restart web services"

细心的读者会发现notify的值也可以是标量。使用topic消息的方式将处理器与名字本身解耦,在剧本、角色间共享处理器场景下非常方便。

  • 多个处理器一起触发时,按照定义的顺序执行,而不是触发顺序。
  • 处理器名字和topic消息都存在于全局命名空间。
  • 如果两个处理器名字相同,只有一个处理器会被触发。
  • 不能触发一个定义在include中的触发器。

如果执行某个任务前,需要先执行排队中的处理器任务,可以用如下方式清空并执行排队中的处理器任务:

# YAML snippet
 tasks:
    - shell: some tasks
    - meta: flush_handlers
    - shell: some other tasks

执行playbook与其他

编写完playbook的YAML文件后,运行playbook非常简单,假设1.yml内容为:

---
- hosts: example
  remote_user: mars
  gather_facts: false
  tasks:
    - name: list files
      shell: pwd && ls -al

以10并发运行playbook:

$ ansible-playbook 1.yml -f 10

PLAY [example] *****************************************************************

TASK [list files] **************************************************************
changed: [a.example.com]
changed: [b.example.com]

PLAY RECAP *********************************************************************
a.example.com : ok=1    changed=1    unreachable=0    failed=0
b.example.com : ok=1    changed=1    unreachable=0    failed=0

检查playbook的语法:ansible-playbook --syntax-check 1.yml
查看模块执行过程中的输出:ansible-playbook 1.yml --verbose
查看一个playbook会影响哪些机器:

$ ansible-playbook 1.yml --list-hosts

playbook: 1.yml

  play #1 (example): example	TAGS: []
    pattern: [u'example']
    hosts (2):
      a.example.com
      b.example.com

你可能感兴趣的:(研发工具)