如何让Ansible Playbook中的特定任务仅执行一次?
问题描述
为实验室项目编写Ansible Playbook,基于EC2 Ubuntu实例托管网站。安装启用apache2后,/var/www/html/目录会生成默认的index.html文件。编写了删除该文件的任务,用于拉取Git源码前清理目录,首次运行正常,但重复执行Playbook时,该删除任务会导致网站宕机。目前只能在首次运行后注释/删除该任务,尝试过run_once但未成功实现仅执行一次的效果。
Inventory 文件
all: hosts: webserver: ansible_host: ansible_user: ansible_ssh_private_key_file: webserver02: ansible_host: ansible_user: ansible_ssh_private_key_file: webserver03: ansible_host: ansible_user: ansible_ssh_private_key_file: children: webservers: hosts: webserver: webserver02: webserver03:
原 Playbook 代码
- name: Install webserver packages hosts: webservers become: yes tasks: - name: Install apache2 ansible.builtin.apt: name: "{{item}}" state: latest update_cache: yes loop: - apache2 - git - zip - unzip - name: Start apache2 service ansible.builtin.service: name: apache2 state: started enabled: yes ### Delete this tasks after running the playbook once ### - name: Remove default index.html ansible.builtin.file: path: /var/www/html/index.html state: absent - name: Clone the source code ansible.builtin.git: repo: "{{ gitrepo }}" ### git source code ### dest: "{{ index_html }}" ### /var/www/html ### single_branch: yes version: gottoweb notify: # the handler will only get executed if there is a change in the git task - restart apache2 service handlers: # this handler only restarts apache2 when there is a change in the git task - name: restart apache2 service ansible.builtin.service: name: apache2 state: restarted enabled: yes
解决方案
方案1:仅删除Apache默认的index.html
通过检查文件内容特征,判断当前index.html是否为Apache默认页面,仅在匹配时执行删除操作。后续运行时,自定义的index.html不会被误删。
修改后的任务片段:
- name: Start apache2 service ansible.builtin.service: name: apache2 state: started enabled: yes # 新增判断逻辑 - name: Check if index.html is Apache default page ansible.builtin.command: grep -q "Apache2 Ubuntu Default Page" /var/www/html/index.html register: is_default_index ignore_errors: yes changed_when: false # 标记该任务不会改变系统状态 - name: Remove default index.html (only if it's Apache's default) ansible.builtin.file: path: /var/www/html/index.html state: absent when: is_default_index.rc == 0 # 仅当匹配到默认页面内容时执行 - name: Clone the source code ansible.builtin.git: repo: "{{ gitrepo }}" dest: "{{ index_html }}" single_branch: yes version: gottoweb notify: - restart apache2 service
方案2:强制Git克隆覆盖默认文件
如果Git仓库包含网站所需的全部文件,可在git任务中添加force: yes参数,强制克隆并覆盖目录内的默认文件,无需单独的删除任务。该方法会清除目录中不在Git仓库内的文件,适合完全由Git管理网站文件的场景。
修改后的Git任务:
- name: Clone the source code (force overwrite existing files) ansible.builtin.git: repo: "{{ gitrepo }}" dest: "{{ index_html }}" single_branch: yes version: gottoweb force: yes notify: - restart apache2 service
方案3:先拉取Git代码,再清理残留默认文件
调整任务顺序,先执行Git拉取,再检查并删除可能残留的默认index.html。此方法避免了先删除正在使用的自定义文件导致的宕机,但需确保Git仓库能正常克隆到非空目录(或搭配方案2的force参数)。
修改后的任务顺序:
- name: Start apache2 service ansible.builtin.service: name: apache2 state: started enabled: yes - name: Clone the source code ansible.builtin.git: repo: "{{ gitrepo }}" dest: "{{ index_html }}" single_branch: yes version: gottoweb force: yes # 可选,用于首次克隆非空目录 notify: - restart apache2 service - name: Check if index.html is Apache default page ansible.builtin.command: grep -q "Apache2 Ubuntu Default Page" /var/www/html/index.html register: is_default_index ignore_errors: yes changed_when: false - name: Remove leftover default index.html ansible.builtin.file: path: /var/www/html/index.html state: absent when: is_default_index.rc == 0
内容的提问来源于stack exchange,提问作者Kyle
相关产品推荐
相关产品推荐

