【运维知识进阶篇】Ansible流程控制详解

简介: 【运维知识进阶篇】Ansible流程控制详解

大家好,今天给大家讲解Ansible的流程控制,Ansible作为可以批量管理客户机的工具,自然是功能齐全,其条件语句、判断语句类似于shell脚本,所以我们要熟练掌握,在实际运用中灵活使用。

playbook条件语句

例如:我们在使用不同的系统的时候,可以通过判断系统来对软件包进行安装;在nfs和rsync安装过程中,客户端服务器不需要推送配置文件,用条件语句可以减少剧本的编写;在安装源码时,可以判断是否执行成功。执行成功就启动等等。

1、根据不同操作系统安装apache

1. [root@Ansible test]# vim test.yml 
2. - hosts: web01
3.   tasks:
4.  - name: install centos httpd
5.       yum:
6.         name: httpd
7.         state: present
8. when: ansible_facts['os_family'] == "CentOS"    #官方写法
9.       #when: ansible_distribution == "CentOS"    非官方写法
10. 
11.  - name: install ubuntu httpd
12.       yum:
13.         name: apache2
14.         state: present
15. when: ansible_facts['os_family'] == "Ubuntu"
16. 
17. #还可以使用括号对条件进行分组
18. tasks:
19.  - name: "shut down CentOS 6 and Debian 7 systems"
20.     command: /sbin/shutdown -t now
21. when: (ansible_facts['distribution'] == "CentOS" and ansible_facts['distribution_major_version'] == "6") or (ansible_facts['distribution'] == "Debian" and ansible_facts['distribution_major_version'] == "7")    #如果当前管理机为CentOS6或者是Debin7就关机
22. 
23. #也可以以列表形式指定多个条件
24. tasks:
25.  - name: "shut down CentOS 6 systems"
26.     command: /sbin/shutdown -t now
27. when:
28.  - ansible_facts['distribution'] == "CentOS"
29.  - ansible_facts['distribution_major_version'] == "6"
30. 
31. #也可以进行条件运算
32. tasks:
33.  - shell: echo "only on Red Hat 6, derivatives, and later"
34. when: ansible_facts['os_family'] == "RedHat" and ansible_facts['lsb']['major_release']|int >= 6    #当系统为RedHat并且版本大于等于6时进行输出
35. 
36. #过滤匹配返回值包含successful
37. tasks:
38.  - name: Check Nginx Configure
39.     command: /usr/sbin/nginx -t
40.     register: result
41.  - name: Restart web02
42.     command: /usr/sbin/reboot
43. when:  result.stderr_lines is match ".*successful.*"    精准匹配,通常配合正则使用
44.     或者    
45. when:  result.stderr_lines is search "successful"       模糊匹配

2、rsync服务端推送配置文件

1. [root@Ansible test]# cat /ansible/rsyncd/rsyncd.yml
2. - hosts: all
3.   tasks:
4.  - name: Install Rsyncd Server
5.       yum: 
6.         name: rsync
7.         state: present
8.  - name: Create www Group
9. group:
10.         name: www
11.         gid: 666
12.  - name: Create www User
13.       user:
14.         name: www
15.         uid: 666
16. group: www
17.         shell: /sbin/nologin
18.         create_home: false
19.  - name: Scp Rsync Config
20. copy: 
21.         src: /ansible/rsyncd/rsyncd.conf
22.         dest: /etc/rsyncd.conf
23.         owner: root
24. group: root
25. mode: 0644
26. when: ansible_hostname == "Backup"
27.  - name: create passwd file
28. copy:
29. content: 'rsync_backup:123'
30.         dest: /etc/rsync.passwd
31.         owner: root
32. group: root
33. mode: 0600
34. when: ansible_hostname == "Backup"
35.  - name: Create backup Directory
36. file:
37.         path: /backup
38.         state: directory
39. mode: 0755
40.         owner: www
41. group: www
42.         recurse: yes
43. when: ansible_hostname == "Backup"
44.  - name: Start Rsyncd Server
45.       systemd:
46.         name: rsyncd 
47.         state: started
48. when: ansible_hostname == "Backup"

3、rsync客户端推送脚本

1. [root@Ansible rsyncd]# cat rsyncd_kehu.yml
2. - hosts: all
3.   tasks:
4.  - name: SCP Backup Shell
5. copy:
6.         src: backup.sh
7.         dest: /root/backup.sh
8. when: ansible_hostname is match "web*"
9. [root@Ansible rsyncd]# ansible-playbook rsyncd_kehu.yml
10. 
11. PLAY [all] *********************************************************************
12. 
13. TASK [Gathering Facts] *********************************************************
14. ok: [nfs]
15. ok: [mysql]
16. ok: [lb01]
17. ok: [rsync]
18. ok: [lb00]
19. ok: [web02]
20. ok: [web01]
21. ok: [lb02]
22. 
23. TASK [SCP Backup Shell] ********************************************************
24. skipping: [rsync]
25. skipping: [nfs]
26. skipping: [lb01]
27. skipping: [lb02]
28. skipping: [mysql]
29. skipping: [lb00]
30. skipping: [web01]
31. skipping: [web02]
32. 
33. PLAY RECAP *********************************************************************
34. lb00                       : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
35. lb01                       : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
36. lb02                       : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
37. mysql                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
38. nfs                        : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
39. rsync                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
40. web01                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
41. web02                      : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
42. 
43. [root@Ansible rsyncd]#

4、变量注册后进行判断

1. [root@Ansible ~]# vim /ansible/test/test.yml 
2. - hosts: web_group
3.   tasks:
4.  - name: check httpd server
5.       command: systemctl is-active httpd
6.       ignore_errors: yes        #忽视报错继续执行
7.       register: check_httpd
8.     -name: print check_httpd    #调试完后可以取消debug
9.       debug:
10.         msg: "{{ check_httpd }}"
11.  - name: httpd restart
12.       service:
13.         name: httpd
14.         state: restated
15. when: check_httpd.rc == 0
16. 
17. [root@Ansible test]# ansible-playbook test.yml 
18. 
19. PLAY [web_group] ***************************************************************
20. 
21. TASK [Gathering Facts] *********************************************************
22. ok: [web02]
23. ok: [web01]
24. 
25. TASK [check httpd server] ******************************************************
26. fatal: [web01]: FAILED! => {"changed": true, "cmd": ["systemctl", "is-active", "httpd"], "delta": "0:00:00.072816", "end": "2023-04-19 21:10:07.733494", "msg": "non-zero return code", "rc": 3, "start": "2023-04-19 21:10:07.660678", "stderr": "", "stderr_lines": [], "stdout": "unknown", "stdout_lines": ["unknown"]}
27. ...ignoring
28. fatal: [web02]: FAILED! => {"changed": true, "cmd": ["systemctl", "is-active", "httpd"], "delta": "0:00:00.073889", "end": "2023-04-19 21:10:07.735992", "msg": "non-zero return code", "rc": 3, "start": "2023-04-19 21:10:07.662103", "stderr": "", "stderr_lines": [], "stdout": "unknown", "stdout_lines": ["unknown"]}
29. ...ignoring
30. 
31. TASK [print check_httpd] *******************************************************
32. ok: [web01] => {
33. "msg": {
34. "changed": true, 
35. "cmd": [
36. "systemctl", 
37. "is-active", 
38. "httpd"
39.         ], 
40. "delta": "0:00:00.072816", 
41. "end": "2023-04-19 21:10:07.733494", 
42. "failed": true, 
43. "msg": "non-zero return code", 
44. "rc": 3, 
45. "start": "2023-04-19 21:10:07.660678", 
46. "stderr": "", 
47. "stderr_lines": [], 
48. "stdout": "unknown", 
49. "stdout_lines": [
50. "unknown"
51.         ]
52.     }
53. }
54. ok: [web02] => {
55. "msg": {
56. "changed": true, 
57. "cmd": [
58. "systemctl", 
59. "is-active", 
60. "httpd"
61.         ], 
62. "delta": "0:00:00.073889", 
63. "end": "2023-04-19 21:10:07.735992", 
64. "failed": true, 
65. "msg": "non-zero return code", 
66. "rc": 3, 
67. "start": "2023-04-19 21:10:07.662103", 
68. "stderr": "", 
69. "stderr_lines": [], 
70. "stdout": "unknown", 
71. "stdout_lines": [
72. "unknown"
73.         ]
74.     }
75. }
76. 
77. TASK [httpd restart] ***********************************************************
78. skipping: [web01]
79. skipping: [web02]
80. 
81. PLAY RECAP *********************************************************************
82. web01                      : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=1
83. web02                      : ok=3    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=1

playbook循环语句

写循环语句可以减少剧本的编写,提高工作效率

1、启动多个服务

1. [root@Ansible test]# cat test.yml
2. - hosts: web_group
3.   tasks:
4.  - name: start service
5.       systemd:
6.         name: "{{ item }}"
7.         state: started
8. with_items:                    #或者是用loop
9.  - httpd
10.  - php-fpm
11.  - mariadb

2、循环定义变量(以列表形式)

1. [root@Ansible test]# cat test.yml
2. - hosts: web_group
3.   tasks:
4.  - name: ensure a list of packages instaled
5.       yum: 
6.         name: "{{ packages }}"
7.       vars:
8.         packages:
9.  - httpd
10.  - httpd-tools
11. 
12. [root@Ansible test]# cat test.yml
13. - hosts: web_group
14.   tasks:
15.  - name: ensure a list of packages instaled
16.       yum: name = "{{ item }}" state=present
17. with_items:
18.  - httpd
19.  - httpd-tools

3、字典循环

1. #创建用户
2. [root@Ansible test]# cat test.yml 
3. - hosts: web_group
4.   tasks:
5.  - name: Add Users    #记得提前创建组
6.       user:
7.         name: "{{ item.name }}"
8.         groups: "{{ item.groups }}"
9.         state: present
10. with_items:
11.  - { name: 'www',groups: 'www'}
12.  - { name: 'koten',groups: 'koten'}
13. 
14. #拷贝文件
15. [root@Ansible test]# cat test.yml 
16. - hosts: web_group
17.   tasks:
18.  - name: copy conf and code
19. copy:
20.         src: "{{ item.src }}"
21.         dest: "{{ item.dest }}"
22. mode: "{{ item.mode }}"
23. with_items:
24.  - { src: "./httpd.conf", dest: "/etc/httpd/conf/", mode: "0644" }
25.  - { src: "./upload_file.php", dest: "/var/www/html/", mode: "0600" }

playbookhandlers

handler是用来执行某些条件下的任务,比如配置文件发生变化时,通过notify触发handler去重启服务。(在saltstack中也有类似的触发器,写法相对Ansible简单,只需要watch,配置文件即可)

handlers案例

1. [root@Ansible test]# cat test.yml
2. - hosts: web_group
3.   vars:
4.  - http_port: 8080                #定义http端口变量
5.   tasks:    
6.  - name: Install Http Server      #安装http服务
7.       yum:
8.         name: httpd
9.         state: present
10. 
11.  - name: config httpd server      #配置http服务
12.       template:                      #将管理机变量内容导入至客户机的这个文件
13.         src: ./httpd.conf
14.         dest: /etc/httpd/conf
15.       notify:                        #检测到配置文件发生变化后,执行handler中的变量
16.  - Restart Httpd Server       #名字要与handlers中-name保持一致
17.  - Restart PHP Server
18. 
19.  - name: start httpd server       
20.       service:
21.         name: httpd
22.         state: started    
23.         enabled: yes
24. 
25.   handlers:                          #handler中内置的变量
26.  - name: Restart Httpd Server
27.       systemd:
28.         name: httpd
29.         state: restarted 
30. 
31.  - name: Restart PHP Server
32.       systemd:
33.         name: php-fpm
34.         state: restarted

注意:

1、无论多少个task通知了相同的handlers,handlers仅会在所有tasks结束后运行一次。

2、Handlers只有在其所在的任务被执行时,才会被运行;如果一个任务中定义了notify调用Handlers,但是由于条件判断等原因,该任务未被执行,那么Handlers同样不会被执行。

3、Handlers只会在每一个play的末尾运行一次;如果想在一个playbook中间运行Handlers,则需要使用meta模块来实现。例如: -meta: flush_handlers。

4、如果一个play在运行到调用Handlers的语句之前失败了,那么这个Handlers将不会被执行。我们可以使用meta模块的–force-handlers选项来强制执行Handlers,即使Handlers所在的play中途运行失败也能执行。

5、不能使用handlers替代tasks

 

playbook任务标签

默认情况下,Ansible在执行一个剧本时,会执行剧本里的所有任务,Ansible的tag功能,可以实现给剧本中的一个或多个任务(整个剧本也可以)打上标签,利用标签来指定这些要运行剧本中的个别任务,或不执行个别任务。

1、打标签方式

对一个task打一个标签;对一个task打多个标签;对多个task打一个标签

2、标签的使用

-t                      执行指定搞定tag标签任务

-skip-tags        执行-skip-tags之外的标签任务

1. [root@Ansible test]# cat test.yml 
2. - hosts: web_group
3.   vars:
4.  - http_port: 8080
5.   tasks:
6.  - name: Install Http Server
7.       yum:
8.         name: httpd
9.         state: present
10.       tags: 
11.  - install_httpd
12.  - httpd_server
13. 
14.  - name: configure httpd server
15.       template:
16.         src: ./httpd.conf
17.         dest: /etc/httpd/conf/httpd.conf
18.       notify: Restart Httpd Server
19.       tags: 
20.  - config_httpd
21.  - httpd_server
22. 
23.  - name: start httpd server
24.       service:
25.         name: httpd
26.         state: started
27.         enabled: yes
28.       tags: service_httpd
29. 
30.   handlers:
31.  - name: Restart Httpd Server
32.       systemd:
33.         name: httpd
34.         state: restarted 
35. 
36. [root@Ansible test]# ansible-playbook test.yml --list-tags    #显示当前剧本的所有标签
37. 
38. playbook: test.yml
39. 
40.   play #1 (web_group): web_group  TAGS: []
41.       TASK TAGS: [config_httpd, httpd_server, install_httpd, service_httpd]
42. 
43. [root@Ansible test]# ansible-playbook test.yml -t httpd_server    #执行httpd_server标签的命令
44. [root@Ansible test]# ansible-playbook test.yml -t install_httpd,confiure_httpd    #执行install_httpd,confiure_httpd的命令
45. [root@Ansible test]# ansible-playbook test.yml --skip-tags httpd_server    #执行除了带httpd_server的命令

playbook文件复用

先前我们写的剧本都是一个一个去执行,我们能否通过写剧本的方法让剧本一键执行,ansible中准备了include的命令,用来动态调用task任务列表

1、只调用task:include_tasks,小剧本中只留tasks,变量需要写在单独的剧本中

1. [root@Ansible test]# cat task.yml
2. - hosts: web_group
3. vars:
4. - http_port: 8080
5. 
6. tasks:
7. - include_tasks: task_install.yml            #下面可以加when判断
8.     - include_tasks: task_configure.yml
9.     - include_tasks: task_start.yml
10. 
11. handlers:
12.     - name: Restart Httpd Server
13. systemd:
14. name: httpd
15. state: restarted
16. 
17. [root@Ansible test]# cat task_install.yml 
18. - name: Install Http Server
19. yum:
20. name: httpd
21. state: present
22. 
23. [root@Ansible test]# cat task_configure.yml 
24. - name: configure httpd server
25. template:
26. src: ./httpd.conf
27. dest: /etc/httpd/conf/httpd.conf
28. notify: Restart Httpd Server
29. 
30. [root@Ansible test]# cat task_start.yml 
31. - name: start httpd server
32. service:
33. name: httpd
34. state: started
35. enabled: yes

2、调用整个task文件:include(新版本:import_playbook)

1. - include: httpd.yml
2. - include: nfs.yml
3. - include: rsync.yml
4. 
5. - import_playbook: httpd.yml
6. - import_playbook: nfs.yml
7. - import_playbook: rsync.yml

3、在saltstack中,叫做top file入口文件

 

playbook忽略错误

剧本在执行中会检测任务执行的返回状态,遇到错误就会终止剧本,但是有些时候,即使执行错误,我们也需要它继续执行。

需要加入参数:ignore_errors: yes 忽略错误

1. [root@Ansible test]# 
2. - hosts: web_group
3.   tasks:
4.  - name: Ignore False
5.       command: /bin/false
6.       ignore_errors: yes
7. 
8.  - name: touch new file
9. file:
10.         path: /tmp/oldboy.txt
11.         state: touch

playbook错误处理

当剧本执行失败时,如果在task中设置了handler也不会被执行。但是我们可以通过参数强制调用handler

1、强制调用handler

1. [root@Ansible test]# cat test.yml
2. - hosts: web_group
3.   vars:
4.  - http_port: 8080
5.   force_handlers: yes                    #错误后强制也会调用handler
6.   tasks:
7.  - name: Install Http Server
8.       yum:
9.         name: htttpd
10.         state: present
11. 
12.  - name: config httpd server
13.       template:
14.         src: ./httpd.conf
15.         dest: /etc/httpd/conf
16.       notify:                            #检测当配置文件变化时,执行变量里的内容
17.  - Restart Httpd Server
18.  - Restart PHP Server
19. 
20.  - name: start httpd server
21.       service:
22.         name: httpd
23.         state: started
24.         enabled: yes
25. 
26.   handlers:
27.  - name: Restart Httpd Server
28.       systemd:
29.         name: httpd
30.         state: restarted 
31. 
32.  - name: Restart PHP Server
33.       systemd:
34.         name: php-fpm
35.         state: restarted

2、抑制changed

被管理主机没有发生变化,可以使用参数将change状态改为ok

1. [root@Ansible test]# cat handler.yml
2. - hosts: web_group
3.   vars:
4.  - http_port: 8080
5.   force_handlers: yes
6.   tasks:
7.  - name: shell
8.       shell: netstat -lntup|grep httpd
9.       register: check_httpd
10.       changed_when: false                        #将客户机状态设置为false,这样当管理机执行剧本时候,就不会因为这条命令执行handler中的内容,不必再去重启服务
11. 
12.  - name: debug
13.       debug: msg={{ check_httpd.stdout.lines }}
14. 
15. [root@Ansible test]# cat test.yml
16. - hosts: webservers
17.   vars:
18.  - http_port: 8080
19.   tasks:
20.  - name: configure httpd server
21.       template:
22.         src: ./httpd.conf
23.         dest: /etc/httpd/conf/httpd.conf
24.       notify: Restart Httpd Server    
25. 
26.  - name: Check HTTPD
27.       shell: /usr/sbin/httpd -t
28.       register: httpd_check
29.       changed_when: 
30.  - httpd_check.stdout.find('OK')
31.  - false
32. 
33.  - name: start httpd server
34.       service:
35.         name: httpd
36.         state: started
37.         enabled: yes
38. 
39.   handlers:
40.  - name: Restart Httpd Server
41.       systemd:
42.         name: httpd
43.         state: restarted

我是koten,10年运维经验,持续分享运维干货,感谢大家的阅读和关注!

目录
相关文章
|
1月前
|
存储 运维 安全
构建高效自动化运维体系:Ansible与Docker的完美结合
【2月更文挑战第31天】 随着云计算和微服务架构的兴起,自动化运维成为保障系统稳定性和提升部署效率的关键手段。本文将详细探讨如何通过Ansible和Docker的结合来构建一个高效、可靠且易于管理的自动化运维体系。首先,介绍自动化运维的必要性及其在现代IT基础设施中的作用;然后,分别阐述Ansible和Docker的技术特点及优势;最后,提供一个基于Ansible和Docker结合使用的实践案例,以及实施过程中遇到的挑战和解决方案。
|
1月前
|
运维 安全 网络安全
构建高效自动化运维体系:Ansible与Docker的完美融合
【2月更文挑战第30天】在当今快速迭代和持续部署的软件发展环境中,自动化运维成为确保效率和稳定性的关键。本文将探讨如何通过结合Ansible和Docker技术,构建一个高效的自动化运维体系。我们将分析Ansible的配置管理功能和Docker容器化的优势,并展示它们如何协同工作以简化部署流程,增强应用的可移植性,并提供一致性的系统环境。此外,文章还将介绍一些最佳实践,帮助读者在真实环境中实现这一整合方案。
|
6月前
|
运维 Shell Linux
Ansible自动化运维工具之常用模块使用实战(5)
Ansible自动化运维工具之常用模块使用实战(5)
|
6月前
|
运维 Kubernetes 网络安全
Ansible自动化运维工具之主机管理与自定义配置文件(2)
Ansible自动化运维工具之主机管理与自定义配置文件(2)
|
6月前
|
存储 运维 Linux
Ansible自动化运维工具安装入门,看这一篇就够了(1)
Ansible自动化运维工具安装入门,看这一篇就够了(1)
|
6月前
|
运维 Cloud Native Go
Ansible自动化:简化你的运维任务
Ansible自动化:简化你的运维任务
61 0
|
7月前
|
运维 大数据 Shell
自动化运维工具—Ansible-1
自动化运维工具—Ansible
106 0
|
6月前
|
运维 应用服务中间件 网络安全
Ansible自动化运维工具之解决SSH连接使用明文密码问题(4)
Ansible自动化运维工具之解决SSH连接使用明文密码问题(4)
|
2天前
|
存储 运维 Kubernetes
构建高效自动化运维体系:Ansible与Kubernetes的协同策略
【4月更文挑战第25天】 在当今快速迭代的软件开发过程中,自动化运维已成为提升效率、保证一致性和降低人为错误的关键。本文将探讨如何利用Ansible作为配置管理工具,以及Kubernetes作为容器编排系统,共同构建一个高效、可靠的自动化运维体系。文章首先概述了自动化运维的基本概念及其重要性,随后详细分析了Ansible与Kubernetes在自动化流程中的作用与优势,并通过一系列实践案例,展示了两者如何协同工作以优化部署、扩缩容和灾难恢复等关键运维任务。最后,文中还讨论了在实际应用中可能遇到的挑战及相应的解决策略,为读者提供了一套完整的自动化运维解决方案参考。
|
3天前
|
存储 运维 Shell
Ansible自动化运维工具安装和基本使用
Ansible 是一款无代理的IT自动化工具,通过SSH连接目标主机执行配置管理、应用部署和云端管理任务。它使用YAML编写的Playbook定义任务,核心组件包括Playbook、模块、主机清单、变量等。Ansible的优势在于易用、功能强大、无须在目标主机安装额外软件,并且开源。安装过程涉及配置网络源、yum安装和SSH密钥设置。通过定义主机清单和使用模块进行通信测试,确保连接成功。
Ansible自动化运维工具安装和基本使用