playbooks 可以称为是 Ansible 的配置,部署,编排语言。在 playbooks 中,你可以定义远程主机要执行的策略,或者是要执行的某组动作。如:希望远程主机要先安装 httpd,创建一个 vhost,最后启动 httpd 服务。

假如说 Ansible 是一个工具模块的话,那么 playbooks 就是你的设计方案。最基本的,playbooks 可以配置或者部署远程主机;高级些的应用是,可以按照一定的次序执行特定的操作,可以对执行节点的主机进行监控,同时也可监控其负载均衡情况。

Ansible 的 playbook 就如同 saltstate,一个 playbook 就是一个 YAML 文件,所以playbook 文件一般都以.yml 结尾,写 playbook 不需要复杂的 YAML 语法,所以也不用单独去学 YAML 语法。此外 playbook 和模板文件(template 模块)还使用 jinja2 语法语法实现高级功能(后面逐一讲到)

一个 playbook 文件由一个或多个 play 组成,每个 play 定义了在一个或多个远程主机上执行的一系列的 tasktask 是按照顺序执行的,且每个 task 会都在指定的所有远程主机上执行,然后再执行下一个 task,其中每个 task 一般就是调用一个 ansible 的模块,如调用copy 模块复制文件到远程主机或调用 shell 模块执行命令;但是,在执行 task 过程中,某个主机的任务执行失败则退出,结束整个流程(除非设置错误过滤忽 ignore_errors:yes

每个模块都是等幂的,意思是当你再次运行的时候,他们只做他们必须要做的操作(改变某些文件状态等),以使系统达到所需的状态。这样的话,当你重复运行多次相同的 playbooks时也是非常安全的

每个任务都应该有一个名称,这个名称会在运行 playbook 的时候输出,如果没有指定名称,那么对主机做的操作行为将会被用来输出到屏幕

Ansible技术问答:http://linux.xyz/topic/Ansible

1、简单演示

例子:只带有一个 playplaybook 文件 apache.yml

--- #任何 playbook 文件(其实就是 yaml 文件)都要以这个开头
- hosts: webservers #对 webservers 主机组下的所有主机进行操作
 remote_user: ops #连接到远程主机的用户,不是必须,如果没有指定则使用运行的用户
 sudo: yes #以 sudo 模式运行该 play
 sudo_user: root #sudo 到哪个用户,默认为 root,如果 sudo 到该用户需要密码,则在执行 ansible-playbook 的时候指定-K 选项来输入 sudo 密码
vars: #为该 play 定义两个变量
 http_port: 80
 max_clients: 200
 tasks: #开始定义 tasks
 - name: httpd install #这是 task 的名字,会打印到屏幕,如果没有 name,对主机的操作行为将用来输出到屏幕上
 yum: pkg=httpd state=latest
 tags: #给该 task 打一个标签
 - apache
 - name: copy the apache config file
 template: src=/srv/httpd.j2 dest=/etc/httpd.conf
 notify: #提供 watch 功能,这里当 apache 配置文件改变时,就调用 handlers 中名为"restart apache"的 task 来重启 apache
 - restart apache
 - name: ensure apache is running
 service: name=httpd state=started
 handlers: #notify 通知这里的 task 执行,谨记:定义在 handlers 下的 task 只有在 notify 触发的时候才会执行
 - name: restart apache
 service: name=httpd state=restarted

执行该 playbook 文件:

$ ansible-playbook apache.yml

运行 playbook 的 yml 文件,ansible 会连接到 webservers 组下的所有远程主机执行上面定义的 tasks,然后返回执行结果。输出也非常容易看懂,通过红黄绿三种颜色标明了不同的执行结果,如下:

  • 红色:表示有 task 执行失败
  • 黄色:表示执行了且改变了远程主机状态
  • 绿色:表示执行成功

2、patterns

playbook 中的每个 play 首先要定义的就是该 play 要在哪些主机上执行,如上面示例的

---
- hosts: webservers

可以指定单个主机、主机组和以:连接的多个主机或主机组,具体见 Ansible 匹配主机(Patterns)

3、remote_user

remote_user: {{ user }} 表示 ansible 连接到远程主机使用的用户,没有指定则使用运行 ansible-playbook 的用户

- hosts: webservers
 remote_user: root

4、sudo

sudo: yes 表示远程主机要以 sudo 权限执行 tasks,不光可以对整个 play 生效,还可以针对单个 task 生效(remote_user 指令也一样):

---
- hosts: webservers
 remote_user: root
 tasks:
 - shell: cmd
 remote_user: user1
 - service: name=httpd state=started
 sudo: yes #只 sudo 运行该 task
 sudo_user: user2 #sudo 到 user2 用户,如果 sudo 需要密码记得为 ansible-playbook 命令提供"-K"选项
 

5、vars

定义该 play 的变量,play 下的所有 tasks 都能使用它的变量

vars:
 http_port: 80
 max_clients: 200
tasks:
 - name: copy the apache config file
 template: src=/srv/httpd.j2 dest=/etc/httpd.conf

关于变量更多的使用方法,请参考 Ansible 变量(Variables)

6、tasks

tasks 由一系列 task 组成,多个task 按照顺序执行,默认所有匹配主机都执行完一个 task后才会移动到下一个 task 执行,默认如果所有主机都执行某个 task 失败,则 ansible 会中断执行流程并打印错误消息,这里都是说的默认,也就是说这些行为都是可自定义的,以后会讲到这些主题

上面提到过一个 task 其实就是执行一个模块,ansible 中的模块是幂等的(idempotent),也就是说多次执行同一个 task,只有在状态发生改变后才会真的去执行,通过下面的例子讲解:

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

该 task 用于保证 apache 服务器处于运行状态,如果我多次执行该 task 且 apache 一直处于运行状态的话,则该 task 其实什么都不会做。这样做的好处就是你可以随意执行你的playbook 文件,不用担心改变远程主机上的内容(除非状态有变化必须要修改)

注:这里要特别提一下 command 和 shell 模块,这两个模块用于在远程主机上执行命令,每次调用这两个模块都会重新执行一遍命令,且返回的状态是 changed,一般来说不会有什么影响,不过 ansible 也提供了 creates 参数来将这两个模块实现等幂 idempotent,具体请参考Ansible 常用模块中的 command 模块相关说明

7、handlers

handlers 是和 notify 指令搭配使用的,作用是当一个 task 执行修改了远程主机状态时就通知(notify)一个handlers 中的 task 执行,一般用在修改了远程主机的服务的配置文件然后调用 handlers 中的对应 task 去重启该服务,例子如下:

tasks:
 - name: template configuration file
 template: src=template.j2 dest=/etc/foo.conf
 notify:
 - restart memcached
 - restart apache
handlers:
 - name: restart memcached
 service: name=memcached state=restarted
 - name: restart apache
 service: name=httpd state=restarted

这里只有模板文件 template.j2 发生了变化,也就是真正修改了远程主机的/etc/foo.conf 文件后,才会触发 handlers 中的两个 task 执行,其他情况 handlers 中的 task 都是不会运行的

8、参数分行

如果模块的参数需要使用多个,一行显得太长可以分开多行写:

tasks:
 - name: copy facts file to /etc/ansible/fact.d/
 copy: src=file/get_version.fact dest=/etc/ansible/fact.d/
 owner=root group=root mode=0777

9、命令行参数

ansible-playbook 命令参数

Usage: ansible-playbook playbook.yml
Options:
## ssh 连接的用户名
 -u REMOTE_USER, --user=REMOTE_USER
 
## ssh 登录密码
 -k, --ask-pass
 
## sudo 运行
 -s, --sudo
 
##sudo 到哪个用户,默认为 root
 -U SUDO_USER, --sudo-user=SUDO_USER
 
## sudo 密码
 -K, --ask-sudo-pass
 
## ssh 连接超时,默认 10 秒
 -T TIMEOUT, --timeout=TIMEOUT
 
## 指定该参数后,执行 playbook 文件不会真正去执行,而是模拟执行一遍,然后输出本次执行会对远程主机造成的修改
 -C, --check
 
## 连接类型(default=smart)
 -c CONNECTION
 
## 设置额外的变量如:key=value 形式 或者 YAML or JSON,以空格分隔变量,或用多个-e
 -e EXTRA_VARS, --extra-vars=EXTRA_VARS
 
## 进程并发处理,默认 5
 -f FORKS, --forks=FORKS
 
## 指定 hosts 文件路径,默认 default=/etc/ansible/hosts
 -i INVENTORY, --inventory-file=INVENTORY
 
## 指定一个 pattern,对- hosts:匹配到的主机再过滤一次
 -l SUBSET, --limit=SUBSET
 
## 只打印有哪些主机会执行这个 playbook 文件,不是实际执行该 playbook
 --list-hosts
 
## 列出该 playbook 中会被执行的 task
 --list-tasks
 
## 私钥路径
 --private-key=PRIVATE_KEY_FILE
 
## 同一时间只执行一个 task,每个 task 执行前都会提示确认一遍
--step

## 只检测 playbook 文件语法是否有问题,不会执行该 playbook 
 --syntax-check
 
## 当 play 和 task 的 tag 为该参数指定的值时才执行,多个 tag 以逗号分隔
 -t TAGS, --tags=TAGS
 
## 当 play 和 task 的 tag 不匹配该参数指定的值时,才执行
 --skip-tags=SKIP_TAGS
 
## verbose mode (-vvv for more, -vvvv to enable connection debugging)
 -v, --verbose