1、加速模式运行playbook
accelerate
对于使用ansible 1.5 及之后版本的用户,加速模式只在以下情况下有用处:
(A) 管理红帽企业版 Linux 6 或者更早的那些依然使用 paramiko 的版本
(B) 像在文档中描述的那样:无法在 TTYs 中使用 sudo.
#只需在你的 play 中添加 accelerate: true 即可使用加速模式: --- - hosts: all accelerate: true tasks: - name: some task command: echo {{ item }} with_items: - foo - bar - baz #如果你希望改变 Ansible 用于加速模式的端口,你只需添加 accelerated_port 选项: --- - hosts: all accelerate: true # default port is 5099 accelerate_port: 10000 #accelerate_port 选项也同样能通过指定环境变量 ACCELERATE_PORT 或者在你的 ansible.cfg 中配置: [accelerate] accelerate_port = 5099
2、异步操作和轮询
async
poll
async_status
默认情况下playbook中的任务执行时会一直保持连接,直到该任务在每个节点都执行完毕.有时这是不必要的,比如有些操作运行时间比SSH超时时间还要长.
解决该问题最简单的方式是一起执行它们,然后轮询直到任务执行完毕.
你也可以对执行时间非常长(有可能遭遇超时)的操作使用异步模式.
为了异步启动一个任务,可以指定其最大超时时间以及轮询其状态的频率.
如果你没有为 poll 指定值,那么默认的轮询频率是10秒钟:
--- - hosts: all remote_user: root tasks: - name: simulate long running op (15 sec), wait for up to 45 sec, poll every 5 sec command: /bin/sleep 15 async: 45 poll: 5
async 并没有默认值,如果你没有指定 async 关键字,那么任务会以同步的方式运行,这是Ansible的默认行为.
另外,如果你不需要等待任务执行完毕,你可以指定 poll 值为0而启用 “启动并忽略”
--- - hosts: all remote_user: root tasks: - name: simulate long running op, allow to run for 45 sec, fire and forget command: /bin/sleep 15 async: 45 poll: 0
对于要求排它锁的操作,如果你需要在其之后对同一资源执行其它任务,那么你不应该对该操作使用”启动并忽略”.比如yum事务.
--forks
参数值过大会更快的触发异步任务.也会加快轮询的效率.
当你想对 “启动并忽略” 做个变种,改为”启动并忽略,稍后再检查”,你可以使用以下方式执行任务:
--- # Requires ansible 1.8+ - name: 'YUM - fire and forget task' yum: name=docker-io state=installed async: 1000 poll: 0 register: yum_sleeper - name: 'YUM - check on fire and forget task' async_status: jid={{ yum_sleeper.ansible_job_id }} register: job_result until: job_result.finished retries: 30
如果 async:
值太小,可能会导致 “稍后检查” 任务执行失败,因为 async_status::
的临时状态文件还未被写入信息,而”稍后检查”任务就试图读取此文件.
3、检查模式运行playbook(dry run)
--check
--diff
--limit
当以 --check
参数来运行 ansible-playbook 时,将不会对远程的系统作出任何更改.
相对的,任何带有检测功能的模块(这几乎包含了所有的主要核心模块,但这不要求所有的模块都需支持.) 只要支持 ‘检测模式’ 将会报告它们会做出什么改变而不是直接进行改变.其他不支持检测模式的模块将既不响应也不提出相应的报告.
检测模式只是一种模拟.如果你的playbook是以先前命令的执行结果作为条件的话,那它可能对你就没有什么大用处了. 但是对于基于一次一节点的基础配置管理的使用情形来说是很有用.
Example:
ansible-playbook foo.yml --check
有时候你甚至会想在检测模式中执行一个任务.为了达到这样的效果, 你需要在相应的任务上使用 always_run 子句.跟 when 子句一样,它的值是一个 Jinja2 表达式. 在一个简单的例子中,布尔值也会表达为一个适当的 YAML 值.
Example: tasks: - name: this task is run even in check mode command: /something/to/run --even-in-check-mode always_run: yes
友情提示,带有 when 子句的任务会返回false,该任务将会被跳过,即使它还被添加了会返回true的 always_run 子句.
对 ansible-playbook 来说 --diff
选项与 --check
(详情参下)配合使用效果奇佳,不过它也可以单独使用.当提供了相应的标识后,当远程系统上任何模板文件的变化时,ansible-playbook CLI 将会报告文件上任何文本的变化 (或者,如果使用了 --check
参数,将报告会发生的变化.).因为 diff 特性会产生大量的输出结果,所以它在一次检测一个主机时使用为佳,如:
ansible-playbook foo.yml --check --diff --limit foo.example.com
4、滚动更新
serial
由于设计初衷是作为多用户,Anisible很擅长在某一个主机上代表另一个做事,或者参考远程主机做一些本地工作.
这个特性对于架设连续实现某些设施或者无缝滚动升级,这里你可能会提到负载均衡或者监控系统.
更多的特性允许调试事情完成的顺序,和设置一批窗口,来确定多少机器在一次中滚动更新.
默认来说,Anisble 可以试图参考某一个play来并行操作所有主机.对于滚动更新案例,你可以使用’‘serial’’ 关键词来定义Ansible在一个特定时间同时控制多少主机:
- name: test play hosts: webservers serial: 3
在上面的例子,如果我们有100台主机,3 台主机定义在组’webservers’ 可以在下面3个主机开始之前完全完成
这个’‘serial’’ 关键词在Ansible 1.8 以后可以被定义为百分数,用来定义每一次操作一个play中百分之多少主机:
- name: test play hosts: websevers serial: "30%"
如果主机数不能被passes数量整除,最后的pass将会包含提醒信息,不管多小的百分比,每个pass的主机数一定会大于等于1.
默认来说,Ansible 会持续执行,只要在一个组中还有主机没有宕机.
在有些情况下,例如之前提到的滚动更新,也许理想的情况是当一个失败数上限达到时,主动宕掉这个play.
为了达到这个目的,在 1.3版本中,你可以设置最大失败半分比:
- hosts: webservers max_fail_percentage: 30 serial: 10
在上面的例子中,如果在10个服务器中如果多余3个,其它的play就会主动宕掉.这个百分比必须被超过,不仅仅是相等.
例如如果serial值呗设置为4,并且你希望任务主动在2个系统失败时候放弃.那么这个百分比应该设置为49而不是50.
5、委任
delegate_to
local_action
如果你想参考其它主机来在一个主机上执行一个任务,我们就可以使用’delegate_to’关键词在你要执行的任务上.
这个对于把节点放在一个负载均衡池里面活着从里面移除非常理想. 这个选项也对处理窗口中断非常有用. 使用’serial’关键词来控制一定数量的主机也是一个好想法:
--- - hosts: webservers serial: 5 tasks: - name: take out of load balancer pool command: /usr/bin/take_out_of_pool {{ inventory_hostname }} delegate_to: 127.0.0.1 - name: actual steps would go here yum: name=acme-web-stack state=latest - name: add back to load balancer pool command: /usr/bin/add_back_to_pool {{ inventory_hostname }} delegate_to: 127.0.0.1
--- # ... tasks: name: take out of load balancer pool local_action: command /usr/bin/take_out_of_pool {{ inventory_hostname }} # ... name: add back to load balancer pool local_action: command /usr/bin/add_back_to_pool {{ inventory_hostname }}
A common pattern is to use a local action to call ‘rsync’ to recursively copy files to the managed servers. Here is an example:
--- # ... tasks: - name: recursively copy files from management server to target local_action: command rsync -a /path/to/files {{ inventory_hostname }}:/path/to/target/
6、本地执行playbook
connection
在本地使用playbook有时候比ssh远程使用更加有用.可以通过把playbook放在crontab中,来确保一个系统的配置,可以很有用.
在OS installer 中运行一个playbook也很有用.例如Anaconda kickstart.
要想在本地运行一个play,可以直接设置”host:” 与 “hosts:127.0.0.1”, 然后使用下面的命令运行:
ansible-playbook playbook.yml --connection=local
或者,一个本地连接也可以作为一个单独的playbook play应用在playbook中, 即便playbook中其他的plays使用默认远程 连接如下:
- hosts: 127.0.0.1 connection: local
7、只运行一次任务
run_once
有时候你有这样的需求,在一个主机上面只执行一次一个任务.这样的配置可以配置”run_once”来实现:
--- # ... tasks: # ... - command: /opt/application/upgrade_db.py run_once: true # ...
这样可以添加在”delegat_to”选项对中来定义要执行的主机:
- command: /opt/application/upgrade_db.py run_once: true delegate_to: web01.example.org
当”run_once” 没有和”delegate_to”一起使用,这个任务将会被清单指定的第一个主机.
在一组被play制定主机.例如 webservers[0], 如果play指定为 “hosts: webservers”.
这个方法也很类似,虽然比使用条件更加简单粗暴,如下事例:
- command: /opt/application/upgrade_db.py when: inventory_hostname == webservers[0]
8、配置环境运行,如代理上网
environment
你完全有可能遇到一些更新包需要通过proxy才能正常获取,或者甚至一部分包需要通过proxy升级而另外一部分包则不需要通过proxy.
或者可能你的某个脚本需要调用某个环境变量才能正常运行.
Ansible 使用 ‘environment’ 关键字对于环境部署的配置非常简单容易,下面是一个使用案例:
- hosts: all remote_user: root tasks: - apt: name=cobbler state=installed environment: http_proxy: http://proxy.example.com:8080
environment 也可以被存储在变量中,像如下方式访问:
- hosts: all remote_user: root # here we make a variable named "proxy_env" that is a dictionary vars: proxy_env: http_proxy: http://proxy.example.com:8080 tasks: - apt: name=cobbler state=installed environment: proxy_env
虽然上面只展示了 proxy 设置,但其实可以同时其实支持多个设置. 大部分合合乎逻辑的地方来定义一个环境变量都可以成为 group_vars 文件,示例如下:
--- # file: group_vars/boston ntp_server: ntp.bos.example.com backup: bak.bos.example.com proxy_env: http_proxy: http://proxy.bos.example.com:8080 https_proxy: http://proxy.bos.example.com:8080
9、playbook中错误处理
ignore_errors
failed_when
fail
change_when
Ansible 通常默认会确保检测模块和命令的返回码.
有时一条命令会返回 0 但那不是报错.有时命令不会总是报告它 ‘改变’ 了远程系统.
本节描述了 如何将 Ansible 处理输出结果和错误处理的默认行为改变成你想要的.
1、忽略错误命令
通常情况下, 当出现失败时 Ansible 会停止在宿主机上执行.有时候,你会想要继续执行下去.为此 你需要像这样编写任务:
- name: this will not be counted as a failure command: /bin/false ignore_errors: yes
注意上面的系统仅仅处理那个特定的任务,所以当你在使用一个未定义的变量时, Ansible 仍然会报 错,需要使用者进行处理.
2、控制对失败的定义
假设一条命令的错误码毫无意义,只有它的输出结果能告诉是你什么出了问题,比如说字符串 “FAILED” 出 现在输出结果中.
在 Ansible 1.4及之后的版本中提供了如下的方式来指定这样的特殊行为:
- name: this command prints FAILED when it fails command: /usr/bin/example-command -x -y -z register: command_result failed_when: "'FAILED' in command_result.stderr"
3、覆写返回结果
当一个 shell或命令或其他模块运行时,它们往往都会在它们认为其影响机器状态时报告 “changed” 状态,
- 有时你可以通过返回码或是输出结果来知道它们其实并没有做出任何更改.
- 你希望覆写结果的“changed” 状态,使它不会出现在输出的报告或不会触发其他处理程序:
tasks: - shell: /usr/bin/billybass --mode="take me to the river" register: bass_result changed_when: "bass_result.rc != 2" # this will never report 'changed' status - shell: wall 'beep' changed_when: False
10、标签
tags
如果你有一个大型的 playbook,那能够只运行其中特定部分的配置而无需运行整个 playbook 将会很有用.
plays 和 tasks 都因这个理由而支持 “tags”
tasks: - yum: name={{ item }} state=installed with_items: - httpd - memcached tags: - packages - template: src=templates/src.j2 dest=/etc/foo.conf tags: - configuration
如果你只想运行一个非常大的 playbook 中的 “configuration” 和 “packages”,你可以这样做:
ansible-playbook example.yml --tags "configuration,packages"
另一方面,如果你只想执行 playbook 中某个特定任务 之外 的所有任务,你可以这样做:
ansible-playbook example.yml --skip-tags "notification"
你同样也可以对 roles 应用 tags:
roles: - { role: webserver, port: 5000, tags: [ 'web', 'foo' ] }
你同样也可以对基本的 include 语句使用 tag:
- include: foo.yml tags=web,foo
11、从指定任务开始运行playbook,分步运行playbook
--start-at
--step
如果你想从指定的任务开始执行playbook,可以使用``–start-at``选项:
ansible-playbook playbook.yml --start-at="install packages"
以上命令就会在名为”install packages”的任务开始执行你的playbook.
我们也可以通过``–step``选项来交互式的执行playbook:
ansible-playbook playbook.yml --step
这样ansible在每个任务前会自动停止,并询问是否应该执行该任务.
比如你有个名为``configure ssh``的任务,playbook执行到这里会停止并询问:
Perform task: configure ssh (y/n/c):
“y”回答会执行该任务,”n”回答会跳过该任务,而”c”回答则会继续执行剩余的所有任务而不再询问你.
12、vault加密文件
ansible-vault
--ask-vault-pass
--vault-password-file
Ansible 1.5的新版本中, “Vault” 作为 ansible 的一项新功能可将例如passwords,keys等敏感数据文件进行加密,
而非存放在明文的 playbooks 或 roles 中. 这些 vault 文件可以分散存放,也可以集中存放.
通过`ansible-vault` 来编辑文件,经常用到的命令如 –ask-vault-pass , –vault-password-file .
你可以在 ansible.cfg 中定义密码文件所在位置,这个选项就不需要在命令行中指定标志了.
Vault可以加密些什么
vault 可以加密任何 Ansible 使用的结构化数据文件. 甚至可以包括:
“group_vars/” 或 “host_vars/” inventory 变量,
“include_vars” 或 “vars_files” 加载的变量,
通过 ansible-playbook 命令行使用 “-e @file.yml” 或 “-e @file.json” 命令传输的变量文件,
role变量,
所有默认的变量都可以被 vault 加密.
因为 Ansible tasks, handlers等都是数据文件, 所有的这些均可以被 vault 加密. 如果你不喜欢你使用的变量被泄漏,你可以将整个 task 文件部分加密.
不过,这个工作量比较大而且可能给你的同事带来不便哦 !
创建加密文件
执行如下命令,创建加密文件:
ansible-vault create foo.yml
首先你将被提示输出密码, 经过Vault加密过的文件如需查看需同时输入密码后才能进行.
提供密码后, 工具将加载你定义的 $EDITOR 的编辑工具默认是 vim, 一旦你关闭了编辑会话框,生成后的文件将会是加密文件.
默认加密方式是 AES (基于共享密钥)
编辑加密文件
编辑加密文件,使用 ansible-vault edit . 该命令会先加密文件为临时文件并允许你编辑这个文件,当完成编辑后会保存回你所命名的文件并删除临时文件:
ansible-vault edit foo.yml
加密普通文件
如果你希望加密一个已经存在的文件,使用 ansible-vault encrypt . 该命令也可同时批量操作多个文件:
ansible-vault encrypt foo.yml bar.yml baz.yml=
解密已加密文件
如果不希望继续加密一个已经加密过的文件,通过 ansible-vault decrypt 你可以永久解密. 命令将解密并保存到硬盘上,这样你不用再使用 ansible-vault edit 来编辑文件了:
ansible-vault decrypt foo.yml bar.yml baz.yml
查阅已加密文件
Available since Ansible 1.8
如果你不希望通过编辑的方式来查看文件, ansible-vault view 可以满足你的需要:
ansible-vault view foo.yml bar.yml baz.yml
在Vault下运行Playbook
执行 vault 加密后的playbook文件,最少需要提交如下两个标志之一. 交互式的指定 vault 的密码文件:
ansible-playbook site.yml --ask-vault-pass
该提示被用来解密(仅在内存中)任何 vault 加密访问过的文件. 目前这些文件中所有的指令请求将被使用相同的密码加密.
另外,密码也可以定义在一个文件或者一个脚本中,但是需要 Ansible 1.7 以上的版本才能支持.
当使用该功能时,一定要确认密码文件的权限是安全的,以确保没有人可以随意访问或者变更密码文件:
ansible-playbook site.yml --vault-password-file ~/.vault_pass.txt ansible-playbook site.yml --vault-password-file ~/.vault_pass.py
密码存储一行一个
如果你使用的是脚本而不是普通文件,确保脚本是可执行的,这样密码可以输出至标准设备.如果你的脚本需要提示输入数据,那提示可以被发送到标准错误.
如果你是从持续集成系统(例如Jenkins)中使用 Ansible 的话上面的这种情况你会用的到.
(–vault-password-file 参数可以在 Ansible-Pull(拉取配置而非推送配置) 命令中被使用,尽管这将需要分发keys到对应的节点上,
所以 ,了解这些隐性问题后 – vault 更倾向使用 push 方式)