一、item---loop
1.给定数据如下:
使用loop来输出 My name is zhangsan/lisi My age is 18/20
users:
- name: zhangsan
age: 18
- name: lisi
age: 20
[root@good ~]# vim playbook2.yml --- - name: hosts: rhce tasks: - name: shell: "{{ item }}" loop: - name: zhangsan age: 18 - name: lisi age: 20 ...
[root@good ~]# ansible-playbook playbook2.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [shell] ******************************************************************* skipping: [rhce] => (item={'name': 'zhangsan', 'age': 18}) skipping: [rhce] => (item={'name': 'lisi', 'age': 20}) PLAY RECAP ********************************************************************* rhce : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
2.给定数据Services,要求使用loop来重启服务:
提示:将services定义为变量
可以使用lookup('dict', services)来进行转换或者使用{{ services | dict2items }}
services:
httpd:
name: httpd
state: restarted
firewalld:
name: firewalld
state: restarted
# 编辑文件 [root@good ~]# vim playbook2.yml --- - name: hosts: rhce tasks: - name: service: name: "{{ item.name }}" state: "{{ item.state }}" loop: - name: httpd state: restarted - name: firewalld state: restarted ... # 执行命令 [root@good ~]# ansible-playbook playbook2.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [service] ***************************************************************** changed: [rhce] => (item={'name': 'httpd', 'state': 'restarted'}) changed: [rhce] => (item={'name': 'firewalld', 'state': 'restarted'}) PLAY RECAP ********************************************************************* rhce : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
二、when条件任务语法
1.使用when,当条件成立时才执行任务:测试给定一个0/1,
#给1 - name: Simple Boolean task Demo hosts: rhce vars: run_my_task: 1 tasks: - name: httpd package is installed yum: name: httpd when: run_my_task #给0 - name: Simple Boolean task Demo hosts: rhce vars: run_my_task: 0 tasks: - name: httpd package is installed yum: name: httpd when: run_my_task
2.给定一个未定义的变量
- name: Simple Boolean task Demo hosts: rhce tasks: - name: httpd package is installed yum: name: httpd when: run_my_task
3.给定一个变量当变量>10时才执行
- name: Simple Boolean task Demo hosts: rhce vars: run_my_task: 11 tasks: - name: httpd package is installed yum: name: httpd when: run_my_task > 10
4.使用and 和 or来连接两个条件: True and False , True or False
# and 运算必须两个都为真 --- - name: hosts: rhce vars: true: 0 false: 1 tasks: - name: yum: name: httpd when: true == 1 and false == 1 ... 不执行 # or 一个为真就可以 --- - name: hosts: rhce vars: true: 0 false: 1 tasks: - name: yum: name: httpd when: true == 1 or false == 1 ... 执行
5.loop和when联合使用 1 中,当name == firewalld时不执行任务
# 编写playbook --- - name: hosts: rhce tasks: - name: service: name: "{{ item.name }}" state: started loop: - name: firewalld - name: httpd when: item.name == "firewalld" ... # 执行playbook [root@good ~]# ansible-playbook playbook4.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [service] ***************************************************************** changed: [rhce] => (item={'name': 'firewalld'}) skipping: [rhce] => (item={'name': 'httpd'}) PLAY RECAP ********************************************************************* rhce : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
三、notify和handler的使用
1.定义一个任务:使用shell模块执行 echo "123", 使用notify通知handler 任务 debug info
# 编写playbook --- - name: hosts: rhce tasks: - name: debug: msg: echo'123' notify: - debug info handlers: - name: debug info shell: echo'123' ... #执行 [root@good ~]# ansible-playbook playbook5.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [debug] ******************************************************************* ok: [rhce] => { "msg": "echo'123'" } PLAY RECAP ********************************************************************* rhce : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
2.定义handler: 包含一个任务:debug info: 执行 输出: I handled the notify
# 编写playbook --- - name: hosts: rhce tasks: - name: debug: msg: I handled the notify notify: - debug info handlers: - name: debug info shell: echo'123' ... #执行 [root@good ~]# ansible-playbook playbook5.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [debug] ******************************************************************* ok: [rhce] => { "msg": "I handled the notify" } PLAY RECAP ********************************************************************* rhce : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.tags使用:定义三个任务:分别打上标签:tag1, tag2, tag2
tags标签: 通过此标签来指定playbook文件执行哪条命令 - hosts: rhce remote_user: root tasks: - name: copy copy: content="apple" dest=/tmp/mama.txt tags: copy1 # 标签名是copy1,在下面执行文件时会用到 - name: copy copy: content="banana" dest=/tmp/mama.txt tags: copy2 # 标签名是copy2,在下面执行文件时会用到 - name: copy copy: content="egg" dest=/tmp/mama.txt tags: copy3 # 标签名是copy3,在下面执行文件时会用到
4.执行playbook, 且指定只执行tag2
#ansible-playbook -t copy2 pbook.yml #执行文件中第二条copy2命令
四、处理任务失败
1.ignore_errors的使用: 定义任务使用command模块执行 test1111
默认情况下任务失败时play会终止。可以通过ingnore乎略失败,其他任务可以继续执行。 --- - name: hosts: rhce tasks: - name: command: ignore_errors: yes - name: service: name: httpd state: started ... #执行跳过失败 [root@good ~]# ansible-playbook playbook6.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [command] ***************************************************************** fatal: [rhce]: FAILED! => {"changed": false, "cmd": null, "delta": null, "end": null, "msg": "no command given", "rc": 256, "start": null, "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []} ...ignoring TASK [service] ***************************************************************** changed: [rhce] PLAY RECAP ********************************************************************* rhce : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
2.再定义一个任务:使用debug模块输出: This is test for ignore errors(确保这个任务可以正常执行)
--- - name: hosts: rhce tasks: - name: debug: msg: This is test for ignore errors ignore_errors: yes - name: service: name: httpd state: started ... # 执行 [root@good ~]# ansible-playbook playbook6.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [debug] ******************************************************************* ok: [rhce] => { "msg": "This is test for ignore errors" } TASK [service] ***************************************************************** changed: [rhce] PLAY RECAP ********************************************************************* rhce : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
3.failed_when: 定义一个任务: 使用shell模块执行echo 123, 将此任务设置为执行失败
vim playbook.yml --- - name: hosts: rhce tasks: - name: shell: echo '123' register: return_value #将echo的标准输出定义到return_value变量中 failed_when: "'123' in return_value.stdout" # 当'123' 在return_value中则执行失败 ... [root@good ~]# ansible-playbook playbook.yml PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [shell] ******************************************************************* fatal: [rhce]: FAILED! => {"changed": true, "cmd": "echo '123'", "delta": "0:00:00.003196", "end": "2022-08-08 22:13:54.989842", "failed_when_result": true, "msg": "", "rc": 0, "start": "2022-08-08 22:13:54.986646", "stderr": "", "stderr_lines": [], "stdout": "123", "stdout_lines": ["123"]} PLAY RECAP ********************************************************************* rhce : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
4.changed_when: 定义一个任务: 使用shell模块执行echo 123 > /root/changed_test, 将此任务的changed状态改为0
--- - name: hosts: rhce tasks: - name: shell: echo '123' > /root/changed_test changed_when: false ... #当设置changed_when 为false,则该任务执行后永远不会返回changed状态,只返回ok或者failed。 [root@good ~]# ansible-playbook playbook6.yml PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [shell] ******************************************************************* ok: [rhce] PLAY RECAP ********************************************************************* rhce : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
5.block, rescue, always: 在block定义两个任务,在rescue中定义两个任务,在always中定义两个任务,让rescue中的任务可以执行
- block: 定义要运行的主要的任务。
- rescue: 定义要在block子句中定义的任务失败时运行的任务。
- always:定义始终都独立运行的任务,不论block和rescue子句中定义的任务是否成功还是失败。
# 编写playbook --- - name: hosts: rhce tasks: - name: block: - name: yum: name: 123 rescue: - name: service: name: httpd state: started always: - name: service: name: firewalld state: started ... # 执行 [root@good ~]# ansible-playbook playbook6.yml -C PLAY [rhce] ******************************************************************** TASK [Gathering Facts] ********************************************************* ok: [rhce] TASK [yum] ********************************************************************* fatal: [rhce]: FAILED! => {"changed": false, "failures": ["123 没有能够与之匹配的软件包: 123"], "msg": "Failed to install some of the specified packages", "rc": 1, "results": []} TASK [service] ***************************************************************** changed: [rhce] TASK [service] ***************************************************************** changed: [rhce] PLAY RECAP ********************************************************************* rhce : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=1 ignored=0
五、使用jinja2模板部署自定义文件
1. 构建一个jinja2模板:
要求:在模板中输出1-10, 打印主机的全限定名称, 输出默认的IP地址
如果权限定名称为node1.example.com 将其输出为: node1
在受控主机中会按照jinja2动态模板文件,生成相对应的主机信息。 [student@workstation ~]$ cat playbook.yml --- - name: 1 hosts: all remote_user: root tasks: - name: deplay /etc/hosts template: src: templates/hosts.j2 dest: /etc/myhosts [student@workstation ~]$ cat templates/hosts.j2 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 {% for host in groups['all'] %} {{ hostvars[host]['ansible_facts']['default_ipv4']['address'] }} {{ hostvars[host]['ansible_facts']['fqdn'] }} {{ hostvars[host]['ansible_facts']['hostname'] }} {% endfor %} {#hostvars[host]不能加引号host是命令Hostvars[cmd]['变量名'] #} [student@workstation ~]$ ssh servera Activate the web console with: systemctl enable --now cockpit.socket Last login: Wed Dec 29 20:07:19 2021 from 172.25.250.9 [student@servera ~]$ cat /etc/myhosts 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 172.25.250.10 servera.lab.example.com servera 172.25.250.11 serverb.lab.example.com serverb 172.25.250.12 serverc.lab.example.com serverc 172.25.250.13 serverd.lab.example.com serverd
六、并行处理forks seria
1.forks和serial的区别
forks(广度优先)
依据 forks 参数,决定一次在多少个服务器上并行执行相应的 task,对于包含多个 task 的场景,这种方式会先将 1 个 task 在指定的所有服务器上都执行完成之后,才会执行后续的 task。所以对于一个包含多个 task 的 playbook 来说,此时所有服务器的状态都是不完整的,都是处于中间状态的。但是当这个包含多个 task 的 playbook 执行完成之后,所有执行成功的服务器的状态都是被更新完成的。这种方式适合对服务器的中间状态不敏感的场景,其优点是可以对指定的所有主机执行同步的配置操作;缺点是更新过程中所有服务器都是未完成配置的中间状态。比如下面的场景,有 4 台服务器需要配置(nodeA, nodeB, nodeC, nodeD),playbook 中定义了 2 个 task,forks 指定的参数是 5,而每个 task 执行的耗时为 5 秒。
serial(深度优先)
而对于深度优先的执行方式,则是在指定数目的服务器上执行完 playbook 的所有 task 之后,才会继续在剩余的其他主机上执行这个 playbook 中定义的 task。这是通过在 playbook 中指定 serial 关键字实现的,所以其是在 forks 参数的基础上,进一步进行约定,从而实现指定数目的服务器执行完成 playbook 之后,才会在其他服务器上执行的操作。这种方式类似于滚动更新。比如,此时仍然为 4 台服务器,forks 仍然设置为 5,然后在 playbook 中增加 serial 关键字,并将其值设置为 2,playbook 中仍然有 2 个 task,且每个 task 执行耗费时间为5秒。
七、playbook的文件导入
1.导入playbook和task
建立一个import_playbook.yaml 然后将其导入另一个playbook: main_playbook.yaml
# main_playbook.yaml --- - name: import_playbook: import_playbook.yml - name: main play hosts: rhce tasks: - name: main task debug: msg: "this is my main playbook" ... # import_playbook.yaml --- - name: hosts: rhce tasks: - name: import play book debug: msg: "this is to import playbook" ...
建立一个import_task.yaml里面只写任务:将其导入main_task_playbook.yaml中
# import_task.yaml --- - name: import_tasks debug: msg: "this is to import tasks" ... # main_task_playbook.yaml --- - name: hosts: rhce tasks: - name: import_tasks: import_tasks.yml - name: debug: msg: "this is main tasks" ...