之前有写过基于简单的ansible命令的方式对多台服务器进行批量操作,但是这种方式不适用于复杂场景的应用,于是我们可以使用playbook以及roles实现复杂任务的部署和批量操作,这是单纯Ansible命令无法实现的。
ansible-playbook是一系列ansible命令的集合。通过Playbook任务,能够集中管理多个任务,将多个任务关联起来,从而实现更加复杂工作,满足生产环境的各个需求,提高运维人员管理服务器效率
playbook使用YAML文件编写,类似XML接口(Tomcat)文件,内部有固定语法、参数等,要掌握常用的YAML语法编写,掌握满足运维管理方向的语法即可。
ansible-playbook命令常跟有一些选项,常用的选项如下:
常用选项示例:
# yaml文件语法检测
$ ansible-playbook --syntax-check test_echo.yml
playbook: test_echo.yml // 这样代表语法没有错误
# 预测试看是否能执行成功,不会真正执行
$ ansible-playbook -C test_echo.yml
159.75.83.204 : ok=1 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
42.194.184.177 : ok=1 changed=0 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
# 查看受影响的主机
$ ansible-playbook --list-hosts test_echo.yml
playbook: test_echo.yml
play #1 (tencent): tencent TAGS: []
pattern: ['tencent']
hosts (2):
42.194.184.177
159.75.83.204
# 查看文件中的标签
$ ansible-playbook --list-tags test_echo.yml
playbook: test_echo.yml
play #1 (tencent): tencent TAGS: []
TASK TAGS: []
通常情况下可以先执行 ansible-playbook -C命令进行测试,测试没问题后再执行 ansible-playbook 命令。
编写一个简单的playbook示例,用到常用的命令模块,tags的使用,以及handlers的用法。示例如下:
---
- hosts: tencent
remote_user: root
vars:
- filename: test.txt
tasks:
- name: 创建playbook文件夹
file: path=/tmp/playbook state=directory
- name: cd到 /usr/ 目录下执行Ls
command: chdir=/usr/ ls
tags: ls
notify: # 配置触发条件
- touch file test # 指定要执行的handlers名字
handlers: # 配置handlers,名字用来给notify触发
- name: touch file test
shell: cd /tmp/playbook/ && touch {{ filename }}
这个playbook执行后,会创建/tmp/playbook/目录如果该目录不存在,并显示/usr/目录下的所有文件及文件夹,最后通过notify执行对应的handlers模块创建一个test.txt文件。
一个动作可以执行多个标签,也可以多个动作执行多个标签,执行标签动作需要加上-t选项:
# 通过tags方式执行,只会执行标记了tags相关的任务
ansible-playbook -t "ls" Ansible/Playbooks/test_echo.yml
# 执行tags以外的内容
ansible-playbook --skip-tags='ls' Ansible/Playbooks/test_echo.yml
变量定义有几种不同的方式:
# playbooks文件
- hosts: tencent
remote_user: root
vars:
- filename: test.txt
vars_files: # 引用变量文件
- ./var.yml # 指定变量文件的path(这里可以是绝对路径,也可以是相对路径)
tasks:
- name: 创建playbook文件夹
file: path=/tmp/playbook state=directory
- name: cd到 /usr/ 目录下执行Ls
command: chdir=/usr/ ls
tags: ls
notify: # 配置触发条件
- touch file test # 指定要执行的handlers名字
handlers: # 配置handlers,名字用来给notify触发
- name: touch file test
shell: cd /tmp/playbook/ && touch {{ filename }},{{filename1}}
# ansible-playbook命令
ansible-playbook -e “filename=test.txt,filename1=test1.txt” Ansible/Playbooks/test_echo.yml
# playbook的yaml文件
如上图,在vars中定义变量filename,直接以双括号方式使用:{{ filename }}
# 配置的host文件
$ cat /etc/ansible/host
[tencent]
42.194.184.177
159.75.83.204
[tencent:vars]
filename=test.txt
# 独立的yaml文件
$ cat var.yml
filename: test.txt
filename1: test1.txt
有些时候需要在满足特定的条件后再触发某一项操作,或在特定的条件下终止某个行为,这个时候需要进行条件判断,when正是解决这个问题的最佳选项。
通过操作系统的类型来判断如何执行,ansible_os_family是内置的变量,示例如下,:
---
- hosts: tencent
remote_user: root
vars:
- var1: test.txt
tasks:
- name: 如果系统是centos执行
file: path=/tmp/test state=directory
when: ansible_os_family == 'RedHat'
- name: 如果系统是Ubuntu执行
file: path=/tmp/test1 state=directory
when: ansible_os_family == 'Debian'
有时候我们还需要更复杂的例子,如判断前一个命令的执行结果去处理后面的操作,这时候就需要register模块来保存前一个命令的返回状态,在后面进行调用
示例如下,:
---
- hosts: tencent
remote_user: root
tasks:
- name: 获取系统负载
shell: uptime | awk '{printf("%.2f\n",$(NF-2))}'
register: result # 将上面的结果注册成一个变量result,在后面可以调用
- name: 负载大则创建
file: path=/tmp/test2 state=directory
when: result.stdout | float > 0.7
with_items方式
with_items是playbook的标准循环,可以用于迭代一个列表或者字典,通过{{ item }}获取每次迭代的值
示例如下:
---
- hosts: tencent
remote_user: root
tasks:
- name: 循环创建文件
file: path=/tmp/test2/{{ item }} state=touch
with_items:
- test1.txt
- test2.txt
- test3.txt
也可以通过更复杂的嵌套子变量的形式,示例如下:
---
- hosts: tencent
remote_user: root
tasks:
- name: 循环创建文件
file: path=/tmp/test2/{{ item.name }}.{{item.type}} state=touch
with_items:
- {name: 'test1',type: 'txt'}
- {name: 'test2',type: 'yaml'}
- {name: 'test3',type: 'conf'}
with_items: # 另一种形式
-
name: test1
type: txt
-
name: test2
type: yaml
# 创建后的文件目录
-rw-r--r-- 1 root root 0 4月 21 10:56 test1.txt
-rw-r--r-- 1 root root 0 4月 21 10:53 test2.txt
-rw-r--r-- 1 root root 0 4月 21 10:56 test2.yaml
-rw-r--r-- 1 root root 0 4月 21 10:56 test3.conf
-rw-r--r-- 1 root root 0 4月 21 10:53 test3.txt
还有其他很多种方式的循环,可以在需要用到时查询官方文档或百度,此处不一一详解。
template本质上是一个模版文件,为我们提供了动态配置服务,使用jinja2语言,里面支持多种条件判断、循环、逻辑运算、比较操作等。
多数情况下都将template文件放在和playbook文件同级的templates目录下(手动创建),这样playbook文件中可以直接引用,会自动去找这个文件。如果放在别的地方,也可以通过绝对路径去指定。
jinja2 语言使用字面量,有下面形式:
一个简单的templates文件定义,遵循jinja2语法,变量tencent定义在playbooks中:
worker_processes {{ ansible_processor_vcpus*2 }}
worker_processes {{ ansible_processor_vcpus+2 }}
{% for host in tencent %}
{% if host.name %}
server_name {{ host.name }}
{% endif %}
{% endfor %}
playbooks文件定义:
---
- hosts: tencent
remote_user: root
vars:
tencent:
- host1:
name: 123
- host2:
name: 456
tasks:
- name: 测试template文件
template: src=test1.txt.j2 dest=/tmp/test2/text1.txt
执行后,在服务器上查看文件结果:
$ cat text1.txt
worker_processes 4
worker_processes 4
server_name 123
server_name 456
templates文件的具体用法和示例不在此一一详解。