Playbooks 是 Ansible的配置,部署,编排语言.他们可以被描述为一个需要希望远程主机执行命令的方案,或者一组IT程序运行的命令集合.
Playbooks 与 adhoc 相比,是一种完全不同的运用 ansible 的方式,是非常之强大的.
简单来说,playbooks 是一种简单的配置管理系统与多机器部署系统的基础, 非常适合于复杂应用的部署.
在playbook中我们可以编排有序的执行过程,甚至可以实现多组机器之间来回有序执行我们指定的任务!并且可以实现同步或异步的发起任务
在使用adhoc时,我们主要使用/usr/bin/ansible 程序执行任务,在使用playbook时,我们更多的是将任务写在剧本文件当中,使用ansible-playbook命令读取执行任务
Playbooks 的格式是YAML, playbook 由一个或多个 ‘plays’ 组成.它的内容是一个以 ‘plays’ 为元素的列表! 在 play 之中,一组机器被映射为定义好的角色.在 ansible 中,play 的内容,被称为 tasks,即任务.在基本层次的应用中,一个任务就是一个对 ansible 模块的调用
通过 playbook,可以编排步骤进行多机器的部署,比如在 webservers 组的所有机器上运行一定的步骤, 然后在 dbservers 组运行一些步骤,最后回到 webservers 组,再运行一些步骤,诸如此类.
---
- hosts: webservers
vars:
http_port: 80
max_clients: 200
remote_user: root
tasks:
- name: ensure apache is at the latest version
yum: pkg=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
核心元素
Tasks:任务,由模板定义的操作列表
Variables:变量
Templates:模板,即使用模板语法的文件
Handlers:处理器 ,当某条件满足时,触发执行的操作
Roles:角色
通过ansible-playbook命令运行
格式:ansible-playbook
[root@ansible PlayBook]# ansible-playbook -h
#ansible-playbook常用选项:
--check or -C #只检测可能会发生的改变,但不真正执行操作
--list-hosts #列出运行任务的主机
--list-tags #列出playbook文件中定义所有的tags
--list-tasks #列出playbook文件中定义的所以任务集
--limit #主机列表 只针对主机列表中的某个主机或者某个组执行
-f #指定并发数,默认为5个
-t #指定tags运行,运行某一个或者多个tags。(前提playbook中有定义tags)
-v #显示过程 -vv -vvv更详细
[root@ansible PlayBook]# ansible-playbook fileName.yml --syntax-check #playbook语法检查
你可以为 playbook 中的每一个 play,去选择要操作的目标机器是哪些,以哪个用户身份去完成要执行的步骤,hosts一行可以是一个主机组、主机、多个主机,中间以冒号分隔,可使用通配模式。其中remote_user表示执行的用户账号。
---
- hosts: webservers #指定主机组,可以是一个或多个组。
remote_user: root ##指定远程主机执行的用户名
我们也可以在一个任务中定义自己的远程用户
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
也支持sudo的调用
---
- hosts: webservers
remote_user: yourname
sudo: yes
如果你需要在使用 sudo 时指定密码,可在运行 ansible-playbook 命令时加上选项 --ask-sudo-pass (-K)
每个play都包含一个task列表(任务列表),一个task在目标主机执行完毕后,才会执行下一个任务,在同一个play当中,所有的主机都会收到接受到相同的指令,
每个 task 的目标在于执行一个模块(module), 通常是带有特定的参数来执行.在参数中可以使用变量
modules 具有”幂等”性,意思是如果你再一次地执行 moudle,moudle 只会执行必要的改动,只会改变需要改变的地方.所以重复多次执行 playbook 也很安全.
每一个 task 必须有一个名称 name,这样在运行 playbook 时,从其输出的任务执行信息中可以很好的辨别出是属于哪一个 task 的. 如果没有定义 name,‘action’ 的值将会用作输出信息中标记特定的 task.
下面是一种基本的task的定义
service 模块使用 key=value 格式的参数,这也是大多数 module 使用的参数格式:
tasks:
- name: make sure apache is running #任务名
service: name=httpd state=running #运行Apache
但是有两个特殊的模块shell模块和command模块,它们不是用key=value的格式,而是这样的:
tasks:
- name: disable selinux
command: /sbin/setenforce 0
使用shell模块和command模块我们需要考虑返回码的问题,若返回码不为0说明命令没有执行成功,那么模块执行的状态也为失败,任务可能就会终止,我们可以按如下执行来解决状态码的问题:
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand || /bin/true
或者
tasks:
- name: run this command and ignore the result
shell: /usr/bin/somecommand
ignore_errors: True
在使用变量之前最好先知道什么是合法的变量名. 变量名可以为字母,数字以及下划线.变量始终应该以字母开头
- hosts: webservers
vars: #变量
http_port: 80
我们可以在playbook文件中引用变量
- hosts: webservers
vars:
base_dir: /usr/local/nginx
shell: {{ base_dir }}/sbin/nignx
我们也可以通过template模块将变量引用到文件当中,Ansible允许你使用Jinja2模板系统在playbook中引用变量
例如:
我们创建文件file.j2,内容:
mysql name is {{ user_name }}
在playbook文件中定义变量:
- hosts: webservers
vars:
user_name: tom
tasks:
- name: copy a fille to host
template: src=file.j2 dest=/root/
template常用于配置文件的推送,我们可以把一些常用的参数,例如nginx的监听地址,网站根目录,网站域名等!我们可以把这些参数都做成变量,然后在配置文件中引用,这样我们以后只需更改playbook文件中变量的值即可!增加了配置的灵活度
YAML语法要求如果值以{{ foo }}开头的话我们需要将整行用双引号包起来.这是为了确认你不是想声明一个YAML字典!
错误的写法:
- hosts: app_servers
vars:
app_path: {{ base_path }}/22
正确的写法:
- hosts: app_servers
vars:
app_path: "{{ base_path }}/22"
在ansible中有些自带的变量,不需要用户定义,直接引用就可以
Facts通过访问远程系统获取相应的信息,比如像查看远程主机的ip地址和系统版本,那么我们可以执行:
ansible hostname -m setup
不过这样执行会返回非常多的变量数据!这里面的变量我们都可以直接引用!
例如{{ ansible_hostname }}就可以获取远程主机的主机名,{{ ansible_eth0[“ipv4”][“address”] }}获取eth0的ipv4的ip地址,当然这些变量我们也可以通过template模块,直接在模板文件中引用
我们有时可能会有敏感数据存放到playbook当中的情况,比如账号密码等!那么如果直接公开我们的playbook源码可能会有隐私数据泄露的情况!那么我么可以把这些敏感数据可以跟playbook进行分割!
我们可以把变量在一个外部变量文件中定义:
---
somevar: somevalue
password: magic
在playbook中直接引用这个变量文件
---
- hosts: all
remote_user: root
vars:
favcolor: blue
vars_files:
- /vars/vars.yml
tasks:
- name: this is just a placeholder
command: /bin/echo foo
我们可以使用handlers定义一些触发任务,这些触发任务可以在其他的任务中调用,但是执行条件是该任务有更改时才会触发这些触发任务!比如如下例子:
- 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=apache state=restarted
重启memcache和apache只有当我们使用template模块分发的配置文件有更改时才会被执行,如果配置文件没有更改则不会执行重启
Handlers 最佳的应用场景是用来重启服务,或者触发系统重启操作.除此以外很少用到了.
在一个playbook中,我们一般会定义很多个task,如果我们只想执行其中的某一个task或多个task时就可以使用tags标签功能了
---
hosts: webservers
remote_user: root
tasks:
- name: make sure apache is running #任务名
service: name=httpd state=running #运行Apache
tags:
- apache
- name: touch file
file: path=/opt/hosts state=touch
之后我们可以使用ansible-playbook --tags=“apache” fileName.yml 就可以只运行playbook中指定标签的task了
在有些时候我们需要选择主机去执行不同的任务,比如我们在关闭防火墙的时候,Centos6和Centos7关闭的方式是不同的,所有我们需要判断主机的系统版本来执行对应的任务
在Ansible中,使用when子句很容易做到这一点,该子句包含不带双花括号的原始Jinja2表达式
tasks:
- name: "shut down Debian flavored systems"
command: /sbin/shutdown -t now
when: ansible_facts['os_family'] == "Debian"
# 注意,所有变量都可以直接在条件语句中使用,而不需要双花括号
还可以使用括号对条件进行分组:
tasks:
- name: "shut down CentOS 6 and Debian 7 systems"
command: /sbin/shutdown -t now
when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or
(ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")
也可以将多个都必须为真的条件(逻辑“和”)指定为列表:
tasks:
- name: "shut down CentOS 6 systems"
command: /sbin/shutdown -t now
when:
- ansible_facts['distribution'] == "CentOS"
- ansible_facts['distribution_major_version'] == "6"