欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 会展 > Ansible-Playbook详解

Ansible-Playbook详解

2025/4/19 15:53:12 来源:https://blog.csdn.net/m0_75233142/article/details/147097029  浏览:    关键词:Ansible-Playbook详解

Ansible-Playbook详解

  • 1 Playbook介绍
    • 1.1 Playbook概念
    • 1.2 Playbook组成
  • 2 Playbook组件
    • 2.1 hosts组件
    • 2.2 tasks列表和task组件
    • 2.3 remote_user组件
    • 2.4 ignore_errors组件
    • 2.5 handlers和notify组件
    • 2.6 tags组件
  • 3 Variables变量
    • 3.1 使用 setup 模块中变量
    • 3.2 register注册变量
    • 3.3 在playbook命令行中定义变量
    • 3.4 在playbook文件中定义变量
    • 3.5 playbook公共的变量文件
    • 3.6 在主机清单中定义主机和主机组的变量
    • 3.7 针对当前项目的主机和主机组的变量
  • 4 Templates模板
  • 5 流程控制
    • 5.1 循环迭代 loop
    • 5.2 条件判断 when
    • 5.3 分组 block
    • 5.4 changed_when
    • 5.5 滚动执行
    • 5.6 委派至其它主机执行
    • 5.7 只执行一次 run_once
    • 5.8 yaml文件的相互调用
  • 6 Roles角色

1 Playbook介绍

1.1 Playbook概念

在 ansible 中,较简单的任务,我们可以直接调用单个模块来完成,但是,如果遇到复杂的需求,需要调用大量模块才能完成一个需求,或多个任务间有依赖的时候,使用单条命令就特别不方便,这种情况下,我们就可以使用 playbook 来实现这种需求

在 ansible 中,我们写好 playbook,服务器作演员,由服务器根据我们编排的剧本,完成环境安装,服务部署,系统搭建,状态检测等各种各样的功能。

playbook 文件规范

  • 扩展名为 yaml 或 yml
  • 第一行用 “---” (英文输入法下的中划线) 表示 yaml 的开始,一般不写,如果有多个 yaml 文件合并,则可用此标识每个 yaml 文件内容,使用 # 作为注释
  • 大小写敏感
  • 缩进符要统一,用空格键缩进,不要用 tab
  • 缩进空格的数量不重要,但是,相同层级的左边缩进,要保持一致,要对齐,就是说,同样的缩进,代表同样的级别
  • 使用 “-”(英文输入法下的中划线)+一个空格 来表示单个列表项
  • 使用 ”:”(冒号)+空格 来表示一个键值对
  • 使用 “{}”(花括号) 来表示一个键值表
  • 一个 name 只能有一个 task

1.2 Playbook组成

  • 一个 playbook(剧本)文件是一个YAML语言编写的文本文件
  • 通常一个playbook只包括一个play,但可以包括多个Play
  • 一个play的主要包括两部分: 主机和tasks. 即实现在指定一组主机上执行一个tasks定义好的任务列表。
  • 一个tasks中可以有一个或多个task任务
  • 每一个Task本质上就是调用ansible的一个module
  • 在复杂场景中,一个playbook中也可以包括多个play,实现对多组不同的主机执行不同的任务

2 Playbook组件

playbook 是由一个或多个 “play” 组成的列表。playbook 的主要功能在于,将多个 play 组织在一个playbook 文件中,让多台预定义的主机按照 playbook 中编排的内容来完成一系列复杂的功能。一个 playbook 至少要包含 name 和 tasks 两部份。

2.1 hosts组件

Hosts:playbook中的每一个play的目的都是为了让特定主机以某个指定的用户身份执行任务。hosts用于指定要执行指定任务的主机列表,须事先定义在主机清单中,其值可以是通配符,主机或组,可以用 -i 选项指定自定义的主机清单文件

- hosts: 10.0.0.206 			#IP写法
- hosts: 192.168.1.*			#通配符
- hosts: node.linux-magedu.com 	#主机名写法
- hosts: group1 				#分组写法
- hosts: group1:group2 			#分组写法,或者关系,两个分组并集
- hosts: group1:&group2 		#分组写法,与关系,两个分组交集
- hosts: group1:!group2 		#分组写法,非关系,两个分组差集

2.2 tasks列表和task组件

tasks:定义要在远程主机上执行的任务列表,play的主体部分,各任务按顺序在 hosts 中指定的主机上执行,即所有主机做完当前任务,才会开始下一个任务

task:执行指定模块,后面跟上预定的参数,参数中可以使用变量。每个task是一个字典,一个完整的代码块功能需最少元素需包括 name 和 task,一个name只能包括一个task

  • 模块的执行是幂等的,这意味着多次执行是安全的,因为其结果均一致,如果在执行过程中发生错误,则会全部回滚(包括前面己执行成功的)
  • 每个 task 都应该定义name,用于playbook的执行结果输出,建议其内容能清晰地描述任务执行步骤
  • 如果没有指定 name ,则 action 的结果将用于输出
- hosts: grouptasks:- name: testcommand: id

2.3 remote_user组件

remote_user:指定任务在远程主机上执行时所使用的用户,可以是任意用户,前提是用户是存在的,默认 root

  • 可用于 Host 和 task 中。也可以通过指定其通过sudo的方式在远程主机上执行任务,其可用于play全局或某任务;此外,甚至可以在sudo时使用 sudo_user 指定sudo时切换的用户
  • 可以全局指定,也可以在特定 task 中指定,切换用户执行需要先完成登录校验或者用 -k 选项手动输入ssh 密码
- hosts: group1 			#指定主机分组gather_facts: no 			#不收集主机信息remote_user: tom 			#全局设置远程执行用户tasks: 					#task列表- name: task1 			#task名称,此task以tom身份认行shell: id 			#具体执行的模块和参数- name: task2 			#task名称,此task以jerry身份连接主机执行shell: id 			#具体执行的模块和参数  remote_user: jerry- name: task3 			#task名称,此task以jerry身份运行sudo到root执行shell: id 			#具体执行的模块和参数  remote_user: jerrysudo: yes				#默认sudo为root- name: task4 			#task名称,此task以jerry身份运行sudo到tom执行shell: id 			#具体执行的模块和参数  remote_user: jerrysudo: yes 			#默认sudo为rootsudo_user: tom		#sudo为tom

2.4 ignore_errors组件

在同一个 playbook中,如果一个task出错,默认将不会继续执行后续的其它 task

利用 ignore_errors: yes 可以忽略此task的错误,继续向下执行playbook其它 task,此项也可以配置为全局选项

- hosts: groupignore_errors: yes  # 全局配置tasks:- name: task-1command: id1ignore_errors: yes  # 忽略此task的错误

2.5 handlers和notify组件

notify 和 handlers:配合使用,某任务的状态在运行后为changed时,可通过"notify"通知给相应的 handlers 任务,可以达到一种触发调用的效果,(类似于函数调用或触发器),由特定条件触发的操作,满足条件方才执行,否则不执行

  • handlers本质上也是 tasks,其中的 task 与前述的 task 并没有本质上的不同,只不过 handlers 中定义的 task,不会主动执行,只有notify关注的资源(task)发生变化时, notify去通知相应的handelrs,才会调用handler中定义的 task,没有改变则不会触发handlers
  • handers中的 task,是在playbook的 tasks 中所有的 task 都执行完成之后才调用,就算多个task触发了相同的handlers, 此handlers也仅会在所有task结束后运行一次,这样是为了避免多次触发同一个hander
  • handlers是在所有前面的 tasks 都成功执行才会执行,如果前面任何一个task失败,会导致handler跳过执行

范例:当文件发生变化时,重启服务

- hosts: rockytasks:- name: config filecopy: src=/root/nginx_v2/linux.magedu.com.conf dest=/etc/nginx/conf.d/notify: restart service 	#当配置文件发生了变化时,通知重启服务,与handlers的name相匹配handlers: - name: restart serviceservice: name=nginx state=restarted

在 task 中使用 notify 来调用 handlers 中的任务,如果该 task 执行成功,但在该 task 之后的其它 task 执行失败,则会导致 notify 通知的 handlers 中的任务不会被调用,如果不论后面的task成功与否,都希望handlers能执行, 可以使用 force_handlers: yes 强制执行handler

force_handlers 是以整个 playbook 的角度来理解的,在 playbook 中,如果有 task 执行失败,那整个 playbook 也执行失败,就算后面有task,也不会继续执行,那么对应的handler也就不会执行了,所以force_handlers保证的是己成功执行的 task 对应的 handlers 一定会被执行。

- hosts: localhostforce_handlers: yes  #force_handlers 可以保证handlers-1被执行,因为task-1任务执行成功tasks:- name: task-1shell: echo "task-1"notify: handlers-1- name: task-2shell: echoooooo "task-2"notify: handlers-2  #task-2执行失败,handlers-2不会执行- name: task-3shell: echo "task-3"notify: handlers-3  #因为task-2执行失败,playbook不会继续执行task-3,所以不论成功与否,handers-3都不会执行handlers:- name: handlers-1debug: msg="handlers-1"- name: handlers-2debug: msg="handlers-2"- name: handlers-3debug: msg="handlers-3"

2.6 tags组件

tags:还可以通过"tags"给 task 打标签,可在ansible-playbook命令上使用 -t 指定进行调用,定义哪些代码内容可以被忽略。ansible虽然具有幂等性,会自动跳过没有变化的部分,即便如此,有些代码为测试其确实没有发生变化的时间依然会非常地长。此时,如果确信其没有变化,就可以通过tags执行特定的 task

  • 可以一个task对应多个tag,也可以多个task对应同一个tag
  • 还有另外3个特殊关键字用于标签,tagged,untagged 和 all,tagged 表示所有被 tag 标记的任务,untagged 表示所有没有被标记的任务,all 表示所有任务。
- hosts: alltasks:- name: configure filecopy:src: files/httpd.confdest: /etc/httpd/conf/tags:- conf

3 Variables变量

Playbook中同样也支持变量,通过 variables 定义 playbook 运行时需要的使用的变量,有多种定义方式,内置变量或自定义变量

  • 变量名:仅能由字母、数字和下划线组成,区分大小写,且只能以字母开头
  • 变量定义:variable=valuevariable: value
  • 变量调用方式:通过 {{ variable_name }} 调用变量,且变量名前后建议加空格,有时用 "{{ variable_name }}" 才生效

变量优先级(从高到低)):-e 选项定义变量 --> playbook中vars_files --> playbook中vars变量定义 --> host_vars/主机名文件 --> 主机清单中主机变量--> group_vars/主机组名文件 --> group_vars/all文件 --> 主机清单组变量

3.1 使用 setup 模块中变量

setup:默认会自动调用的模块,获取远程主机的一些信息都是放在 facts 变量中的,在playbook中,可以直接使用 gather_facts 选项来获得目标主机的信息,默认是yes

facts中所有可用变量请参考官方文档:ansible_facts

- hosts: rockygather_facts: yestasks:- name: show-factsdebug: msg={{ ansible_facts }}- name: show-facts-hostnamedebug: msg={{ ansible_hostname }}- name: show-facts-ipv4-Adebug: msg={{ ansible_facts["eth0"]["ipv4"]["address"] }}--{{ ansible_facts.eth0.ipv4.address }}- name: show-facts-ipv4-Bdebug: msg={{ ansible_eth0["ipv4"]["address"] }}--{{ ansible_eth0.ipv4.address }}- name: show-facts-ipv4-Cdebug: msg={{ ansible_default_ipv4["address"] }}--{{ ansible_default_ipv4.address }}

每次执行playbook,默认会收集每个主机的所有facts变量,每次执行都需要消耗一定的资源和时间,在不需要facts变量时可以禁用该项 gather_facts: no 来加快 playbook 的执行效率。

如果又需要使用 facts 中的内容,还希望执行的速度快,这时候可以设置 facts 的缓存,可以在 ansible 的配置文件中设置在本地做缓存,也可以将 facts 变量信息存在 redis 服务器中,以便在频繁执行时减少资源消耗

[defaults]
gathering=smart|implicit|explicit 		  #facts策略,默认smart,新版默认implicit
fact_caching_timeout=86400 			      #本地缓存时长,默认86400S
fact_caching=memeory|jsonfile|redis 	  #缓存类型,默认memory
fact_caching_connection=/path|REDIS       #缓存路径或redis信息

gathering 参数说明

  • smart:远程主机信息如果有本地缓存,则使用缓存,如果没有,就去抓取,再存到缓存中,下次就直接使用缓存信息
  • implicit:不使用缓存,每次都抓取新的,可以使用 gather_facts: no 来限制不去抓取新的
  • explicit:不收集主机信息,除非在playbook中用 gather_facts: yes 显式指定

fact_caching 参数说明

  • memeory:只在当前有效,下次还是要重新抓取
  • jsonfile:本地缓存,fact_caching_connection 需要指定本地缓存路径
  • redis:使用 redis 缓存,fact_caching_connection 的格式为 REDIS_IP:REDIS_PORT:REDIS_DB_NUMBER[:REDIS_PASSWORD]

3.2 register注册变量

在playbook中可以使用register将捕获命令的输出保存在临时变量中,方便后续调用此变量,比如可以使用debug模块进行显示输出

- hosts: dbsrvstasks:- name: get variableshell: hostnameregister: name- name: "print variable"debug:msg: "{{ name }}"          		 #输出register注册的name变量的全部信息,注意变量要加" "引起来#msg: "{{ name.cmd }}"       		 #显示命令#msg: "{{ name.rc }}"       		 #显示命令成功与否,相当于$?#msg: "{{ name.stdout }}"     	 #显示命令的输出结果为字符串形式,所有结果都放在一行里显示,适合于结果是单行输出#msg: "{{ name.stdout_lines }}"  	 #显示命令的输出结果为列表形式,逐行标准输出,适用于多行显示#msg: "{{ name['stdout_lines'] }}" #显示命令的执行结果为列表形式,和效果上面相同#msg: "{{ name.stdout_lines[0] }}" #显示命令的输出结果的列表中的第一个元素

范例:修改主机名形式为 web_<随机字符>

- hosts: webserverstasks:- name: generate randomshell: openssl rand -base64 12 | tr -dc '[:alnum:]'register: num- name: show randomdebug:msg: "{{ num }}"- name: change hostnamehostname:name: web-{{ num.stdout }}

3.3 在playbook命令行中定义变量

#直接在命令行中指定  
[root@ubuntu ~]# ansible-playbook -e uname=tom -e age=18 -e gender=M var1.yaml#多个变量一次定义
[root@ubuntu ~]# ansible-playbook -e "uname=tom age=18 gender=M" var1.yaml#从文件中读取
[root@ubuntu ~]# cat var.txt
uname: jerry
age: 20
gender: F#文件前面要加 @
[root@ubuntu ~]# ansible-playbook -e "@/root/var.txt" var1.yaml
[root@ubuntu ~]# ansible-playbook -e "@./var.txt" var1.yaml

3.4 在playbook文件中定义变量

此方式定义的是私有变量,即只能在当前playbook中使用,不能被其它Playbook共用

- hosts: webserversremote_user: rootvars:username: user1groupname: group1tasks:- name: create group {{ groupname }}group: name={{ groupname }} state=present- name: create user {{ username }}user: name={{ username }} group={{ groupname }} state=present

范例:变量的相互调用

- hosts: webserversvars:suffix: "txt"file: "{{ ansible_nodename }}.{{suffix}}"tasks:- name: test varfile: path="/data/{{file}}" state=touch

3.5 playbook公共的变量文件

可以在一个独立的 yaml 文件中定义公共变量,在其它的playbook文件中可以引用变量文件中的变量

此方式比playbook中定义的变量优化级高

[root@ansible ~]#cat vars.yml
var1: httpd
var2: nginx[root@ansible ~]#cat var.yml
- hosts: webvars_files:- vars.yml  # 可以使用相对路径和绝对路径的写法tasks:- name: create httpd logfile: name=/app/{{ var1 }}.log state=touch- name: create nginx logfile: name=/app/{{ var2 }}.log state=touch

3.6 在主机清单中定义主机和主机组的变量

主机变量:在 inventory 主机清单文件中为指定的主机定义变量以便于在playbook中使用

[webservers]
www1.wang.org http_port=80 maxRequestsPerChild=808
www2.wang.org http_port=8080 maxRequestsPerChild=909

主机组变量:在inventory 主机清单文件中赋予给指定组内所有主机上的在playbook中可用的变量,如果和主机变量是同名,优先级低于主机变量

[webservers]
10.0.0.8 
10.0.0.18[webservers:vars]	# webservers组所拥有
ntp_server=ntp.wang.org
nfs_server=nfs.wang.org[all:vars]	# 所有主机所拥有
ntp_server=ntp.wang.org
nfs_server=nfs.wang.org

3.7 针对当前项目的主机和主机组的变量

上面的方式是针对所有项目都有效,而官方更建议的方式是使用ansible特定项目的主机变量和组变量

生产建议在每个项目对应的目录中创建额外的两个变量目录,分别是host_vars和group_vars

  • host_vars下面的文件名和主机清单主机名一致,针对单个主机进行变量定义
    • 格式:host_vars/hostname
  • group_vars下面的文件名和主机清单中组名一致,针对单个组进行变量定义
    • 格式:group_vars/groupname
  • group_vars/all 文件内定义的变量对所有组都有效
[root@ubuntu ~]#cat hostname.yaml
- hosts: alltasks:- name: change hostnamehostname: name=web-{{ id }}.{{ domain }}[root@ubuntu ~]#cat /etc/ansible/hosts
[webserver]
10.0.0.8
10.0.0.18[appserver]
10.0.0.28
10.0.0.38[root@ubuntu ~]#cat host_vars/10.0.0.8
id: 8
[root@ubuntu ~]#cat host_vars/10.0.0.18
id: 18
[root@ubuntu ~]#cat host_vars/10.0.0.28
id: 28
[root@ubuntu ~]#cat host_vars/10.0.0.38
id: 38[root@ubuntu ~]#cat group_vars/webserver
domain: wang.org#不属于webserver组的使用
[root@ubuntu ~]#cat group_vars/all
domain: wu.org[root@ubuntu ~]#ansible-playbook hostname.yaml#最终结果是
[root@10.0.0.8 ~]#hostname
web-8.wang.org
[root@10.0.0.18 ~]#hostname
web-18.wang.org
[root@10.0.0.28 ~]#hostname
web-28.wu.org
[root@10.0.0.38 ~]#hostname
web-38.wu.org

4 Templates模板

templates:模板模块,配合变量使用的模板文件,可以实现批量执行时,在不同主机上用同一个模板生成不同配置文件的功能,可替换模板文件中的变量并实现一些简单逻辑的文件,用于根据每个主机的不同环境而为生成不同的文件。模板文件中支持嵌套jinja2语言的指令,来实现变量、条件判断、循环等功能。

template文件建议存放在和 playbook 文件同级目录的 templates 目录下,且以 .j2 结尾,这样在 playbook 中使用模板文件时,就不需要指定模板文件的路径了。

范例:利用template生成不同的nginx配置文件

[root@ansible ~]#mkdir templates
[root@ansible ~]#vim templates/nginx.conf.j2
......
worker_processes {{ ansible_processor_vcpus*2 }};  #根据不同主机的CPU核数生成不同的配置
......[root@ansible ~]#vim temnginx.yml
---
- hosts: webserversremote_user: roottasks:- name: install nginxyum: name=nginx- name: template config to remote hoststemplate: src=nginx.conf.j2 dest=/etc/nginx/nginx.conf	- name: start serviceservice: name=nginx state=started enabled=yes

template中也可以使用流程控制 for 循环和 if 条件判断,实现动态生成文件功能

for 循环格式

{% for i in EXPR %}...
{% endfor %}

if 条件判断格式

#单分支
{% if EXPR %}
...
{% endif %}#双分支
{% if EXPR %}
...
{% else %}
...
{% endif %}#多分支
{% if EXPR %}
...
{% elif EXPR %}
...
{% else %}
...
{% endif %}

playbook 文件 templnginx5.yml

- hosts: webserversremote_user: rootvars:nginx_vhosts:- listen: 8080root: "/var/www/nginx/web1/"- listen: 8080server_name: "web2.wang.org"root: "/var/www/nginx/web2/"- listen: 8080server_name: "web3.wang.org"root: "/var/www/nginx/web3/"tasks:- name: template configtemplate:src: nginx.conf5.j2dest: /data/nginx5.conf

模版文件 templates/nginx.conf5.j2

{% for vhost in nginx_vhosts %}
server {listen {{ vhost.listen }};{% if vhost.server_name is defined %}
server_name {{ vhost.server_name }};{% endif %}
root {{ vhost.root }};
}
{% endfor %}

生成结果

server {listen 8080;root /var/www/nginx/web1/;
}
server {listen 8080;server_name web2.wang.org;root /var/www/nginx/web2/;
}
server {listen 8080;server_name web3.wang.org;root /var/www/nginx/web3/;
}

5 流程控制

5.1 循环迭代 loop

ansible 的 task 中,如果要重复执行相同的模块,则可以使用循环的方式来实现

对于迭代项的引用,要使用固定内置变量 item 来引用,这是固定写法。

范例:安装多个安装包

- hosts: webserverstasks:- name: Install Httpd and Php-fpm Packageyum:name: "{{ item }}"state: latestloop:- httpd- php-fpm

在迭代中,还可以嵌套子变量,关联多个变量在一起使用

范例:批量修改用户密码

- hosts: ssh-hosttasks:- name: change user passwduser:name: "{{ item.name }}"password: "{{ item.chpass | password_hash('sha512') }}"update_password: alwaysloop:- { name: 'root', chpass: '123456' }- { name: 'app', chpass: '654321' }

5.2 条件判断 when

可以实现条件测试。例如可以根据变量、facts或此前任务的执行结果来做为某task执行与否的前提,通过在task后添加when子句即可使用 jinja2 的语法格式条件测试

范例: 判断服务状态决定是否重新启动

- hosts: webserverstasks:- name: Check nginx Servicecommand: systemctl is-active nginxignore_errors: yesregister: check_nginx- name: debug vardebug:var: check_nginx- name: Httpd Restartservice:name: nginxstate: restartedwhen: check_nginx.rc == 0  #如果nginx服务没启动,就重新启动#failed_when: check_nginx.rc != 0 	#条件不成立才执行,和when相反

范例: 多条件判断写法

- hosts: alltasks:- name: "shut down CentOS 6 and Debian 7 systems"shell:cmd: /sbin/shutdown -h nowwhen: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")- name: "shut down CentOS 7 systems"shell: /sbin/shutdown -h nowwhen:  # when的列表形式表示 and 关系- ansible_facts['distribution'] == "CentOS"- ansible_facts['distribution_major_version'] == "7"

其他判断条件

  • 操作系统版本判断的第二种写法:ansible_distribution_file_variety == "Debian"
  • 操作系统主版本号判断的第二种写法:ansible_distribution_major_version == "7"
  • 判断变量是否被定义:name is undefined,name指定要判断的变量名
  • 对主机名进行条件判断:ansible_fqdn is match ("web*")

5.3 分组 block

当想在满足同样条件下,执行多个任务时,就需要分组。而不再针对每个任务都用相同的when来做条件判断

使用 block 可以对 task 任务进行分组,将多个 task 任务放到一个 block 下,可以在写一个 when 判断的情况下调用多个 task 任务

- hosts: localhosttasks:- block:- debug: msg="first"- debug: msg="second"when:- ansible_facts['distribution'] == "CentOS"- ansible_facts['distribution_major_version'] == "8"#相当于下面写法
- hosts: localhosttasks:- debug: msg="first"when:- ansible_facts['distribution'] == "CentOS"- ansible_facts['distribution_major_version'] == "8"- debug: msg="second"when:- ansible_facts['distribution'] == "CentOS"- ansible_facts['distribution_major_version'] == "8"

5.4 changed_when

第一个作用:关闭 changed 状态

只有在 task 的执行结果返回状态为 changed 的时候,我们才认为该 task 是真实执行了,在远程主机上产生了数据变化,但是在 ansible 中,不是所有模块都具有幂等性,对于某些不会产生数据变化的 task,ansible 也会给出 changed 输出。所以当确定某个task不会对被控制端产生数据变化时,而不想显示的是黄色的changed状态,可以通过 changed_when: false 来避免这一情况

- hosts: localhosttasks:- name: task-1shell: idchanged_when: false

第二个作用:自定义条件判断

Ansible 在执行任务之后,会依据任务的执行状况判断该任务是否使系统状态发生了改变,并且在输出结果里标记为 changed 或者 ok。不过,有时候 Ansible 默认的判断规则不符合我们的需求,这时就可以使用 changed_when 来自定义判断逻辑。

- hosts: webserverstasks:- name: check configshell: /usr/sbin/nginx -tregister: check_nginx_configchanged_when: "'successful' in check_nginx_config.stdout"  #自定义条件判断任务是否发生了变更

5.5 滚动执行

默认情况下,Ansible将尝试并行管理playbook中所有的机器,如果一个 playbook 中有多个 task,在有多台远程主机的情况下,需要在所有远程主机上执行完当前的 task 之后才执行下一个 task,如果主机过多,或者需要执行的task 比较消耗时间,则会导致所有主机都处于一个执行中状态。如下图,先在 A,B,C 三台主机上执行 Task-1,再在三台主机上执行 Task-2

在这里插入图片描述

这样的话,在有些场景中是不利于的。比如升级场景,我们希望是先A主机执行完所有task,再到B主机依次执行,就不会导致所有主机都处于一个执行中状态,都无法对外提供服务。所以对于滚动更新用例,可以使用 serial 关键字定义Ansible一次应管理多少主机,还可以将 serial 关键字指定为百分比,表示每次并行执行的主机数占总数的比例

- hosts: allserial: 2  #每次只同时处理2个主机#serial: "20%"  #每次只同时处理20%的主机gather_facts: falsetasks:- name: task onecommand: hostname- name: task twocommand: hostname

5.6 委派至其它主机执行

利用委托技术,可以在非当前被控主机的其它主机上执行指定操作,即可以在非指定的主机上执行 task,委派时必须要有key验证

范例:将任务委派给指定的主机执行

#在10.0.0.8上执行hostname -I,而非当前主机localhost
- hosts: localhosttasks:- name: show ip addresscommand: hostname -Idelegate_to: 10.0.0.8  #指定当前任务被委派给的目标主机delegate_facts: true  #收集被委派的目标主机的facts信息

范例: 将任务被委派给控制端ansible主机执行

#在本地执行ifconfig,而非10.0.0.8,下面展示三种实现方式
- hosts: 10.0.0.8tasks:- name: show ip addresslocal_action:  #旧语法,委派给控制端ansible主机执行module: commandargs: ifconfig- name: show hostnameshell: hostnameconnection: local  #委派给控制端ansible主机执行- name: kernel versionshell: uname -rdelegate_to: localhost  #委派给控制端ansible主机执行

5.7 只执行一次 run_once

利用 run_once 指令可以只执行一次,而非在所有被控主机都执行,通常会在第一个匹配的主机上执行该任务

- hosts: webserverstasks:- name: Run hostname command oncecommand: hostnamerun_once: true

5.8 yaml文件的相互调用

利用 include 或 include_tasks 可以在某个 task 中调用其它的只有 task 内容的 yaml 文件,include 在 2.16 版本之后被弃用,建议使用 include_tasks 来实现包含。include_tasks 一次只能引用一个 yaml 文件

注意:一个task只有一个include_tasks生效,也可以配合when和变量一起使用

#a.yml
- hosts: webserverstasks:- name: run a jobcommand: wall run a job- name: excute b.ymlinclude_tasks: b.yml  #调用b.yml执行task#b.yml
- name: run b jobcommand: wall run b job

import_playbook 合并多个 playbook 文件,将多个包含完整内容的 yaml 文件交由一个 yaml 统一调用

[root@ansible ansible]#cat main.yml
- import_playbook: tasks1.yml
- import_playbook: tasks2.yml[root@ansible ansible]#cat tasks1.yml
- hosts: webserverstasks:- name: run task1 jobcommand: wall run task1 job[root@ansible ansible]#cat tasks2.yml
- hosts: dbsrvstasks:- name: run task2 jobcommand: wall run task2 job

6 Roles角色

角色是ansible自1.2版本引入的新特性,用于层次性、结构化地组织playbook。roles能够根据层次型结构自动装载变量文件、tasks以及handlers等。要使用roles只需要在playbook中使用 include 指令即可。简单来讲,roles就是通过分别将变量、文件、任务、模板及处理器放置于单独的目录中,分门别类的管理起来,使其看起来更像一个项目,并可以便捷地 include 它们的一种机制,主要用来解决多文件之间的相互包含,引用,组合等问题

在Playbook中调用角色

一、直接调用

- hosts: webserversremote_user: rootroles:- mysql- memcached- nginx

二、传参

键role用于指定角色名称,后续的k/v用于传递变量给角色

- hosts: allremote_user: rootroles:- role: mysqlusername: mysql

三、结合条件测试调用

- hosts: allremote_user: rootroles:- role: nginxusername: nginxwhen: ansible_distribution_major_version == '7'

四、结合tags调用

- hosts: appsrvsremote_user: roottags: approles:- role: nginxtags:- nginx- web

五、依赖其它角色,在meta目录下编写与该role相关的依赖角色

dependencies:- role: nginx- role: php-fpm- role: mysql

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词