Ansible Lint 常见问题 FAQ

发布时间: 更新时间: 总字数:1702 阅读时间:4m 作者:IP:上海 网址

Ansible Lint 常见问题与修复指南 (FAQ)

F&A

Ansible-lint is not available. Kindly check the path or disable validation using ansible-lint

pip3 install ansible-lint

fqcn[action-core]:内置模块未使用全限定集合名称 (FQCN)

  • 问题现象Use FQCN for builtin module actions (include_tasks/apt/yum)
  • 原因:Ansible 2.10+ 将核心模块移入 ansible.builtin 集合。使用简写虽兼容,但易引发命名冲突。
  • 解决方法:将简写替换为完整集合名。
    yaml
    # 修改前
    include_tasks: my_tasks.yml
    apt: name=nginx state=present
    # 修改后
    ansible.builtin.include_tasks: my_tasks.yml
    ansible.builtin.apt: name=nginx state=present
  • 批量修复:运行 ansible-lint --fix all 可一键全局替换。

risky-file-permissions:文件权限未设置或设置不正确

  • 问题现象:使用 copy/file/template 等模块时未指定权限。
  • 原因:不指定 mode 会继承系统 umask,可能导致敏感文件权限过宽。
  • 解决方法:显式声明权限值。
    • 普通文件/配置:mode: '0644'
    • 目录/可执行脚本:mode: '0755'
    • 私钥/密码文件:mode: '0600'

yaml[octal-values]:禁止隐式八进制值 0644

  • 问题现象Forbidden implicit octal value "0644"
  • 原因:YAML 1.1 将 0644 解析为八进制,YAML 1.2 可能解析为十进制,存在歧义风险。
  • 解决方法永远给权限值加引号,强制转为字符串。
    yaml
    mode: 0644   # 错误
    mode: '0644' # 正确

key-order[play]:Play 关键字顺序不符合规范

  • 问题现象You can improve the play key order to: name, hosts, gather_facts, tasks
  • 原因:为提升可读性,Lint 要求按逻辑顺序排列 Play 属性。
  • 解决方法:调整标准顺序: name -> hosts -> gather_facts/become -> vars/vars_files -> roles -> tasks -> handlers
  • 批量修复ansible-lint --fix all 可自动重排。

no-changed-when:Shell/Command 命令未定义变更条件

  • 问题现象Commands should not change things if nothing needs doing.
  • 原因shell/command 默认每次运行都返回 changed: true,破坏 Ansible 幂等性。
  • 解决方法(按场景):
    • 只读检查:加 changed_when: false
    • 条件变更:结合 register 捕获输出,如 changed_when: "'Updated' in result.stdout"
    • 最佳实践:优先改用 Ansible 原生模块(如 git, unarchive, get_url),自动处理状态。

run-once[task]run_oncefree 策略冲突

  • 问题现象Using run_once may behave differently if strategy is set to free.
  • 原因strategy: free 下主机异步执行,run_once: true 无法保证确定性。
  • 解决方法
    1. 推荐:显式声明 strategy: linear(Ansible 默认策略,消除歧义)。
    2. 拆分:将需 run_once 的任务独立到一个默认的 linear Play 中。

syntax-check[specific]:关键字层级冲突

  • 问题现象conflicting action statements: strategy, ansible.builtin.debug
  • 原因strategyPlay 级 关键字,被错误地写在了 Task 级 内部。
  • 解决方法:将 strategy: linear 移出 tasks: 列表,与 hosts: 保持同级缩进。

risky-shell-pipe:管道命令未设置 pipefail

  • 问题现象Shells that use pipes should set the pipefail option.
  • 原因:默认管道只返回最后一个命令的退出码。前置命令失败会被掩盖,Ansible 误判成功。
  • 解决方法:首行添加 set -o pipefail,并指定 bash 解释器。
    yaml
    ansible.builtin.shell: |
      set -o pipefail
      cat /var/log/app.log | grep "ERROR"
    args:
      executable: /bin/bash

command-instead-of-module:滥用 systemctl 命令

  • 问题现象systemctl used in place of systemd module
  • 原因:直接调 Shell 命令缺乏幂等性、不支持 Check Mode。
  • 解决方法:改用 ansible.builtin.systemd 模块。
    • systemctl start nginx && enable nginx -> name: nginx, state: started, enabled: true
    • systemctl daemon-reload -> daemon_reload: true

name[template]:任务名称以 Jinja 变量开头

  • 问题现象Jinja templates should only be at the end of 'name'
  • 原因:以变量开头会导致日志输出难以搜索、追踪和审计。
  • 解决方法:确保任务名以静态动词开头,变量置后。
    yaml
    name: "{{ item }} install"      # 错
    name: "Install package {{ item }}" # 对

package-latest:软件包安装使用 state: latest

  • 问题现象Package installs should not use latest.
  • 原因:每次运行都会尝试升级,导致环境版本不可控、可能引发意外重启。
  • 解决方法
    • 生产推荐:改为 state: present 或锁定版本(如 name: nginx=1.18.0)。
    • 特殊场景(如 CI/CD 镜像构建):若确需最新,行尾加注释忽略:# noqa package-latest

changed_when 语法疑问:"'Initialized' not in init_result.stdout" 正确吗?

  • 答案语法完全正确changed_when 支持 Jinja2/Python 表达式。
  • 逻辑自检:该写法表示“输出中不包含该词时,标记为 changed”。
    • 适用场景:脚本在“已初始化”时输出 Already Initialized,无输出或输出其他内容时才代表执行了变更。
    • 常见误区:若脚本成功初始化会输出 Initialized,则应改用 in(即 "'Initialized' in init_result.stdout")。
    • 💡 注意:若 stdout 为空字符串 '''xxx' not in '' 会返回 true,请结合业务逻辑确认。