后续此博客不再更新,欢迎大家搜索关注微信公众号“测开之美”,测试开发工程师技术修炼小站,持续学习持续进步。
学习playbook前,推荐先阅读:学习Ansible[5]:YAML文件格式浅析。 Playbook是Ansible的配置、部署、编排语言,可以描述远端机器的执行策略,或一般IT流程中的一组步骤。如果Ansible的模块是车间里的工具,playbook就是操作手册,资源清单中的主机就是操作的原材料。 playbook的基本功能是管理远端机器的配置、部署,更高级点可以对涉及滚动更新的多层发布任务进行排序,将操作委派给其他主机,同时与监视服务器和负载平衡器进行交互。 Github上的ansible/ansible-examples示例是Ansible提供的官方示例,推荐阅读。
一个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: startedplay和任务的执行顺序,与在playbook中的定义顺序一样,都是从上到下,所以上面的例子可以实现在不同的机器组间切换不同的任务。下面深入介绍playbook的基础。
每个play,都要明确针对哪些机器(hosts)、以何种身份(remote_user)完成指定的任务。 hosts的值,是一个或多个机器组或机器pattern的列表,用冒号分割。remote_user是登录远端机器的用户名。一个play级的主机配置片段举例:
# YAML snippet --- - hosts: webservers remote_user: rootremote_user可以在每个任务中单独定义:
# YAML snippet --- - hosts: webservers remote_user: root tasks: - name: test connection ping: remote_user: marsplay级的提升权限:
# 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: sudoplay级的切换到其他用户:
# 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_hostnameorder参数取值范围:
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: startedname参数描述这个任务的功能,执行playbook时会输出到日志中。 大多数模块(比如上例中的service模块)接受key=value格式的参数,对于command、shell这种直接接收参数列表的模块,可以按照如下格式定义:
# YAML snippet tasks: - name: enable selinux command: /sbin/setenforce 1command和shell模块关注命令的返回值,如果命令成功执行时的返回值不是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.j2playbook的通知机制(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: restartednotify中定义的任务列表是处理器(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的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