目录
处理任务失败
通常情况下playbook遇到错误会终止执行,但是有特定时候我们需要在它失败后还要继续执行
忽略任务失败
关键字:ignore_errors
ignore_errors: no
ignore_errors: yes
cat test.yml
---
- name: Test
hosts: web
tasks:
- name: Install Package
yum:
name: k8s
state: latest
ignore_errors: yes
...
任务失败后强制执行处理程序
关键字:force_handlers: yes
- ansible playbook中,handler其实也类似于task,不过该task默认不执行,只有在触发的时候才执行
- handler通过notify来监视单个或者多个task,一旦task执行结果发生变化,则触发handler,执行相应操作
- handler会在所有的play都执行完毕之后才会执行,这样可以避免当handler监视的多个task执行结果都发生了变化之后而导致handler的重复执行(handler只需要在最后执行一次即可)
在notify中定义内容一定要和tasks中定义的 - name 内容一样,这样才能达到触发的效果,否则会不生效
默认情况下,在一个play中,只要有task执行失败,则play终止,即使是与handler关联的task在失败的task之前运行成功了,handler也不会被执行。若向handler仍然能执行,需设置force_handlers: yes
cat test01.yml
---
- hosts: web
# force_handlers: yes
tasks:
- name: always notify # 一个成功的任务
command: /bin/true
notify: restart apache
- name: fail task # 一个失败的任务
yum:
name: k8s
state: latest
handlers: # 触发器,处理程序只有在changed的情况下执行
- name: restart apache
service:
name: httpd
state: restarted
...
指定任务失败条件
关键字:failed_when
tasks:
- name: run script
shell: /user/local/bin/user.sh
register: command_result
failed_when: "'failure' in command_result.stdout"
failed模块可以实现此效果
tasks:
- name: run script
shell: /user/local/bin/user.sh
register: command_result
ignore_errors: yes
- name: Report failure
fail:
msg: "Authentication failure" # fail模块可以提供明确消息
when: "'failure' in command_result.stdout"
指定报告何时报告"Changed"结果
- name: get time
shell: date
changed_when: false
ansible块和错误处理
三种关键字:
block:定义要运行的主要任务
rescue:定义在block子句中定义的任务失败时运行的任务
always:定义时中独立运行的任务
练习
故意制造错误
- name: Task Failure
hosts: web
vars:
web_pkg: http
db_pkg: mariadb-server
db_service: mariadb
tasks:
- name: Install {{ web_pkg }} packages
yum:
name: "{{ web_pkg }}"
state: present
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
在这里我们发现,第一个任务失败,第二个任务就不会运行
添加忽略关键字
13 ignore_errors: yes
使用block、rescue、always将任务分开
rescue:定义任务失败的时候的定义,相当于if...else中的else语句
always:定义始终独立运行的任务
- name: Task Failure
hosts: web
vars:
web_pkg: http
db_pkg: mariadb-server
db_service: mariadb
tasks:
- name: set up web
block:
- name: Install {{ web_pkg }} packages
yum:
name: "{{ web_pkg }}"
state: present
rescue:
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
always:
- name: start {{ db_service }} service
service:
name: "{{ db_service }}"
state: started
执行结果有报错,但是mariadb正常启动
再修改,将http的包改为正确
web_pkg: httpd
发现rescue部分被忽略,但是always总会执行
控制'changed'条件
- name: Task Failure
hosts: web
vars:
web_pkg: httpd
db_pkg: mariadb-server
db_service: mariadb
tasks:
- name: check time
command: date
register: command_result
#changed_when: false
- name: print time
debug:
var: command_result.stdout
- name: set up service
block:
- name: Install {{ web_pkg }} packages
yum:
name: "{{ web_pkg }}"
state: present
# failed_when: web_pkg == 'httpd'
rescue:
- name: Install {{ db_pkg }} packages
yum:
name: "{{ db_pkg }}"
state: present
always:
- name: start {{ db_service }} service
service:
name: "{{ db_service }}"
state: started
运行发现check time任务始终是changed
但是因为任务没有更改受管主机,所以不应该每次都是changed
修改文件
12 changed_when: false
再次运行,变为OK
使用failed_when关键字
failed_when: web_pkg == 'httpd'
有报错,但是其实已经安装了httpd包,failed_when关键字只是改变了任务的执行状态,没有改变任务本身。但是失败的状态可以让rescue语句块执行
总结
- 循环迭代的方法
- 条件用于仅在符合特定条件时执行任务或play
- 处理程序用法
- 只有任务报告受管主机做了更改,才会通知处理程序
- 处理任务失败,即使成功的任务也可以标记为失败
- 块用于将任务分组为单元,通过任务是否成功来确定执行其他任务与否
在受管节点上创建文件或目录
修改文件并将其复制到主机
常用文件模块
文件模块 | 功能 |
blockinfile | 将文本块添加到现有文件 |
copy | 将文件复制到受管主机 |
fetch | 从受管主机拷贝文件到控制节点 |
file | 设置文件属性 |
lineinfile | 确保特定行位于某个文件 |
stat | 检索文件状态信息 |
synchronize | rsync命令的一个打包程序 |
file模块处理文件,如果不存在新建
- name: Test
hosts: web
tasks:
- name: Touch a file
file:
path: /root/file
owner: westos
group: westos
mode: 0640
state: touch
修改文件属性
- name: set selinux
file:
path: /root/file
setype: samba_share_t
永久更改
- name: set selinux
sefcontext:
target: /root/file
setype: samba_share_t
state: present
在受管主机上删除文件
- name: delete file
file:
dest: /root/file
state: absent # absent即删除
检测受管主机上文件状态
检测文件的MD5校验和
- name: verify the status
stat:
path: /root/file
checksum_algorithm: md5
register: result
- debug:
msg: "The checksum is {{ result.stat.checksum }}"
使用jinja2模板部署自定义文件
构建出模板可以更方便的管理文件
{ % EXPR % } # 表达式或者逻辑
{{ EXPR }} # 最终向用户输出表达式或结果
{ # COMMENT # } # 注释
构建jinja2模板
jinja2模板由多个元素组成:数据、变量、表达式,模板中使用的变量可以在playbook的vars中指定
模板中所有的值都使用变量方式,将来会被受管主机对应的值替代
Port 22 ==> Port {{ ssh_port }}
PermitRootLogin yes ==> {{ root_allowed }}
部署jinja2模板
tasks:
- name: template
template:
src: /root/j2-template.j2
dest: /root/dest-config-file.txt
控制结构
循环
#1
{ % for user in users %}
{{ user }} # user变量将遍历users
{ % endfor % }
#2
{ % for myhost in groups['myhosts'] %} # 列出myhosts组中所有主机
{{ myhosts }}
{ % endfor % }
条件语句
{ % if finished % } # 只有此条件为真,才会将result变量的值放入文件
{{ result }}
{ % endif % }
注意:jinja2的循环和条件只能在模板中使用,不能在playbook中使用
变量过滤器
{{ output | to_json }} #以 json 格式输出
{{ output | to_yaml }}
{{ output | from_json }} #对 json 格式字符串进行解析
{{ output | from_yaml }}
变量可以通过“过滤器”进行修改,过滤器可以理解为是jinja2里面的内置函数和字符串处理函数
过滤器名称 | 说明 |
safe | 渲染时值不转义 |
capitialize | 把值的首字母转换成大写,其他子母转换为小写 |
lower | 把值转换成小写形式 |
upper | 把值转换成大写形式 |
title | 把值中每个单词的首字母都转换成大写 |
trim | 把值的首尾空格去掉 |
striptags | 渲染之前把值中所有的HTML标签都删掉 |
join | 拼接多个值为字符串 |
replace | 替换字符串的值 |
round | 默认对数字进行四舍五入,也可以用参数进行控制 |
int | 把值转换成整型 |
- file 模块库包含创建、复制、编辑、修改等权限和其他属性
- 使用 jinja2 模板动态构建文件来部署
- jinja2 模板由两个元素构成:变量和表达式,在使用 jinja2 模板时,他们被替换为值
- 通过 jinja2 过滤器,模板表达式可以从一种数据格式转换为另一种
管理大项目
利用主机模式选择主机
1.使用通配符匹配多个主机
-hosts:'*' 匹配所有
-hosts:'*.example.com' 匹配所有已example.com结尾的主机
-hosts:'172.25.254.*' 匹配所有此网段的主机
2.通过列表匹配主机或主机组
-hosts:www1.example.com,www2.example.com,172.25.254.250 匹配此三台主机
-hosts:webservers,westos 匹配此两个主机组
3.将通配符和列表等一起使用
-hosts:webservers,&westos 即属于webserver组也属于westos组
4.匹配westos组中所有主机,但是 servera.lab.example.com除外
-hosts:westos,!servera.lab.example.com
5.匹配所有主机除了servera.lab.example.com
-hosts all,!servera.lab.example.com
管理动态清单
编写动态清单程序,将 INI 格式的清单转换为 JSON 格式
配置并行
使用 forks 在 ansible 中配置并行,ansible 最大同时连接数由 ansible 配置文件中 forks 参数控制
可以在命令行使用 -f 或者 --forks 参数来指定并行数
管理滚动更新
如果更新发生在负载均衡服务器,更新完成会重启,可能导致后端所有 web 服务器停止服务, 可以使用 serial 关键字来分批运行
serial 参数优点:
在更新时如果出现问题,那么在前 2 台发生问题是 playbook 就会 停止运行,后面的服务器不会执行,那么也就保证了服务的高可用
包含和导入文件
大型 playbook 管理起来比较复杂,可以用模块化的方式管理
两种方法:包含、导入
1. 导入 playbook
例 1:
- name: configure webserver
import_playbook: web.yml
例 2:
- name: Play 1
hosts: localhost
tasks:
- debug:
msg: Play1
- name: Import Playbook
import_playbook: play2.yml
2. 导入和包含任务的 playbook
一个只有任务的 playbook
- 导入任务
使用导入时,when 等条件语句应用于导入的每个任务;循环不能作用于导入的任务
- 包含任务
为外部 play 和任务定义变量
提高复用性
可以用于导入
管理大项目综合实验
- 运行
- 测试