4.5 playbook介绍

playbook是一个不同于Ansible命令行执行方式的模式,其功能更为强大灵活。简而言之,它是一个非常简单的配置管理和多主机部署系统。playbook是由一个或多个“play”组成的列表。play的主要功能在于将事先归为一组的主机装扮成通过Ansible中的task事先定义好的角色。从根本上来讲,所谓的task就是调用Ansible的一个个模块将多个play组织在一个playbook中,这样就可以让它们联通起来按事先编排的机制同唱一台大戏。

playbook的模板是使用Python的jinja2模块来处理的。学习过Saltstack的朋友对此模板应该是比较熟悉的。另外,playbook也是通过YAML格式来进行描述定义的,可以实现多台主机的应用部署,语法也并不复杂,大家可以对应官方案例学习其语法,官方网站提供了大量的案例,其地址为https://github.com/ansible/ansible-examples 。

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

下面先来看一下Ansible官方网站的一个案例,以举例说明playbook的用法。

#选择的主机组

- hosts: webserver

#定义的变量

vars:

user: www

group: www

maxclients: 2000

DocumentRoot: /var/www/html

#远端的执行权限

remote_user: root

#task是定义任务列表

tasks:

#利用

yum模块来操作

- name: ensure apache is at the latest version

#建议每个任务事件都要定义一个

name标签,这样做既增强了可读性,又便于观察结果输出。

yum: pkg=httpd state=latest

- name: Apache Config File

template: src=/home/yhc/apache/httpd.conf.j2 dest=/etc/httpd/conf/httpd.conf

#src为

Ansible主控端模块存放位置,

dest为被控端

httpd配置文件位置

#触发重启服务器

notify:

- restart apache

- name: ensure apache is running

service: name=httpd state=started

#这里的

restart apache 和上面的触发是配对的

,这就是

handlers(处理程序)的作用。

handlers:

- name: restart apache

service: name=httpd state=restarted

模板文件/home/yhc/apache/httpd.conf.j2可参考官方案例,建议以j2结尾,表明这是一个经过jinja2模板渲染的文件,并且存放在名为templates的子目录中。

定义的变量最好跟模板文件/home/yhc/apache/httpd.conf.j2中的变量一一对应,不然后面执行ansible-playbook时会报错,由于模板文件内容太长,这里只摘录跟变量相对应的内容,如下:

User {{ user}}

Group {{ group}}

DocumentRoot "{{DocumentRoot}}"

MaxClients {{maxclients}}

语法简单明了,YAML文件中的变量以“{{变量名}}”表示,该文件若写得过于复杂,就会有语法错误的问题,可以采用如下方式检查语法错误:

ansible-playbook /home/yhc/httpd.yml --list-hosts --list-tasks

playbook: /home/yhc/httpd.yaml

play #1 (webserver): host count=2

192.168.1.205

192.168.1.206

play #1 (webserver): TAGS: []

ensure apache is at the latest version TAGS: []

write the apache config file TAGS: []

ensure apache is running TAGS: []

执行我们预先写好的YAML文件,路径为/home/yhc/httpd.yml,命令如下:

ansible-book /home/yhc/httpd.yml -f 10

显示结果如下所示:

PLAY [webserver] **************************************************************

GATHERING FACTS ***************************************************************

ok: [192.168.1.205]

ok: [192.168.1.206]

TASK: [ensure apache is at the latest version] ********************************

ok: [192.168.1.206]

ok: [192.168.1.205]

TASK: [write the apache config file] ******************************************

changed: [192.168.1.205]

changed: [192.168.1.206]

TASK: [ensure apache is running] **********************************************

ok: [192.168.1.205]

ok: [192.168.1.206]

NOTIFIED: [restart apache] ****************************************************

changed: [192.168.1.205]

changed: [192.168.1.206]

PLAY RECAP ********************************************************************

192.168.1.205 : ok=5 changed=2 unreachable=0 failed=0

192.168.1.206 : ok=5 changed=2 unreachable=0 failed=0

ansible-playbook后面紧跟着的就是我们所写的/home/yhc/httpd.yml文件,它的默认并行进程数为5,可以带上参数-f 10或更大的数值以提高并行进程数。

playbook文件的详细说明

(1)定义主机和用户

每份playbook文件都需要指定针对哪些主机进行运维,而hosts变量则说明了这个问题,users则说明了采用哪个用户执行这条命令。

针对webserver主机组,这里采用root用户执行命令,代码如下:

---

- hosts: webservers

remote_user: root

如果是AWS EC2主机,可以采用sudo模式执行命令,代码如下:

---

- hosts: webservers

remote_user: ec2-user

sudo: yes

(2)任务列表

每一个playbook都会有一份任务列表(tasks list),说明究竟要按照怎样的顺序去执行这些命令(从上至下,依照顺序执行task)。

使用service模块的命令如下:

tasks:

- name: make sure apache is running

service: name=httpd state=running

使用command模块的命令如下:

tasks:

- name: disable selinux

command: /sbin/setenforce 0

使用shell模块的命令如下:

tasks:

- name: run this command and ignore the result

shell: /usr/bin/somecommand || /bin/true

使用copy模块的命令如下:

tasks:

- name: Copy ansible inventory file to client

copy: src=/etc/ansible/hosts dest=/etc/ansible/hosts

owner=root group=root mode=0644

使用template模块的命令如下:

tasks:

- name: create a virtual host file for {{ vhost }}

template: src=somefile.j2 dest=/etc/httpd/conf.d/{{ vhost }}

(3)handlers

当被控端主机配置文件发生变化以后,通知处理程序handlers来触发后续的动作,比如重启Apache服务。在没有通知触发时handlers中定义的处理程序是不会执行的,触发是通过handlers定义的name标签来识别的,比如下面的notify中的“restart apache”和handlers中的“name:restart apache”内容请保持一致。

notify:

- restart apache

- name: ensure apache is running

service: name=httpd state=started

handlers:

- name: restart apache

service: name=httpd state=restarted

下面简单介绍下playbook的条件语句与循环,语法非常简单,直接通过示例即可说明。

条件语句when的示例如下:

tasks:

- name: reboot redhat host

command: /usr/sbin/reboot

when: ansible_os_family == "RedHat"

循环语句的示例如下:

tasks:

- name: install LNMP

yum: name={{ item }} state=present

with_items:

- nginx

- mysql-server

- php-fpm

循环还支持列表,使用的是with_flattened语句。

变量文件的示例如下:

---

packages_LNMP:

- [ 'nginx', 'mysql-server', 'php-fpm' ]引用

- name: Install LNMP

yum: name={{ item }} state=present

with_flattened:

- packages_LNMP

关于playbook文件的更多说明可参考文档http://docs.ansible.com/playbooks_roles.html 。

工作中经常会有这样一个需求:被控机上有3个用户(yhc、admin和readonly),分别对应3套公私钥(分别对应不同的权限),需要用Ansible主控端进行公钥推送。这时,ssh-copy-id.yml文件如下所示:

# Using alternate directory locations:

- hosts: webserver

user: root

tasks:

- name: ensure users is present

user: name={{ item }} state=present

with_items:

- yhc

- admin

- readonly

- name: ssh-copy-id user yhc

authorized_key: user=yhc key='{{ lookup('file', '/home/yhc/ansible/ssh-copy-id/example-master.pub') }}'

- name: ssh-copy-id user admin

authorized_key: user=admin key='{{ lookup('file', '/home/yhc/ansible/ssh-copy-id/example-operation.pub') }}'

- name: ssh-copy-id user readonly

authorized_key: user=readonly key='{{ lookup('file', '/home/yhc/ansible/ssh-copy-id/example-readonly.pub') }}'

authorized_key是Ansible官方新出的一个模块,作用为添加或删除用户SSH公钥(adds or removes an SSH authorized key),这里主要用于添加用户公钥,详细说明请参见:http://docs.ansible.com/ansible/authorized_key_module.html 。

如果Ansible部署在AWS EC2主机上,则默认是不允许root进行SSH的,并且root不提供密码,因此这里需要用一个有sudo权限的用户来执行,默认用户一般是ec2-user。

需要注意的是,这里的公钥文件全部都在Ansible主控机器的/home/yhc/ansible/ssh-copy-id目录下,而且不必担心被控机器端的.ssh目录是否建立、authorized文件权限是否为600等,这些全部由authorized_key模块全自动完成,是不是很人性化呢?

此时的ssh-copy-id文件调整如下:

- hosts: bidder

user: ec2-user

sudo: yes

tasks:

- name: ensure users is present

user: name={{ item }} state=present

with_items:

- bilin

- readonly

sudo:yes

- name:ssh-copy-id user bilin

authorized_key: user=bilin key='{{ lookup('file', '/home/yhc/ansible/ssh-copy-id/example-operation.pub') }}'

- name:ssh-copy-id user readonly

authorized_key: user=readonly key='{{ lookup('file', '/home/yhc/ansible/ssh-copy-id/example-readonly.pub') }}'

可用如下命令执行ssh-copy-id.yml文件,如下所示:

ansible-playbook -i hosts ssh-copy-id.yml

在被控端机器上进行检查,可发现公钥都已经正确分发了,而且权限自动地分配成了600权限,在主控端上切换相应的用户,SSH登录也是正常的,说明整个配置过程是没有问题的。