ansible的playbook进阶(五)
http://blog.51niux.com/?id=46 看到这里也只是能写一些简单的playbook,里面有好多需要注意的知识点需要继续了解。
一、playbook的附加特性
1.1 local_action(在控制主机上运行task)
Ansible 默认只会对控制机器执行操作,如果希望在控制主机上面运行一个特定的task。
--- - name: wait for ssh server to be running hosts: 7servers tasks: - name: wait for ssh server to be running local_action: wait_for port=22 host={{ inventory_hostname }} search_regex=OpenSSH #local_action就是在服务器本机执行,wait_for就是等待什么,这里就是等待ssh连接成功
#上面这个例子就是先将这个等待ssh连接放到第一个task,如果成功再进行后面的task,如果ssh连接都不成功就等待会,但是很快也会报超时。一般不设置
1.2 serial逐台主机运行
一般情况下, ansible会同时在所有服务器上执行用户定义的操作, 但是用户可以通过serial参数来定义同时可以在多少台机器上执行操作.
- name: test play hosts: webservers serial: 2
#如从负载均衡中移除主机并更新软件包,这里serial设置了2,就是两台主机两台主机的执行,但是如果有两台主机失败了,是会停止执行失败的主机上的任务,但是还会继续在其他主机上执行。
- hosts: webservers max_fail_percentage: 25 serial: 2
#如果我们想当我们这个组里的主机失败的比例到达多少的时候,就让整个play失败的话,可以通过max_fail_percentage来设置百分比。如果失败主机的超过25%就会停止,架设我们有四台web,那就是两台失败就会停止play,因为一台失败还是25%,并未超过25%。max_fail_percentage设置为0,就是有任何主机出现task执行失败都会放弃执行play。
1.3 run_once只执行一次
因为我们的playbook里面要设计主机组,所以某个task会根据主机组里面主机的数量执行多次。比如我们负载均衡后面的web服务器,配置文件都一致。我们就想执行一次备份配置文件,或者代码就可以了,不想执行多次的task。就需要用到run_once了。
在某条task下面加上run_once: true。就是让本条task只运行一次。
- command: /opt/scripts/backup.sh run_once: true delegate_to: 192.168.1.111 #可以结合delegate_to(任务委派功能),表示只在192.168.1.111这台主机上面执行。如果不加这句话,第一个执行的主机会负责执行此条task。
当然我们也可以跟local_action结合,防止local_action的一条task执行多次:
--- - name: local env test hosts: 7servers tasks: - name: local test shell: echo "{{ ansible_distribution }}-{{ansible_distribution_version}}" >>/tmp/test #将两个客户端fact的变量记录到/tmp/test文件 connection: local run_once: true
#connection: local是local_action的另外一种实现形式。这个例子挺有用的,比如我们要编写playbook的时候会涉及到各种取客户端的变量,当然变量是不是我们想要的值我们不确定,得测试,这种就是将我们要取的变量的值记录到ansible服务端的指定文件中去,然后我们看看这个文件就知道我们取的值是不是我们想要的了,但是如果不用run_once的话,如果一个组里面主机过多,会重复的记录多条语句,我们不需要那么多重复的就需要一条的时候就加上run_once。
查看下产生的文件的内容(此文件是在ansible服务端哦并非在ansible客户端):
1.4 使用Vault加密敏感数据
Ansible 1.5的新版本中, “Vault” 作为 ansible 的一项新功能可将例如passwords,keys等敏感数据文件进行加密,而非存放在明文的 playbooks 或 roles 中. 这些 vault 文件可以分散存放也可以集中存放.
通过`ansible-vault` 来编辑文件,经常用到的命令如 –ask-vault-pass , –vault-password-file . 这里,你可以在 ansible.cfg 中定义密码文件所在位置,这个选项就不需要在命令行中指定标志了.
ansible-vault命令:
ansible-vault encrypt file.yaml #加密明文文件file.yaml ansible-vault decrypt file.yaml #解密已加密的文件file.yaml ansible-vault view file.yaml #打印已加密文件file.yaml的内容 ansible-vault create file.yaml #创建新的加密文件file.yaml ansible-vault edit file.yaml #编辑已加密的文件file.yaml ansible-vault rekey file.yaml #变更已加密文件file.yaml的密码
博文来自:www.51niux.com
二、控制让哪些主机来执行task
2.1 patterns(主机与组正则匹配部分)
通配模式Patterns,在Ansible 中,Patterns 意味着要管理哪些机器,在playbooks 中,意味着哪些主机需要应用特定的配置或者过程.
all : 表示匹配所有主机 * : 表示匹配所有主机(但是不能写在playbooks里面) [1:10] : 表示数字范围
#剩下的匹配规则看下面的举例。
# cat /etc/ansible/hosts #以这个简单的hosts文件为例
[webservers] 192.168.1.112 192.168.1.113 192.168.1.109 [dbservers] 192.168.1.109 192.168.1.111 192.168.1.112 [masterhost] 192.168.1.108 [7servers] 192.168.1.121 192.168.1.122
不管是并集、交集还是什么的,都是在playbook文本中的hosts那一行写的。如:hosts: webservers:dbservers
例1:设置并集
hosts: webservers:dbservers #查看执行结果
例2:设置交集
hosts: webservers:&dbservers #查看执行结果
例3:排除某个组
hosts: all:!dbservers #所有主机里面就排除dbservers组里面的主机,下面查看执行结果
hosts: webservers:!dbservers #这个就是webservers组里面有,但是dbservers里面没有的主机,下面查看执行结果
#从图中可以看出只有192.168.1.113运行了(这里的重点是要输出的组为webservers组里面的主机,只是又匹配了下,dbservers组里面的主机要是跟webservers组里面的主机重合了,那么webservers组就会把这些重合的主机去掉)
例4:通配符匹配
hosts: 192.168.1.12* #匹配所有192.168.1.12开头的主机(hosts文件里面定义的,其实它去找的是hosts文件里面定义的主机名或者别名,只不过我们这里全设置的IP地址,这点要搞清楚),当然我这里hosts里面没设置主机名,还可以如:*.51niux.com等之类的,*就是通配符嘛
hosts: :*servers #取出所有以通配符servers结尾的组,重点是*.servers前面有个:哦,如果直接*.servers会报错的
# hosts: masterhost:*servers #当然混合使用也可以,取出masterhost组和所有servers结尾组的并集
例5:正则表达式
正则表达式永远以~开头,这是要注意的地方。
hosts: ~servers #匹配所有包含servers的组
hosts: ~servers$ #匹配所有以servers结尾的组
hosts: ~192.168.1.12 #匹配主机名包含192.168.1.12的主机,当然如果hosts里面主机名不是IP的形式,还可以是:~web\d\.example\.com的形式。
2.2 限定某些主机运行
首先要明确一点,这个限定主机运行,是playbooks里面定义的hosts里面规定的哪些主机作为你限定的范围。-l等同于--limit.
如:hosts: webservers (这个里面的主机有:192.168.1.112、192.168.1.113 、192.168.1.109)
# ansible-playbook -l dbservers local_yest.yaml #dbservers组里有(192.168.1.109、192.168.1.111、192.168.1.112)
#所以这个限定主机运行有点求交集的意思,就是在你规定的hosts组里主机再限定一次缩小下范围。
# ansible-playbook -l 192.168.1.109 local_yest.yaml #当然也可以限定主机
# ansible-playbook -l 'webservers:&dbservers' local_yest.yaml #当然也可以再外部引用组的交集并集啥的来限定
2.3 过滤器
过滤器是Jinja2模板引擎的特性。Ansible除了使用Jinja2作为模板之外,还将其用于变量求职,所以除了模板之外,还可以在playbook中在{{}}内使用过滤器。详细内容请看:http://docs.ansible.com/ansible/playbooks_templating.html
default过滤器
tasks: - name: local test shell: echo "{{ databse | default('localhost') }}" >/tmp/test connection: local run_once: true
#如果database已被定义,那么括号就会将直接获取这个变量的值,相反如果database没有被定义,那么括号就取值为字符串localhost。
用于注册变量的过滤器
前面记录了ignore_errors: True可以忽略task失败主机,让task继续执行,但是只是显示报错最后的汇总信息里面只显示了哪些主机执行成功了。
register 关键字可以存储指定命令的输出结果到一个自定义的变量中,我们通过访问这个自定义变量就可以获取到命令的输出结果。
--- - name: filters test hosts: 7servers tasks: - name: mkdir testdir command: mkdir /opt/test register: result ignore_errors: True - debug: msg="stop running playbook fail host" failed_when: result|failed
#failed_when其实是ansible的一种错误处理机制,是由fail模块使用了when条件语句的组合效果。
先看不加 failed_when: result|failed(我们测试的时候始终保持有一个能正常,才能来区分):
#从图中可以看出虽然192.168.1.122有个报错提示目录已经存储不能创建了,但是后面的结果是两个OK,failed哪里也是0.
下面我们将failed_when: result|failed加上查看一下:
#从图中可以看出效果出来了,192.168.1.122执行palybook过程中,确实有报错,最后的结果也显示192.168.1.122有一个报错,注意它的failed哪里是true
下面是对注册变量检查状态的过滤器:
failed : 如果注册变量的值是任务failed则返回True
changed : 如果注册变量的值是任务changed则返回True
success : 如果注册变量的值是任务success则返回True
skipped: 如果注册变量的值是任务skipped则返回True
博文来自:www.51niux.com
三、lookup
做playbook的扩展的。 设立一个变量,但是这个变量是不固定的,需要每次推送playbook的时候,做更新的,就可以考虑lookup了。
ansible支持从不同来源获取数据的lookup:
file : 文件内容
password : 随机生成一个密码
pipe : 本地命令执行的输出
env : 环境变量
template : Jinja2 模板渲染的结果
csvfile : .csv文本的条目
dnstxt : DNS的TXT记录
redis_kv : 对Redis的key进行查询
etcd : 对etcd中的key进行查询
file举例:
--- - name: lookup yaml test hosts: 7servers vars: contents: "{{ lookup('file', '/home/yunwei/.ssh/id_rsa.pub') }}" #这里通过lookup将本地/home/yunwei/.ssh/id_rsa.pub里的内容赋值给了变量contents tasks: - debug: msg="the value of id_rsa.pub is {{ contents }}" #然后可以打印一下,看看是不是将文件里面的内容取出来了
#上面的例子是一个简单的取出本地文件里面的内容并打印出来。
下面的例子为将一个其他用户的公钥分发给被控制端:
--- - name: lookup yaml test hosts: 7servers tasks: - name: create yunwei user user: name=yunwei uid=3002 - name: create yunwei key dir file: name=/home/yunwei/.ssh state=directory owner=yunwei group=yunwei - name: cp is_rsa.pub to hosts template: src=yunwei_authorized_keys.j2 dest=/home/yunwei/.ssh/authorized_keys owner=yunwei group=yunwei
# cat yunwei_authorized_keys.j2
{{ lookup('file', '/home/yunwei/.ssh/id_rsa.pub') }} #在jinja2模板中调用lookup,把秘钥的内容放到此文件中,注意这文件内容是本机的文件的内容。
# ssh yunwei@192.168.1.121 -i /home/yunwei/.ssh/id_rsa #在ansible控制机上面登录测试一下,下图为结果
pipe举例
pipe lookup在控制主机上调用一个外部程序,并将这个程序的输出,pipe 这个就是调用 subprocess 模块执行命令。
tasks: - name: get ansible version debug: msg="{{ lookup('pipe','ansible --version') }}" #把ansible --version的结果输出,这个类似于将命令结果传参。
template举例
template lookup让你指定一个Jinja2模板文件,让后返回这个模板渲染的结果。
tasks: - name: output message from template debug: msg="{{ lookup('template','yunwei_authorized_keys.j2') }}"