安装与快速上手
安装
Ansible 只需要装在控制节点(你日常操作的那台 macOS / Linux)上,受管的 Ubuntu 服务器什么都不用装。
先分清两个包的关系:
| 包名 | 内容 |
|---|---|
ansible-core | Ansible 核心引擎 + ansible.builtin.* 内置模块,体积小、发布节奏快 |
ansible | ansible-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 按以下优先级查找配置文件,找到第一个就停:
- 环境变量
ANSIBLE_CONFIG指向的文件 - 当前目录下的
./ansible.cfg(最常用的方式,配置跟着项目走) - 用户目录
~/.ansible.cfg - 全局
/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 的更多写法了。