附上前两篇关于Ansible的博客地址,以供查阅,欢迎学习交流!
自动化运维之Ansible概述及Ansible部署
Ansible命令应用之常用模块


Playbook简介

playbook是ansible用于配置,部署,和管理被控节点的剧本。

通过playbook的详细描述,执行其中的一系列tasks,可以让远端主机达到预期的状态。playbook就像Ansible控制器给被控节点列出的的一系列to-do-list,而被控节点必须要完成。

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

Playbook的使用场景

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

就像执行shell命令与写shell脚本一样,也可以理解为批处理任务,不过playbook有自己的语法格式。

使用playbook你可以方便的重用这些代码,可以移植到不同的机器上面,像函数一样,最大化的利用代码。在你使用Ansible的过程中,你也会发现,你所处理的大部分操作都是编写playbook。可以把常见的应用都编写成playbook,之后管理服务器会变得十分简单。

Playbook格式介绍

playbook由YMAL语言编写。YAML( /ˈjæməl/ )参考了其他多种语言,包括:XML、C语言、Python、Perl以及电子邮件格式RFC2822,Clark Evans在2001年5月在首次发表了这种语言,另外Ingy döt Net与Oren Ben-Kiki也是这语言的共同设计者。

YMAL格式是类似于JSON的文件格式,便于人理解和阅读,同时便于书写。首先学习了解一下YMAL的格式,对我们后面书写playbook很有帮助。以下为playbook常用到的YMAL格式。

文件的第一行应该以 ”—” (三个连字符)开始,表明YMAL文件的开始。
在同一行中,#之后的内容表示注释,类似于shell,python和ruby。
YMAL中的列表元素以”-”开头然后紧跟着一个空格,后面为元素内容。就像这样:

- apple - banana - orange等价于JSON的这种格式

[ “apple”, “banana”, “orange” ]
同一个列表中的元素应该保持相同的缩进。否则会被当做错误处理。

Playbook本身由以下各部分组成:

  • Tasks:任务,即调用模板完成某操作;
  • Variables:变量;
  • Templates:模板;
  • Handlers:处理器,当某条件满足时,触发执行的操作;
  • Roles:角色。

playbook中hosts,variables,roles,tasks等对象的表示方法都是键值中间以”:”分隔表示,”:”后面还要增加一个空格。

house:
    family: { name: Doe, parents: [John, Jane], children: [Paul, Mark, Simone] }
    address: { number: 34, street: Main Street, city: Nowheretown, zipcode: 12345 }

Ansible-playbook执行playbook文件

使用ansible-playbook运行playbook文件,得到如下输出信息,输出内容为JSON格式。并且由不同颜色组成,便于识别。一般而言

| 绿色代表执行成功,系统保持原样

| ×××代表系统代表系统状态发生改变

| 红色代表执行失败,显示错误输出。

执行有三个步骤:1、收集facts 2、执行tasks 3、报告结果

[root@CentOS7-master ~]# ansible-playbook mariadb.yml 
---------------------------1、收集facts------------------------------------------
PLAY [webservers] **************************************************************

TASK [setup] *******************************************************************
ok: [172.17.254.165]
ok: [172.17.254.180]
---------------------------2、执行tasks------------------------------------------
TASK [Install mariadb-server package] ******************************************
changed: [172.17.254.165]
changed: [172.17.254.180]

TASK [Starting mysqld service] *************************************************
changed: [172.17.254.165]
changed: [172.17.254.180]
---------------------------3、报告结果-------------------------------------------
PLAY RECAP *********************************************************************
172.17.254.165             : ok=3    changed=2    unreachable=0    failed=0   
172.17.254.180             : ok=3    changed=2    unreachable=0    failed=0

Playbook的基础组件

1.Hosts和Users

Playbook的设计目的是为了让某个或某些主机以某个用户的身份去执行相应的任务。其中用于指定要执行指定任务的主机用hosts定义,可以是一个主机也可以是由冒号分隔的多个主机组;用于指定被管理主机上执行任务的用户用remote_user来定义。

remote_user也可定义指定用户通过sudo的方法在被管理主机上运行指令,甚至可以在使用sudo时用sudo_user指定sudo切换的用户。

Hosts:运行指定任务的目标主机;
remoute_user: 在远程主机上执行任务的用户;
sudo_user:指定sudo切换的用户
tasks:任务列表
模块,模块参数;
格式:
    (1) action: module arguments
    (2) module: arguments

2.任务列表tasks

每一个play包含了一个task列表(任务列表)。一个task在其所对应的所有主机上(通过host pattern匹配的所有主机)执行完毕之后,下一个task才会执行。有一点需要明白的是(很重要),在一个play之中,所有hosts会获取相同的任务指令,这是play的一个目的所在,也就是将一组选出的hosts映射到task。

在运行playbook时(从上到下执行),如果一个host执行task失败,这个host将会从整个 playbook的rotation中移除. 如果发生执行失败的情况,请修正playbook中的错误,然后重新执行即可。

每个task的目标在于执行一个moudle, 通常是带有特定的参数来执行.在参数中可以使用变量(variables)。

modules具有”幂等”性,意思是如果你再一次地执行 moudle(译者注:比如遇到远端系统被意外改动,需要恢复原状),moudle只会执行必要的改动,只会改变需要改变的地方。所以重复多次执行playbook也很安全。

对于command module和shell module,重复执行 playbook,实际上是重复运行同样的命令。如果执行的命令类似于‘chmod’或者‘setsebool’这种命令,这没有任何问题。也可以使用一个叫做 ‘creates’ 的 flag 使得这两个module变得具有”幂等”特性(不是必要的)。

每一个task必须有一个名称name,这样在运行playbook时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个task 的。如果没有定义name,‘action’ 的值将会用作输出信息中标记特定的task。

如果要声明一个task,以前有一种格式:“action: module options”。可能在一些老的playbooks 中还能见到)。现在推荐使用更常见的格式:”module: options”,本文档使用的就是这种格式。

下面是一种基本的task 的定义,service moudle使用key=value格式的参数,这也是大多数 module 使用的参数格式:

tasks:
  - name: make sure apache is running
    service: name=httpd state=running

比较特别的两个modudle是command和shell,它们不使用key=value格式的参数,而是这样:

tasks:
  - name: disable selinux
    command: /sbin/setenforce 0

或者是这样:

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

如果action行看起来太长,你可以使用space(空格)或者indent(缩进)隔开连续的一行:

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

在action行中可以使用变量.假设在‘vars’那里定义了一个变量‘vhost’,可以这样使用它:

tasks:
  - name: create a virtual host file for {{ vhost }}
    template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}

这些变量在 tempates 中也是可用的,稍后会讲到。

3.Handlers

Handlers用于当关注的资源发生变化时所采取的操作。在notify中列出的操作便称为handler,也就是在notify中需要调用handler中定义的操作。而notify这个动作在每个play的最后被触发,仅在所有的变化发生完成后一次性的执行指定操作。

tasks:
    – name: TASK_NAME
      module: arguments
      notify: HANDLER_NAME
      handlers:
    – name: HANDLER_NAME
      module: arguments

这里是一个handlers的示例:

- name: template configuration file
  template: src=template.j2 dest=/etc/foo.conf
  notify:
     - restart memcached
     - restart apache

handler也是task列表格式,如:

handlers:
    - name: restart memcached
      service:  name=memcached state=restarted
    - name: restart apache
      service: name=apache state=restarted

简单示例如下:

[root@CentOS7-master ~]# vim mariadb.yml 
- hosts: webservers
  remote_user: root
  tasks:
   - name: Install mariadb-server package
     yum: name=mariadb-server state=present

   - name: copy my.cnf
     copy: src=/etc/my.cnf dest=/etc/ backup=yes
     notify: start
     tags: startmariadb

   - name: Stopping mysqld service
     service: name=mariadb state=stopped
     tags: stopmariadb

  handlers:
   - name: start
     service: name=mariadb state=started

4.Variables:

(1) facts:可直接调用;
    注意:可使用setup模块直接获取目标主机的facters;
(2) 用户自定义变量:
    (a) ansible-playbook命令的命令行中的
        -e VARS, --extra-vars=VARS
    (b) 在playbook中定义变量的方法:
        vars:
            - var1: value1
            - - var2: value2
(3) 通过roles传递变量;
(4) Host Inventory
    (a) 用户自定义变量
        (i) 向不同的主机传递不同的变量;
            IP/HOSTNAME varaiable=value var2=value2
        (ii) 向组中的主机传递相同的变量;
            [groupname:vars]
            variable=value
            eg:
                [web]
                    172.17.251.188
                    172.17.250.209
                [web:vars]
                    rpmname=samba

5.Templates

Jinja是基于Python的模板引擎。Template类是Jinja的另一个重要组件,可以看作是一个编译过的模板文件,用来产生目标文本,传递Python的变量给模板去替换模板中的标记。

Jinja:Jinja2是python的一种模板语言,以Django的模板语言为原本。
Jinja文件的创建可以直接将自己创建好的文本文件的后缀改成以“.j2”结尾的即可!
下面用到的nginx.conf.j2文件就是将nginx.conf文件修改好后将其重命名为nginx.conf.j2的!
支持:
    字符串:使用单引号或双引号;
    数字:整数,浮点数;
    列表:[item1, item2, ...]
    元组:(item1, item2, ...)
    字典:{key1:value1, key2:value2, ...}
    布尔型:true/false
    算术运算:
        +, -, *, /, //, %, **
    比较操作:
        ==, !=, >, >=, <, <=
    逻辑运算:
        and, or, not

示例:

[root@CentOS7-master ~]# vim nginx.yml 
- hosts: webservers
  remote_user: root
  vars:
    - rpmname: nginx
      nginxport: 8888
  tasks:
    - name: yum install {{ rpmname }}
      yum: name={{ rpmname }} state=present

    - name: copy {{ rpmname }}.conf
      template: src=/tmp/{{ rpmname }}.conf.j2 dest=/etc/nginx/{{ rpmname }}.c
onf backup=yes
      notify: reload
      tags: reload{{ rpmname }}

    - name: start service
      service: name={{ rpmname }} state=started
      tags: start{{ rpmname }}

  handlers:
    - name: reload
      service: name={{ rpmname }} state=restarted

模板配置文件:

[root@CentOS7-master ~]# cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.j2

[root@CentOS7-master ~]# vim nginx.conf.j2
worker_processes {{ ansible_processor_vcpus }};
listen {{ http_port }};

6.Tags

如果多次执行修改Playbook会涉及到一些没有变化的代码,可以使用tags让用户选择跳过没有变化的代码,只运行Playbook中发生变化的部分代码。可以在Playbook中为某个或某些任务定义“标签”,在执行此Playbook时通过ansible-playbook命令使用--tags选项能实现仅运行指定的tasks。

简单示例如下:

[root@CentOS7-master ~]# vi hosts.yml
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: Copy hosts file
      copy: src=/etc/hosts dest=/etc/hosts
      tags:
      - only
    - name: touch file
      file: path=/opt/hosts state=touch

分别执行ansible-playbook hosts.yml --tags="only"和ansible-playbook hosts.yml可以发现,有--tags="only"的命令只运行了Copy hosts file部分。

事实上,不光可以为单个或多个task指定同一个tags。playbook还提供了一个特殊的tags为always。作用就是当使用always当tags的task时,无论执行哪一个tags时,定义有always的tags都会执行。

vi hosts.yml
---
- hosts: webserver
  remote_user: root
  tasks:
    - name: Copy hosts file
      copy: src=/etc/hosts dest=/etc/hosts
      tags:
      - only
    - name: touch file
      file: path=/opt/hosts state=touch
      tags:
      - always