DevOps ·

Ansible 入门:安装、Playbook 编写与日常排障

Ansible 是运维自动化必备工具,基于 SSH 无 Agent 架构。本文从安装、Inventory、模块、Playbook 开始,到 Roles、常用场景、常见报错排查,系统整理一套日常能用的学习与排障手册。

Ansible 入门:安装、Playbook 编写与日常排障

Ansible 是一款基于 SSH、无 Agent、声明式的自动化配置管理工具,用 Python 编写,用 YAML 描述任务。相比 Puppet/Chef/Salt,它最大的优势是被控端不用装任何东西——只要能 SSH 上去、有 Python 就能管。

一、学习路线与核心概念

1.1 核心组件速览

组件作用说明
Control Node控制节点执行 ansible / ansible-playbook 的机器,一般是你的 Mac / 跳板机
Managed Node被控节点被管理的服务器,只需要 SSH + Python 2.7/3.5+
Inventory主机清单写哪些机器要管,支持分组、变量
Module模块单步操作的最小单元,如 yumcopyserviceshell
Playbook剧本YAML 文件,把多个模块按顺序编排成一套任务
Role角色把 Playbook + 模板 + 文件 + 默认变量按目录结构打包,便于复用
Task任务Playbook 里的一步,通常调用一个模块
Handler处理器Task 通知触发(比如改完配置才重启服务)
Facts事实被控端自动采集的变量(OS、网卡、CPU、磁盘等)

1.2 学习路线建议

  1. 单模块先跑通 ansible ad-hoc(临时命令)→ 理解 Inventory + SSH 连通
  2. 会写 10–20 行的小 Playbook(装包→写配置→启服务)→ 掌握 copy / template / service / package 四大基础模块
  3. 学会变量优先级、条件 when、循环 loopblock 错误处理
  4. 把 Playbook 拆成 Roles,理解 ansible-galaxy 与社区角色
  5. 进阶:ansible-lint、Vault 加密密码、AWX/Tower Web 界面、Molecule 测试

二、安装与第一个命令

2.1 安装控制节点

# macOS
brew install ansible

# Debian / Ubuntu
sudo apt update && sudo apt install -y ansible

# pip(版本最新)
python3 -m pip install --user ansible

# 验证
ansible --version
# 关注:ansible [core x.y.z],config file,python version

2.2 准备 Inventory

最简单写一个 hosts 文件(INI 格式):

[web]
web01 ansible_host=192.168.1.10 ansible_user=root
web02 ansible_host=192.168.1.11 ansible_user=deploy

[db]
db01 ansible_host=192.168.1.20 ansible_port=2222 ansible_user=root

[prod:children]
web
db

[prod:vars]
ansible_ssh_private_key_file=~/.ssh/id_ed25519

分组支持 [group:children] 嵌套、[group:vars] 变量。更推荐生产用 YAML 格式或 Dynamic Inventory(从 CMDB / 云平台拉)。

2.3 第一个 ad-hoc 命令

# -i 指定 inventory,all = 所有主机,-m ping 模块(不是 ICMP,是 SSH+Python 连通测试)
ansible all -i hosts -m ping

成功返回 pong 就说明 SSH 认证 + Python 环境 OK。

# 收集 Facts
ansible web -i hosts -m gather_facts

# 批量执行 shell
ansible web -i hosts -m shell -a "uptime && free -h"

# 批量安装包(幂等:装过就跳过)
ansible web -i hosts -m apt -a "name=nginx state=present update_cache=yes" -b
# -b = --become,相当于 sudo

三、写第一个 Playbook

建一个 nginx.yml

---
- name: 配置并启动 Nginx
  hosts: web
  become: true
  gather_facts: true

  vars:
    nginx_worker_connections: 1024
    nginx_port: 80

  tasks:
    - name: 安装 Nginx
      ansible.builtin.package:
        name: nginx
        state: present

    - name: 部署 nginx.conf 模板
      ansible.builtin.template:
        src: templates/nginx.conf.j2
        dest: /etc/nginx/nginx.conf
        owner: root
        group: root
        mode: "0644"
        validate: "nginx -t -c %s"     # 保存前先校验配置语法
      notify: 重启 Nginx              # 文件变了才触发 handler

    - name: 确保 Nginx 启动并开机自启
      ansible.builtin.service:
        name: nginx
        state: started
        enabled: true

    - name: 放通防火墙
      ansible.builtin.firewalld:
        port: "{{ nginx_port }}/tcp"
        permanent: true
        immediate: true
        state: enabled
      when: ansible_os_family == 'RedHat'   # 条件:只有 RHEL/CentOS/Rocky 才执行

  handlers:
    - name: 重启 Nginx
      ansible.builtin.service:
        name: nginx
        state: restarted

然后建模板 templates/nginx.conf.j2(Jinja2):

worker_processes auto;
events {
    worker_connections {{ nginx_worker_connections }};
}
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    sendfile        on;
    keepalive_timeout  65;
    server {
        listen       {{ nginx_port }};
        server_name  _;
        location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
        }
    }
}

执行:

# 先 DRY RUN 看会改什么(推荐每次先跑)
ansible-playbook -i hosts nginx.yml --check --diff

# 真的执行
ansible-playbook -i hosts nginx.yml

# 限制只跑某台主机,加 -l
ansible-playbook -i hosts nginx.yml -l web01

# 只跑叫"部署配置"的 task,加 --tags
ansible-playbook -i hosts nginx.yml --tags config

四、常用基础模块 Top 10

模块场景示例
ansible.builtin.package装包(跨发行版自动选 yum/apt/dnf)package: name=vim state=present
ansible.builtin.copy拷贝本地文件到远端copy: src=app.properties dest=/opt/app/ mode=0600
ansible.builtin.template拷贝 Jinja2 模板并渲染见上面 Playbook 例子
ansible.builtin.service / systemd管理服务启停、开机自启service: name=crond state=started enabled=yes
ansible.builtin.file建目录/软链/改权限file: path=/data/logs state=directory mode=0755
ansible.builtin.lineinfile改配置文件的某一行lineinfile: path=/etc/sysctl.conf regexp='^fs.file-max' line='fs.file-max=65535'
ansible.builtin.replace正则替换多行replace: path=... regexp='old' replace='new'
ansible.builtin.user / group建用户组user: name=deploy shell=/bin/bash groups=sudo append=yes
ansible.builtin.get_url下载文件get_url: url=https://.../app.tar.gz dest=/tmp/ checksum=sha256:xxx
ansible.builtin.shell / command跑命令(尽量少用)shell: "cat /var/log/nginx/*.log | wc -l"

小原则:能用声明式模块解决的就不要用 shell,shell 会破坏幂等性。

五、变量优先级速记(从低到高)

越后面优先级越高:

  1. Role defaults(roles/x/defaults/main.yml
  2. Inventory group_vars/all
  3. Inventory group_vars/<group>
  4. Inventory host_vars/<host>
  5. Playbook vars
  6. Playbook vars_prompt / vars_files
  7. Role varsroles/x/vars/main.yml
  8. --extra-vars / -e 命令行(最高,-e "foo=bar"

生产建议:敏感变量(密码、Token)用 Ansible Vault,别明文写:

# 加密一个文件
ansible-vault encrypt group_vars/prod/vault.yml
# 执行时加 --ask-vault-pass 或 --vault-password-file
ansible-playbook site.yml --ask-vault-pass

六、Role 目录结构

roles/
  nginx/
    defaults/main.yml      # 最低优先级变量(可被覆盖)
    vars/main.yml          # 高优先级变量
    tasks/main.yml         # 任务入口
    handlers/main.yml      # handlers
    templates/             # .j2 模板
    files/                 # 直接拷贝的文件
    meta/main.yml          # 角色依赖

在 Playbook 里引用:

- hosts: web
  roles:
    - nginx

七、日常排障手册

7.1 调试手段清单

需求命令 / 做法
最 verbose 输出,看到每个模块传参和 SSH 细节-vvvv
只看会改什么,不动真实环境--check --diff
打印变量值- debug: var=myvar 或 `- debug: msg=”{{ myvar
停止在第一个失败任务处调试--step(每步问)或 --start-at-task='Task名'
单步快速验证某个模块用 ad-hoc ansible host -m xxx -a '...'
验证 Playbook 语法ansible-playbook yml --syntax-check
静态扫描最佳实践ansible-lint playbook.yml

7.2 常见报错对照表

报错关键字根因 / 排查方式
FAILED! => {"msg": "Failed to connect to the host via ssh: ... Permission denied (publickey,password)."}SSH 不通:检查 ansible_user / 私钥路径 / 目标主机 authorized_keys / 本地 ssh-add -l 是否有 Key,先手动 ssh user@host
MODULE FAILURE\nSee stdout/stderr for the exact error + /bin/sh: /usr/bin/python: No such file or directory目标没装 Python(Ubuntu 最小化安装常见)。装 python3,或 inventory 加 ansible_python_interpreter=/usr/bin/python3
Missing sudo password需要 -K / --ask-become-pass 输入 sudo 密码,或确认 become 配置是否正确
Syntax Error while loading YAMLYAML 缩进错、Tab 代替空格、冒号后面没空格。用 yamllint 或 VS Code YAML 插件先查
The task includes an undefined variable变量没定义 / 打错名字。加 defaults 过滤器兜底:`{{ myvar
FAILED! => {"changed": false, "msg": "Destination /etc/xxx is not writable"}become: true 或 become 用户权限不足
Ansible received a broken pipe长任务中途 SSH 断了。开 SSH keepaliveansible.cfgssh_args = -o ServerAliveInterval=30)或改 async / poll
ERROR! conflicting action statements同一个 task 里写了两个模块名。一个 task 只能调用一个模块
handler 不执行handler 是”通知触发”——必须有 task changed=truenotify: 才会跑;且整个 play 结束前只执行一次
FAILED – RETRYING (until/retry 超时)用了 retries + until,条件始终不满足。把 register 的结果 debug 出来看真实返回

7.3 一条命令:用最短路径复现环境

出问题时,先从最短链路逐步放大:

# 1. SSH 本身通吗?
ssh -o PreferredAuthentications=publickey deploy@192.168.1.10 echo OK

# 2. Python 能跑吗?
ssh deploy@192.168.1.10 python3 --version

# 3. ansible ad-hoc 单模块
ansible web01 -i hosts -m ping -vvv

# 4. playbook check mode
ansible-playbook -i hosts nginx.yml -l web01 -C -D -vvv

7.4 性能慢怎么办

  • 开启 SSH 长连接(ControlMaster):在 ansible.cfg
    [ssh_connection]
    ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ServerAliveInterval=30
  • gather_facts: false:不需要 Facts 就关掉
  • strategy: free:主机间不再互相等步骤
  • --forks 20:加大并行度(默认 5)
  • ansible.posix.firewalld / 原生模块,别写一堆 shell

八、进阶学习方向

  1. Ansible Collectionsansible-galaxy collection install community.general community.mysql,现代版本几乎所有非核心模块都在 Collections 里。
  2. Molecule:给 Role 写测试(默认用 Docker/Driver + Ansible Verifier)。
  3. AWX / Ansible Tower / Semaphore:把 Playbook 放到 Web 上定时跑、接审批、审计日志、RBAC。
  4. Ansible Pull:反过来——节点自己定时 ansible-pull 拉 Git 上的 Playbook 本地执行,更适合几千台规模。
  5. Filter & Lookup:Jinja2 filters(selectattrmapcombineregex_replace)是写 Playbook 的瑞士军刀。

参考资料

问问 AI