Ansible 大项目管理实践笔记:并行任务、角色管理与负载均衡架构部署

发布于:2025-08-20 ⋅ 阅读:(13) ⋅ 点赞:(0)

管理大项目

Ansible 在大项目管理中的“并行配置与异步任务管理”方法

配置 async

async 异步任务

  • 测试 async + poll 参数对任务调度的影响

示例1: 任务执行失败,在规定时间内容任务没有执行完成。

async: 5 + poll: 2,任务超时 → 演示 异步任务超时失败的情况

 [yuxb@controller web 09:53:08]$ vim playbook.yml 
 [yuxb@controller web 09:54:09]$ cat playbook.yml 
 ---
 - name: connection
   hosts: node1
   tasks:
     - name: conneciton 
       shell: sleep 10
       async: 5
       poll: 2
 ​
 # 执行
 [yuxb@controller web 09:51:33]$ ansible-playbook playbook.yml 
 ​
 PLAY [connection] ***********************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node1]
 ​
 TASK [conneciton] ***********************************************************************************
 fatal: [node1]: FAILED! => {"changed": false, "msg": "async task did not complete within the requested time - 5s"}
 ​
 PLAY RECAP ******************************************************************************************
 node1                      : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   
 ​

示例2: 放入后台下载,立刻执行下一个任务。

async: 100 + poll: 0,任务后台运行 → 演示 放到后台执行,立即执行下一个任务

 [yuxb@controller web 09:54:12]$ vim playbook.yml 
 [yuxb@controller web 09:55:22]$ cat playbook.yml 
 ---
 - name: connection
   hosts: node1
   tasks:
     - name: download
       get_url: 
         url: http://192.168.48.100/ISOS/openEuler-24.03-LTS-x86_64-dvd.iso
         dest: /home/yuxb
       async: 100
       poll: 0
 ​
 # 执行
 [yuxb@controller web 09:54:43]$ ansible-playbook playbook.yml 
 ​
 PLAY [connection] ***********************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node1]
 ​
 TASK [download] *************************************************************************************
 changed: [node1]
 ​
 PLAY RECAP ******************************************************************************************
 node1                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​
 ​

示例3: ansible 默认行为,等该任务执行完,再执行下一个任务。

async: 0 + poll: 2,相当于默认 → 演示 同步等待,按顺序执行任务

 [yuxb@controller web 09:55:24]$ vim playbook.yml 
 [yuxb@controller web 09:56:13]$ cat playbook.yml 
 ---
 - name: connection
   hosts: node1
   tasks:
     - name: conneciton 
       shell: sleep 10
       async: 0
       poll: 2
 ​
 # 执行
 [yuxb@controller web 09:55:37]$ ansible-playbook playbook.yml 
 ​
 PLAY [connection] ***********************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node1]
 ​
 TASK [conneciton] ***********************************************************************************
 changed: [node1]
 ​
 PLAY RECAP ******************************************************************************************
 node1                      : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​

wait_for 模块

  • 测试 如何让 Playbook 在后台任务完成前,智能等待资源就绪

示例1: 测试文件是否存在

等待文件 /tmp/hello 被创建 → 演示 检测文件存在性

 [yuxb@controller web 09:56:16]$ vim playbook.yml 
 [yuxb@controller web 10:11:46]$ cat playbook.yml 
 ---
 - name: test wait for
   hosts: node1
   tasks:
     - shell: sleep 10 && touch /tmp/hello
       # async时间要大于sleep的时间
       async: 20
       poll: 0
       register: out
 ​
     - name: wait for create /tmp/hello
       wait_for:
         path: /tmp/hello
         state: present
         delay: 5
         timeout: 30
         sleep: 2
 ​
 # 测试
 [yuxb@controller web 09:56:39]$ ansible-playbook playbook.yml 
 ​
 PLAY [test wait for] ********************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node1]
 ​
 TASK [shell] ****************************************************************************************
 changed: [node1]
 ​
 TASK [wait for create /tmp/hello] *******************************************************************
 ok: [node1]
 ​
 PLAY RECAP ******************************************************************************************
 node1                      : ok=3    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​

示例2: 测试主机端口是否打开

等待主机端口(22)恢复 → 演示 等待主机重启并恢复服务

 [yuxb@controller web 10:11:49]$ vim playbook.yml 
 [yuxb@controller web 10:12:49]$ cat playbook.yml 
 ---
 - name: test wait_for
   hosts: node1,node2
   tasks:
     - name: reboot node1
       shell: shutdown -r now "Ansible updates triggered"
       async: 1
       poll: 0
       when: inventory_hostname == "node1"
     
     - name: wait for node1 come back
       wait_for:
         host: node1
         port: 22
         state: started
         # delay,设置检测前延迟时间。
         delay: 10
         # sleep,设置检测时间间隔。
         sleep: 2
         # timeout,设置检测超时时间。
         timeout: 300
       when: inventory_hostname == "node2"
 ​
 # 测试
 # node1会重启,连接会断开
 [yuxb@controller web 10:12:17]$ ansible-playbook playbook.yml 
 ​
 PLAY [test wait_for] ********************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node1]
 ok: [node2]
 ​
 TASK [reboot node1] *********************************************************************************
 skipping: [node2]
 changed: [node1]
 ​
 TASK [wait for node1 come back] *********************************************************************
 skipping: [node1]
 ok: [node2]
 ​
 PLAY RECAP ******************************************************************************************
 node1                      : ok=2    changed=1    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
 node2                      : ok=2    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0   
 ​

async_status 模块

  • 使用 async_status 跟踪任务的 ansible_job_id,直到 finished

  • 演示 如何主动检查后台任务的执行状态,而不是被动等待。

  • 测试 如何追踪和确认异步任务的完成情况

使用 async_status 模块检查之前的任务是否运行完成。

 [yuxb@controller web 10:12:51]$ vim playbook.yml 
 [yuxb@controller web 10:14:35]$ cat playbook.yml 
 ---
 - name: test async_status
   hosts: node1
   tasks:
     - shell: sleep 10 
       async: 20
       poll: 0
       register: out
     
     - name: wait for
       async_status:
         # 通过任务的 ansible_job_id 属性跟踪任务
         jid: "{{ out.ansible_job_id }}"
       register: job_result
       # 根据当前任务执行结果的finished值,判断跟踪任务是否执行完成
       until: job_result.finished
       #retries,设置重试次数,默认值为3。
       retries: 30
       # delay,设置检测时间间隔,默认5秒检测一次。
       delay: 2
 ​
 # 测试
 [yuxb@controller web 10:14:53]$ ansible-playbook playbook.yml 
 ​
 PLAY [test async_status] ****************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node1]
 ​
 TASK [shell] ****************************************************************************************
 changed: [node1]
 ​
 TASK [wait for] *************************************************************************************
 FAILED - RETRYING: wait for (30 retries left).
 FAILED - RETRYING: wait for (29 retries left).
 FAILED - RETRYING: wait for (28 retries left).
 FAILED - RETRYING: wait for (27 retries left).
 FAILED - RETRYING: wait for (26 retries left).
 changed: [node1]
 ​
 PLAY RECAP ******************************************************************************************
 node1                      : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​

Including 和 importing 文件

Ansible 的 Playbook 拆分与调用

playbook 级别(在 Playbook 层级做 include/import)
 [yuxb@controller web 10:38:50]$ vim playbook.yml 
 [yuxb@controller web 10:39:34]$ cat playbook.yml 
 - name: prepare the web server
   import_playbook: pre_web.yml
 ​
 - name: prepare the vsftpd server
   import_playbook: pre_vsftpd.yml
 ​
 - name: prepare the databse server
   import_playbook: pre_db.yml
 ​

其余文件

 [yuxb@controller web 10:40:06]$ cat > pre_web.yml << EOF
 > - name: Play web
 >   hosts: node1
 >   tasks:
 >     - name: install httpd
 >       yum:
 >         name: httpd
 >         state: present
 > EOF
 [yuxb@controller web 10:40:10]$ cat > pre_vsftpd.yml << EOF
 > - name: Play vsftpd
 >   hosts: node1
 >   tasks:
 >     - name: install vsftpd
 >       yum:
 >         name: vsftpd
 >         state: present
 > EOF
 [yuxb@controller web 10:40:17]$ cat > pre_db.yml << EOF
 > - name: Play db
 >   hosts: node1
 >   tasks:
 >     - name: install mariadb-server
 >       yum:
 >         name: mariadb-server
 >         state: present
 > EOF
 ​
 # 执行
 [yuxb@controller web 10:15:07]$ ansible-playbook playbook.yml

Ansible 角色管理

Ansible 角色

什么是角色(Role)

  • 角色(Role) 是 Ansible 提供的一种 分层组织 Playbook 的方式

  • 它可以把任务(tasks)、变量(vars)、文件(files)、模板(templates)等内容,按功能模块化、目录化管理。

  • 适合 大项目多人协作,让 Playbook 更加清晰、可复用。

角色目录结构

一个标准角色目录通常长这样:

 roles/
   └── webserver/         # 角色名称
       ├── tasks/         # 主要任务(main.yml 必须有)
       │    └── main.yml
       ├── files/         # 静态文件
       ├── templates/     # Jinja2 模板
       ├── vars/          # 变量(优先级较高)
       │    └── main.yml
       ├── defaults/      # 默认变量(优先级最低)
       │    └── main.yml
       ├── handlers/      # handlers(如服务重启)
       │    └── main.yml
       └── meta/          # 角色依赖信息
            └── main.yml

Ansible 角色结构

 [yuxb@controller web 11:28:30]$ ansible-galaxy init yubb
 - Role yubb was created successfully
 [yuxb@controller web 11:29:28]$ tree yubb
 yubb
 ├── defaults
 │   └── main.yml
 ├── files
 ├── handlers
 │   └── main.yml
 ├── meta
 │   └── main.yml
 ├── README.md
 ├── tasks
 │   └── main.yml
 ├── templates
 ├── tests
 │   ├── inventory
 │   └── test.yml
 └── vars
     └── main.yml
 ​
 8 directories, 8 files
 ​

Ansible 角色目录位置

  • 本地项目目录:./roles/(最常用)

  • 全局目录:/etc/ansible/roles//usr/share/ansible/roles/

  • 自定义目录:通过 ansible.cfg 设置 roles_path

优先级从上到下依次降低。

可以在ansible.cfg配置文件[defaults]块中通过变量roles_path定义role位置:

 [defaults]
 roles_path  = ./roles
 ......

多个路径使用冒号分隔:

 roles_path = /etc/ansible/roles:/home/student/web/roles

:w

用 Ansible 创建并编写一个角色(Role)来自动化部署 Apache(httpd)Web 服务。

创建角色
 [yuxb@controller web 11:29:33]$ mkdir roles
 [yuxb@controller web 11:30:33]$ ansible-galaxy init apache
 - Role apache was created successfully
 [yuxb@controller web 11:30:39]$ mv apache/ roles
 # 命令一样
 [yuxb@controller web 11:30:45]$ ansible-galaxy init apache --init-path=./roles
 # 生成了 roles/apache/ 目录结构(tasks、handlers、templates、defaults 等)。
 ​
 ​
 # 查看角色列表
 [yuxb@controller web 11:31:34]$ ansible-galaxy list
 # /usr/share/ansible/roles
 # /etc/ansible/roles
 [WARNING]: - the configured path /home/yuxb/.ansible/roles does not exist.
 ​
 [yuxb@controller web 11:31:54]$ cd roles/apache/
 # 核心任务逻辑:安装、启动、配置、创建目录和首页
 [yuxb@controller apache 11:31:55]$ vim tasks/main.yml
 [yuxb@controller apache 11:33:11]$ cat tasks/main.yml 
 ---
 # tasks file for apache
 ​
 # 1. 安装 Apache 软件包(默认为 httpd)
 - name: install web
   yum:
     name: "{{ web_package }}"   # 使用变量,便于修改
     state: latest               # 确保安装最新版本
 ​
 # 2. 启动并设置 Apache 开机自启
 - name: "start {{ web_service }}"
   service:
     name: "{{ web_service }}"   # 服务名(默认为 httpd)
     state: started              # 确保服务已启动
     enabled: yes                # 开机自动启动
 ​
 # 3. 渲染 motd 模板,更新 /etc/motd 欢迎信息
 - name: prepare motd
   template:
     src: motd.j2                # 模板文件路径(位于 templates/)
     dest: /etc/motd             # 渲染后生成的目标文件
 ​
 # 4. 渲染 Apache 虚拟主机配置
 - name: prepare yuxb site
   template:
     src: yuxb.conf.j2           # 虚拟主机配置模板
     dest: /etc/httpd/conf.d/yuxb.conf
   notify:                       # 如果文件有变化,触发 handlers
     - restart_web
 ​
 # 5. 创建站点目录(以主机名区分,避免冲突)
 - name: prepare DocumentRoot 
   file:
     path: "/var/www/html/{{ ansible_hostname }}"  # 每台主机单独目录
     state: directory                              # 确保存在目录
 ​
 # 6. 渲染首页 index.html
 - name: prepare index.html
   template:
     src: index.html.j2          # 首页模板
     dest: "/var/www/html/{{ ansible_hostname }}/index.html"
 ​
 # 定义默认变量,便于在 tasks 中引用
 [yuxb@controller apache 11:33:15]$ vim defaults/main.yml
 [yuxb@controller apache 11:34:04]$ cat defaults/main.yml 
 ---
 # defaults file for apache
 # 定义默认软件包和服务名称,方便在 tasks 中调用
 web_package: httpd # Apache 软件包
 web_service: httpd # Apache 服务名
 ​
 ​
 [yuxb@controller apache 11:34:18]$ vim templates/motd.j2
 [yuxb@controller apache 11:34:33]$ cat templates/motd.j2
 hello guys!
 Welcome to {{ ansible_fqdn }}!
 ​
 ​
 [yuxb@controller apache 11:36:48]$ cat templates/yuxb.conf.j2 
 # {{ ansible_managed }}
 <VirtualHost *:80>
     ServerAdmin yuxb@{{ ansible_fqdn }}
     ServerName {{ ansible_fqdn }}
     ErrorLog logs/{{ ansible_hostname }}-error.log
     CustomLog logs/{{ ansible_hostname }}-common.log common
     DocumentRoot /var/www/html/{{ ansible_hostname }}/
 ​
     <Directory /var/www/html/{{ ansible_hostname }}/>
        Options +Indexes +FollowSymlinks +Includes
        Order allow,deny
        Allow from all
     </Directory>
 </VirtualHost>
 ​
 # 定义“触发器”,当配置文件变化时执行
 [yuxb@controller apache 11:36:56]$ vim handlers/main.yml
 [yuxb@controller apache 11:37:42]$ cat handlers/main.yml 
 ---
 # handlers file for apache
 - name: restart_web
   service:
     name: "{{ web_service }}" # 使用变量,默认为 httpd
     state: restarted          # 重启 Apache 服务
 ​
 # 模板文件:系统欢迎信息(motd)
 [yuxb@controller apache 11:37:46]$ vim templates/index.html.j2
 [yuxb@controller apache 11:38:31]$ cat templates/index.html.j2 
 Welcome to {{ ansible_fqdn }} !
 ​
调用角色
 [yuxb@controller web 11:46:25]$ cat playbook.yml 
 ---
 - name: deploy apache
   hosts: node2
   roles:
     - apache
 ​
 [yuxb@controller web 11:52:31]$ ansible-playbook playbook.yml 
 ​
 PLAY [deploy apache] ********************************************************************************
 ​
 TASK [Gathering Facts] ******************************************************************************
 ok: [node2]
 ​
 TASK [apache : install web] *************************************************************************
 ok: [node2]
 ​
 TASK [apache : start httpd] *************************************************************************
 ok: [node2]
 ​
 TASK [apache : prepare motd] ************************************************************************
 changed: [node2]
 ​
 TASK [apache : prepare yuxb site] *******************************************************************
 changed: [node2]
 ​
 TASK [apache : prepare DocumentRoot] ****************************************************************
 changed: [node2]
 ​
 TASK [apache : prepare index.html] ******************************************************************
 changed: [node2]
 ​
 RUNNING HANDLER [apache : restart_web] **************************************************************
 changed: [node2]
 ​
 PLAY RECAP ******************************************************************************************
 node2                      : ok=8    changed=5    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
 ​

验证

 [yuxb@controller web 11:52:45]$ curl http://node2/
 Welcome to node2.yuxb.cloud !
 [yuxb@controller web 11:53:37]$ ssh node2
 Last login: Tue Aug 19 11:52:43 2025 from 10.1.8.10
 hello guys!
 Welcome to node2.yuxb.cloud!
 ​

使用系统角色

系统角色安装和说明

 [yuxb@controller web 13:36:00]$ sudo yum install -y rhel-system-roles
 ​

角色使用案例-timesync

使用 Ansible 的系统角色(system roles)来管理 NTP 时间同步服务

 [yuxb@controller web 13:45:52]$ vim ansible.cfg 
 [yuxb@controller web 13:46:53]$ cat ansible.cfg 
 [defaults]
 inventory = ./inventory
 remote_user = yuxb
 vault_password_file = ./password-for-vault
 roles_path  = ./roles:/usr/share/ansible/roles/ #设置了角色搜索路径,保证 Ansible 可以找到系统角色和本地自定义角色。
 #ask_pass = True
 #module_name = command
 #private_key_file = /opt/id_rsa
 #host_key_checking = False
 ​
 [privilege_escalation]
 become=True
 become_method=sudo
 become_user=root
 become_ask_pass=False
 ​
 ​
 # playbook内容取自如下
 [yuxb@controller web 13:47:23]$ vim /usr/share/ansible/roles/rhel-system-roles.timesync/README.md 
 ​
 ​
 # 调用了 rhel-system-roles.timesync 角色,自动配置时间同步服务。
 # 通过变量 timesync_ntp_servers 指定 NTP 服务器(这里是 ntp.aliyun.com)。
 # 角色内部会根据变量去修改系统配置(如 /etc/chrony.conf 或 /etc/ntp.conf),启动时间同步服务,并确保服务开机自启。
 [yuxb@controller web 13:46:56]$ vim playbook.yml 
 [yuxb@controller web 13:51:24]$ cat playbook.yml 
 - name: Manage timesync with 1 servers
   hosts: all
   vars:
     timesync_ntp_servers:
       - hostname: ntp.aliyun.com
         iburst: true
   roles:
     - rhel-system-roles.timesync
 ​
 # 执行
 # Ansible 会在所有目标主机上执行系统角色 tasks,实现 自动化时间同步配置。
 [yuxb@controller web 13:54:08]$ ansible-playbook playbook.yml 
 ​

Ansible 自动化部署“负载均衡 + Web 服务”架构

  1. 准备工具

    • 下载两个“现成脚本包”:

      • apache:能一键帮你装好 Apache Web 服务。

      • haproxy:能一键帮你装好 HAProxy 负载均衡。

  2. 写了“任务清单”(Playbook)

    • controller 机器去装 HAProxy,配置好后端的 4 台 Web 节点。

    • node1-4 机器去装 Apache,每台都能跑网站。

  3. 写了“通讯录”(Inventory)

    • controller 这一台 = 负载均衡器。

    • node1~node4 四台 = 网站服务器。

  4. 一键执行任务

    • 运行 Playbook,Ansible 就自动去所有机器执行任务,不用你一台一台手动配置。

  5. 验证效果

    • 访问 http://controller,请求被 HAProxy 自动分发到不同的 Web 节点。

    • 所以可以看到:一会儿是 node2 的欢迎语,一会儿是 node3、node4、node1 的。

    • 这就是 负载均衡:把访问请求平均分到多台服务器上

 [yuxb@controller web 14:10:27]$ ansible-galaxy role search --author geerlingguy apache
 ​
 Found 2 roles matching your search:
 ​
  Name                       Description
  ----                       -----------
  geerlingguy.apache         Apache 2.x for Linux.
  geerlingguy.apache-php-fpm Apache 2.4+ PHP-FPM support for Linux.
 [yuxb@controller web 14:10:52]$ ansible-galaxy role install geerlingguy.apache
 - downloading role 'apache', owned by geerlingguy
 - downloading role from https://github.com/geerlingguy/ansible-role-apache/archive/4.0.0.tar.gz
 - extracting geerlingguy.apache to /home/yuxb/web/roles/geerlingguy.apache
 - geerlingguy.apache (4.0.0) was installed successfully
 [yuxb@controller web 14:12:02]$ ls roles/
 apache  geerlingguy.apache
 ​
 [yuxb@controller web 14:17:18]$ ansible-galaxy install http://192.168.42.100/%E8%BD%AF%E4%BB%B6/ansible-role-haproxy-1.3.1.tar.gz
 - downloading role from http://192.168.42.100/%E8%BD%AF%E4%BB%B6/ansible-role-haproxy-1.3.1.tar.gz
 - extracting ansible-role-haproxy-1.3.1 to /home/yuxb/web/roles/ansible-role-haproxy-1.3.1
 - ansible-role-haproxy-1.3.1 was installed successfully
 ​
 [yuxb@controller web 14:20:18]$ mv roles/ansible-role-haproxy-1.3.1/ roles/haproxy
 [yuxb@controller web 14:21:19]$ ls roles/
 apache  geerlingguy.apache  haproxy
 ​
 [yuxb@controller web 14:24:02]$ vim playbook.yml 
 [yuxb@controller web 14:28:59]$ cat playbook.yml 
 - name: deploy LB
   hosts: LBs
   vars:
     haproxy_backend_servers:
       - name: node1
         address: 10.1.8.11:80
       - name: node2
         address: 10.1.8.12:80
       - name: node3
         address: 10.1.8.13:80
       - name: node4
         address: 10.1.8.14:80
   roles:
     - haproxy
 - name: deploy apache
   hosts: WEBs
   roles:
     - apache 
 ​
 [yuxb@controller web 14:29:02]$ vim inventory 
 [yuxb@controller web 14:30:26]$ cat inventory 
 [LBs]
 controller
  
 [WEBs]s                  674321`234CXa
 node[1:4]
 ​
 ​
 [yuxb@controller web 14:32:02]$ ansible all -a 'systemctl disable nginx --now'
 ​
 ​
 [yuxb@controller web 14:30:49]$ ansible-playbook playbook.yml 
 ​
 [yuxb@controller web 14:33:09]$ curl http://controller
 Welcome to node2.yuxb.cloud !
 [yuxb@controller web 14:33:25]$ curl http://controller
 Welcome to node3.yuxb.cloud !
 [yuxb@controller web 14:33:29]$ curl http://controller
 Welcome to node4.yuxb.cloud !
 [yuxb@controller web 14:33:29]$ curl http://controller
 Welcome to node1.yuxb.cloud !
 ​

网站公告

今日签到

点亮在社区的每一天
去签到