跳到主要内容

安装与快速上手

安装​

Ansible 只需要装在控制节点(你日常操作的那台 macOS / Linux)上,受管的 Ubuntu 服务器什么都不用装。

先分清两个包的关系:

包名内容
ansible-coreAnsible 核心引擎 + ansible.builtin.* 内置模块,体积小、发布节奏快
ansibleansible-core + 一大批社区 collection(云厂商、网络设备等各类模块),体积大、版本跟着 collection 走

日常服务器运维用 ansible 全家桶更省心;只想要核心、按需安装 collection 的话选 ansible-core。

用 pipx 安装(推荐)​

pipx 会给 ansible 一个独立的 Python 虚拟环境,不污染系统 Python,升级也方便:

# macOS / Linux 通用,先确保装了 pipx
pipx install ansible

# 之后升级
pipx upgrade ansible

也可以用 pip 直接装(会装进用户目录):

python3 -m pip install --user ansible

用系统包管理器安装​

# macOS
brew install ansible

# Ubuntu(官方 PPA,版本比自带源新)
sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install -y ansible

# RHEL / CentOS / Fedora
sudo dnf install -y ansible-core
提示

系统包里的 ansible 版本通常偏旧,想跟住新版本就用 pipx/pip。Ubuntu 自带源里的 ansible 是很老的版本,要么加官方 PPA,要么走 pipx。

验证安装​

ansible --version
ansible [core 2.17.5]
config file = None
configured module search path = ['/Users/liangyou/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /Users/liangyou/.local/pipx/venvs/ansible/lib/python3.12/site-packages/ansible
ansible collection location = /Users/liangyou/.ansible/collections:/usr/share/ansible/collections
executable location = /Users/liangyou/.local/bin/ansible
python version = 3.12.7 (main, Oct 1 2024, 02:05:46) [Clang 16.0.0 (clang-1600.0.26.3)]

输出里值得看的三行:

  • ansible [core 2.17.5]:core 版本号,2.16 / 2.17 都是当前主流。
  • config file = None:当前生效的配置文件,显示 None 说明还没配置,下文会解决。
  • python version:控制端使用的 Python 版本。

Python 版本要求(ansible-core 2.16 / 2.17 时代):

端要求
控制节点Python ≥ 3.10(macOS 用 brew/pipx 装会自动带合适的版本)
受管节点Python ≥ 3.6(2.17 起要求 ≥ 3.7);Ubuntu 22.04 自带 3.10,开箱满足

最小配置 ansible.cfg​

Ansible 按以下优先级查找配置文件,找到第一个就停:

  1. 环境变量 ANSIBLE_CONFIG 指向的文件
  2. 当前目录下的 ./ansible.cfg(最常用的方式,配置跟着项目走)
  3. 用户目录 ~/.ansible.cfg
  4. 全局 /etc/ansible/ansible.cfg
备注

推荐「每个项目目录放一份 ansible.cfg」,这样不同项目的 inventory、参数互不干扰,还能随项目一起进 git。

在项目根目录建一个最小可用的配置:

[defaults]
inventory = inventories/hosts.ini
host_key_checking = False
forks = 20

三个配置的含义:

  • inventory:默认主机清单路径,免得每条命令都加 -i。
  • host_key_checking = False:首次 SSH 连接不做交互式主机指纹确认。自动化场景下开着它命令会卡在 yes/no 上;代价是放弃了中间人攻击校验,公网环境建议先 ssh-keyscan 把指纹收进 known_hosts,再保持默认开启。
  • forks = 20:并发数,即同时和多少台机器维持 SSH 连接。默认 5 太保守,几十台机器时调到 20~50。

改完再验证一次,config file 这行应该指向你的 ansible.cfg:

ansible --version | grep 'config file'
  config file = /Users/liangyou/ansible-demo/ansible.cfg

第一条 ad-hoc 命令​

按上面配置的 inventory = inventories/hosts.ini,先建清单文件:

# inventories/hosts.ini
[local]
localhost ansible_connection=local

[web]
192.168.1.11
192.168.1.12

说明:

  • [web] 是组名,组里两台机器;ansible 命令的目标就是按组/主机/pattern 来选的。
  • localhost ansible_connection=local 表示本机不走 SSH,直接本地执行。
  • 远程机器默认用 SSH 密钥登录,用户名与当前用户一致;不一样的话在主机后加 ansible_user=ubuntu,或命令行加 -u ubuntu。

第一条命令——对所有机器执行 ping 模块(不是 ICMP ping,是验证「能连上、对端 Python 能用」):

ansible all -m ansible.builtin.ping
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.11 | SUCCESS => {
"changed": false,
"ping": "pong"
}
192.168.1.12 | SUCCESS => {
"changed": false,
"ping": "pong"
}

看到 pong 就说明控制链路和节点 Python 都正常。

再看一眼 facts——Ansible 自动采集的节点信息:

ansible localhost -m ansible.builtin.setup
localhost | SUCCESS => {
"ansible_facts": {
"ansible_distribution": "MacOSX",
"ansible_distribution_version": "15.1",
"ansible_fqdn": "MacBook-Pro.local",
"ansible_memtotal_mb": 32768,
"ansible_processor_vcpus": 12,
...
}
}

facts 内容很长,上面是截取的几行。这些变量(如 ansible_distribution、ansible_memtotal_mb)后面在 playbook 里可以直接引用,比如「按发行版选不同的包名」。

提示

只要 facts 里的个别字段,用 filter 收窄:ansible localhost -m ansible.builtin.setup -a "filter=ansible_distribution*"。

第一个 playbook​

写一个完整可跑的 playbook:给 web 组装 nginx、放一个首页、确保服务开机自启且正在运行。

新建 playbooks/nginx.yml:

---
- name: 部署 nginx 到 web 组
hosts: web
become: true

tasks:
- name: 安装 nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: true

- name: 拷贝首页
ansible.builtin.copy:
dest: /var/www/html/index.html
content: |
<h1>Hello from Ansible</h1>
<p>deployed on {{ inventory_hostname }}</p>
mode: '0644'

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

要点说明:

  • hosts: web:这个 play 作用于 inventory 里的 web 组。
  • become: true:到对端用 sudo 提权(装包、写 /var/www 需要 root)。
  • 三个 task 分别调用 apt / copy / service 模块,全部幂等,可以放心反复执行。
  • {{ inventory_hostname }} 是 Ansible 内置变量,渲染时会替换成每台机器在清单里的名字。

执行:

ansible-playbook playbooks/nginx.yml
PLAY [部署 nginx 到 web 组] **************************************************

TASK [Gathering Facts] *******************************************************
ok: [192.168.1.11]
ok: [192.168.1.12]

TASK [安装 nginx] ************************************************************
changed: [192.168.1.11]
changed: [192.168.1.12]

TASK [拷贝首页] **************************************************************
changed: [192.168.1.11]
changed: [192.168.1.12]

TASK [确保 nginx 已启动并开机自启] *******************************************
ok: [192.168.1.11]
ok: [192.168.1.12]

PLAY RECAP *******************************************************************
192.168.1.11 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
192.168.1.12 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

输出解读:

  • PLAY:一个 play 的开始,显示名字和目标主机组。
  • TASK:每个任务逐台执行并汇报结果。最前面的 Gathering Facts 是 Ansible 自动加的采集 facts 步骤(可用 gather_facts: false 关掉)。
  • PLAY RECAP:每台机器的汇总计数,含义如下:
计数含义
ok执行成功且状态没变(已达标,幂等跳过)
changed执行成功且做了修改
unreachable连不上(SSH 层问题)
failed任务执行失败
skipped按条件跳过(如 when: 不满足)

第二次再执行同一条命令,apt 和 copy 应该全部变成 ok、changed=0——这就是幂等的直观体现。

验证部署结果:

curl http://192.168.1.11
<h1>Hello from Ansible</h1>
<p>deployed on 192.168.1.11</p>

推荐目录结构(简单版)​

小项目按这个约定组织就够用了:

ansible-demo/
├── ansible.cfg # 项目级配置,指定 inventory 等
├── inventories/
│ └── hosts.ini # 主机清单(环境多了可拆 prod.ini / staging.ini)
└── playbooks/
└── nginx.yml # 剧本都放这里

要点:

  • ansible.cfg 放项目根目录,所有命令都在项目根下执行,配置自动生效。
  • inventory 和 playbook 分目录放,后续引入 role 时再加 roles/ 目录。
  • 整个目录进 git,配置即代码。

常见问题​

装完找不到 ansible 命令​

用 pip install --user 装的 ansible 在用户目录的 bin 下(Linux 是 ~/.local/bin,macOS 类似 ~/Library/Python/3.x/bin),这个目录经常不在 PATH 里。两种解法:

# 临时:直接用全路径确认
~/.local/bin/ansible --version

# 长期:把目录加进 PATH(写进 ~/.zshrc 或 ~/.bashrc)
export PATH="$HOME/.local/bin:$PATH"

用 pipx 装的可以执行一次 pipx ensurepath,它会帮你把 PATH 配好。

macOS 首次连接卡在主机指纹确认​

第一次 ssh 到新机器时,OpenSSH 会交互式询问 Are you sure you want to continue connecting (yes/no/[fingerprint])?,Ansible 批量执行时会因此挂起。处理方式:

# 方式一:提前把指纹收进 known_hosts(推荐,安全不打折)
ssh-keyscan 192.168.1.11 192.168.1.12 >> ~/.ssh/known_hosts

# 方式二:内网图省事,在 ansible.cfg 里关掉校验
# host_key_checking = False

Ubuntu 受管端缺 python3 报错​

报错长这样:

192.168.1.11 | FAILED! => {
"changed": false,
"module_stderr": "Shared connection to 192.168.1.11 closed.\r\n",
"module_stdout": "/bin/sh: 1: /usr/bin/python3: not found\r\n",
"msg": "The module failed to execute correctly, you probably need to set the interpreter.\nSee stdout/stderr for the exact error"
}

原因是 Ansible 的模块需要在对端用 Python 执行,而这台机器没装 python3(最小化安装的 Ubuntu、部分云镜像会遇到)。处理:

# 单台:直接 ssh 上去装
ssh 192.168.1.11 'sudo apt-get update && sudo apt-get install -y python3'

机器多、不想逐台手工装时,可以用不依赖对端 Python 的 ansible.builtin.raw 模块来装:

ansible web -m ansible.builtin.raw -a "apt-get update && apt-get install -y python3" -b
注意

raw 模块不走 Python、不幂等,只用来解决「Python 还没装上」这个鸡生蛋问题,装完 python3 就回归正常模块。

小结​

  • 控制节点装 Ansible 推荐 pipx(版本新、环境干净);ansible 包 = ansible-core + 社区 collection。
  • 项目根目录放 ansible.cfg 管理配置,优先级:ANSIBLE_CONFIG > ./ansible.cfg > ~/.ansible.cfg > /etc/ansible/ansible.cfg。
  • ad-hoc 命令 ansible <目标> -m <模块> 适合一次性操作;正式运维写成 playbook,幂等、可重复执行、可进 git。
  • 输出看 PLAY RECAP:ok 是已达标,changed 是做了修改,failed 和 unreachable 是要处理的。
  • 常见坑就三个:PATH 里没有 ansible、首次 SSH 指纹确认卡住、受管端缺 python3。

环境跑通之后,后面就可以深入 inventory 的分组与变量、以及 playbook 的更多写法了。