Linux 自动化运维工具实战

1次阅读

ansible卡在“gathering facts”主因是setup模块收集系统信息失败,需确认python版本、ssh配置并可禁用事实收集;shell模块不解析jinja2变量,应指定executable或改用shell模块;cron模块不重载服务且忽略path,须校验语法并显式指定user和完整路径;跨发行版需用package模块或条件判断os_family。

Linux 自动化运维工具实战

Ansible 执行任务卡在 “Gathering Facts” 不动

这是最常见的阻塞点,不是 Ansible 挂了,而是它默认会先 SSH 连上去跑 setup 模块收集目标主机的系统信息(比如 OS 版本、IP、磁盘、Python 路径等)。如果目标机 Python 缺失、SSH 延迟高、或防火墙拦截了某些探测行为,就会卡住甚至超时失败。

实操建议:

  • 确认目标主机已安装 Python 3(python3 --version),Ansible 2.10+ 默认要求 Python 3;若只有 Python 2,需在 inventory 中显式指定 ansible_python_interpreter=/usr/bin/python2
  • 跳过事实收集:在 playbook 顶层加 gather_facts: false,或 ad-hoc 命令加 -m ping 快速验证连通性(ansible all -m ping
  • 检查 SSH 配置:确保 ControlPersist yesControlMaster auto 开启,避免每次任务都新建连接;同时确认 ~/.ssh/config 中没写错 HostKeyAlgorithms 导致握手失败

Shell 模块里变量不展开,{{ item }} 输出字面量

Ansible 的 shellcommand 模块默认不经过 shell 解析器,所以 $PATH$(date){{ item }} 这类都不会被替换——它们只是字符串参数,传给远程 /bin/sh -c 时还没被 Jinja2 渲染。

实操建议:

  • args: + executable: /bin/bash 强制走 bash:
    - name: Run bash command with variable   shell: echo "host: {{ inventory_hostname }}"   args:     executable: /bin/bash
  • 更安全的做法是改用 ansible.builtin.shell(显式声明)并配合 vars:loop: 控制上下文,避免拼接字符串引发注入
  • 如果只是想执行简单命令,优先用 command 模块(更安全、无 shell 注入风险),把需要展开的内容提前用 set_fact 存成变量再引用

Cron 模块添加定时任务后不生效

Ansible 的 cron 模块只负责写入 /var/spool/cron//etc/cron.d/,但不会 reload cron daemon,也不会校验语法是否合法。常见现象是文件写了,但 crond 没读取,或者环境变量缺失导致脚本找不到命令。

实操建议:

  • validate: 'crontab -t %s' 参数让 Ansible 在写入前校验语法,避免非法格式写死 cron 表
  • 明确指定 user:(如 root),否则默认以当前连接用户写入,可能和预期不符;写入 /etc/cron.d/ 时还必须带用户名字段,cron daemon 才认
  • 注意 PATH:系统 crond 的默认 PATH 很窄(通常只有 /usr/bin:/bin),脚本中别直接写 python3,换成 /usr/bin/python3 或在 crontab 条目开头加 PATH=/usr/local/bin:/usr/bin:/bin

Playbook 在不同发行版上因包管理器报错

同一份 Playbook 在 centosubuntu 上运行,yumapt 模块不能混用,硬编码会导致失败。Ansible 不会自动识别 distro 并切换模块,得靠条件判断。

实操建议:

  • ansible_facts['distribution']ansible_facts['os_family'] 做条件分支,例如:
    - name: Install nginx   yum:     name: nginx     state: present   when: ansible_facts['os_family'] == 'RedHat'
  • 优先使用抽象层模块如 package(Ansible 2.5+),它会根据 ansible_facts['pkg_mgr'] 自动选 apt/yum/dnf,但要注意旧版系统(如 CentOS 7)的 pkg_mgr 可能是 yum,而 CentOS 8 是 dnf,行为略有差异
  • 避免在 vars: 里硬写包名(如 nginx_package: nginx),应按发行版覆盖:vars_files: [vars/RedHat.yml, vars/debian.yml]

真正麻烦的从来不是写多少 task,而是每个模块背后隐含的执行上下文:Python 版本、shell 环境、cron 加载机制、包管理器状态——这些细节不会报错,但会让任务静默失败。

text=ZqhQzanResources