目录
处理任务失败
忽略任务失败
任务失败后强制执行处理程序
指定任务失败条件
指定报告何时报告"Changed"结果
ansible块和错误处理
练习
总结
在受管节点上创建文件或目录
修改文件并将其复制到主机
常用文件模块
file模块处理文件,如果不存在新建
修改文件属性
永久更改
在受管主机上删除文件
检测受管主机上文件状态
检测文件的MD5校验和
使用jinja2模板部署自定义文件
控制结构
循环
条件语句
变量过滤器
管理大项目
利用主机模式选择主机
管理动态清单
配置并行
管理滚动更新
包含和导入文件
管理大项目综合实验
通常情况下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"
- name: get time
shell: date
changed_when: false
三种关键字:
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语句块执行
文件模块 | 功能 |
blockinfile | 将文本块添加到现有文件 |
copy | 将文件复制到受管主机 |
fetch | 从受管主机拷贝文件到控制节点 |
file | 设置文件属性 |
lineinfile | 确保特定行位于某个文件 |
stat | 检索文件状态信息 |
synchronize | rsync命令的一个打包程序 |
- 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即删除
- name: verify the status
stat:
path: /root/file
checksum_algorithm: md5
register: result
- debug:
msg: "The checksum is {{ result.stat.checksum }}"
构建出模板可以更方便的管理文件
{ % 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 | 把值转换成整型 |
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 和任务定义变量
提高复用性
可以用于导入