Ansible递归修改SFTP Chroot目录权限/组时,大目录树执行报worker死状态错误求助
我太懂你这种头疼了——用Ansible递归处理SFTP chroot下的大目录树时,直接跑递归任务就触发worker崩溃,报错:
ERROR! A worker was found in a dead state
大概率是内存耗尽或者栈溢出的问题,毕竟大目录里文件数量太多,Ansible原生的file模块递归是用Python层面处理的,扛不住这么大的量级。结合你的需求:要统一chroot目录下非隐藏文件/文件夹的组(厂商要求的默认组)和权限(0755),我给你几个实用的解决方向:
1. 用系统原生find命令替代Ansiblefile模块(最推荐)
系统自带的find是原生C实现的,处理海量文件的效率和内存占用比Python递归好太多。你可以在Ansible里用command模块直接调用find,分别处理目录和文件,还能跳过隐藏项:
- name: Fix permissions and group for non-hidden directories command: find /path/to/your/chroot -type d ! -name ".*" -exec chmod 0755 {} \; -exec chgrp your-default-group {} \; args: warn: false # 避免Ansible对raw命令的警告 changed_when: false # 如果需要判断变更,可以根据命令输出调整,比如检查是否有匹配项 - name: Fix permissions and group for non-hidden files command: find /path/to/your/chroot -type f ! -name ".*" -exec chmod 0755 {} \; -exec chgrp your-default-group {} \; args: warn: false changed_when: false
2. 把递归任务改成异步执行,分摊压力
如果你坚持要用Ansible原生模块,试试把递归任务拆成异步执行,给足超时时间和轮询间隔,避免worker被压垮:
- name: Start recursive permission fix (async) file: path: /path/to/your/chroot state: directory mode: '0755' group: your-default-group recurse: yes async: 3600 # 设置1小时超时,根据你的目录大小调整 poll: 0 # 立即返回,不阻塞后续任务 register: perm_fix_job - name: Wait for permission fix to finish async_status: jid: "{{ perm_fix_job.ansible_job_id }}" register: job_status until: job_status.finished retries: 60 # 每隔10秒检查一次,总共等10分钟 delay: 10
3. 从根源解决:设置默认ACL和umask
这才是一劳永逸的办法——给chroot根目录设置默认ACL,让后续新建的文件/文件夹自动继承正确的组和权限,这样就不用反复递归修复了:
- name: Set default group ACL for chroot directory acl: path: /path/to/your/chroot default: yes state: present entity: your-default-group etype: group permissions: rwx # 对应目录的0755,文件会自动继承合理权限
同时在SFTP服务配置(比如sshd_config)里给用户强制设置umask,比如在Match Group sftp-users块里加上:
ForceCommand internal-sftp -u 002
这样用户创建文件时默认权限就是0755,目录是0775(如果需要目录也是0755,可以调整umask或者ACL),从根源减少权限问题。
4. 拆分目录分批处理
如果以上方法都不适用,可以把大目录拆成多个子目录分批处理,避免单次任务处理太多文件:
- name: Get list of non-hidden first-level subdirectories command: find /path/to/your/chroot -maxdepth 1 -type d ! -name ".*" ! -path /path/to/your/chroot register: chroot_subdirs changed_when: false - name: Fix permissions for each subdirectory (async) file: path: "{{ item }}" state: directory mode: '0755' group: your-default-group recurse: yes loop: "{{ chroot_subdirs.stdout_lines }}" async: 1800 poll: 0 register: subdir_jobs - name: Wait for all subdirectory tasks to complete async_status: jid: "{{ item.ansible_job_id }}" register: subdir_status until: subdir_status.finished retries: 30 delay: 10 loop: "{{ subdir_jobs.results }}"
优先推荐第一种方法,效率最高,内存占用最小;第三种是治本的方案,能彻底减少后续的维护成本。
备注:内容来源于stack exchange,提问作者user158642

