2.1 系统要求
2.1.1 控制节点要求
操作系统支持: - Red Hat Enterprise Linux 7+ - CentOS 7+ - Ubuntu 16.04+ - Debian 9+ - macOS 10.12+ - Windows(通过 WSL)
软件要求:
# Python 版本要求
Python 2.7 或 Python 3.5+
# 检查 Python 版本
python3 --version
python3 -c "import sys; print(sys.version)"
# 必需的 Python 包
pip3 install --upgrade pip
pip3 install setuptools
硬件要求: - CPU:1 核心(推荐 2 核心+) - 内存:512MB(推荐 2GB+) - 磁盘:1GB 可用空间 - 网络:能够访问被管理节点
2.1.2 被管理节点要求
操作系统支持: - 几乎所有类 Unix 系统 - Windows(通过 WinRM) - 网络设备(支持 SSH)
软件要求:
# SSH 服务
sudo systemctl status ssh
sudo systemctl enable ssh
sudo systemctl start ssh
# Python 解释器
python3 --version
# 或者
python2 --version
# sudo 权限(可选)
sudo -l
2.2 安装 Ansible
2.2.1 使用包管理器安装
Ubuntu/Debian 系统
# 更新包索引
sudo apt update
# 安装软件属性通用包
sudo apt install software-properties-common
# 添加 Ansible PPA
sudo add-apt-repository --yes --update ppa:ansible/ansible
# 安装 Ansible
sudo apt install ansible
# 验证安装
ansible --version
CentOS/RHEL 系统
# 安装 EPEL 仓库
sudo yum install epel-release
# 或者在 CentOS 8/RHEL 8 上
sudo dnf install epel-release
# 安装 Ansible
sudo yum install ansible
# 或者
sudo dnf install ansible
# 验证安装
ansible --version
Fedora 系统
# 安装 Ansible
sudo dnf install ansible
# 验证安装
ansible --version
macOS 系统
# 使用 Homebrew
brew install ansible
# 使用 MacPorts
sudo port install py38-ansible
# 验证安装
ansible --version
2.2.2 使用 pip 安装
# 安装最新版本
pip3 install ansible
# 安装指定版本
pip3 install ansible==4.10.0
# 升级 Ansible
pip3 install --upgrade ansible
# 安装到用户目录
pip3 install --user ansible
# 验证安装
ansible --version
which ansible
2.2.3 从源码安装
# 克隆源码
git clone https://github.com/ansible/ansible.git
cd ansible
# 切换到稳定分支
git checkout stable-2.12
# 设置环境
source ./hacking/env-setup
# 安装依赖
pip3 install -r requirements.txt
# 验证安装
ansible --version
2.2.4 Docker 方式运行
# 拉取 Ansible 镜像
docker pull ansible/ansible:latest
# 运行 Ansible 容器
docker run -it --rm \
-v $(pwd):/ansible \
-v ~/.ssh:/root/.ssh:ro \
ansible/ansible:latest
# 在容器中验证
ansible --version
2.3 配置 Ansible
2.3.1 配置文件优先级
Ansible 按以下优先级查找配置文件:
ANSIBLE_CONFIG
环境变量指定的文件- 当前目录下的
ansible.cfg
- 用户主目录下的
~/.ansible.cfg
- 系统配置文件
/etc/ansible/ansible.cfg
# 查看当前配置文件
ansible-config view
# 查看所有配置选项
ansible-config list
# 查看配置文件位置
ansible-config dump --only-changed
2.3.2 创建配置文件
# ansible.cfg
[defaults]
# 主机清单文件位置
inventory = ./inventory/hosts
# 远程用户
remote_user = ansible
# SSH 私钥文件
private_key_file = ~/.ssh/ansible_rsa
# 禁用主机密钥检查
host_key_checking = False
# 启用 SSH 管道
pipelining = True
# 并发连接数
forks = 20
# 超时设置
timeout = 30
# 日志文件
log_path = ./ansible.log
# 角色路径
roles_path = ./roles
# 事实缓存
gathering = smart
fact_caching = memory
fact_caching_timeout = 86400
# 重试文件
retry_files_enabled = False
[inventory]
# 启用插件
enable_plugins = host_list, script, auto, yaml, ini, toml
[privilege_escalation]
# 默认使用 sudo
become = True
become_method = sudo
become_user = root
become_ask_pass = False
[paramiko_connection]
# Paramiko 连接设置
record_host_keys = False
[ssh_connection]
# SSH 连接设置
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
control_path_dir = ~/.ansible/cp
control_path = %(directory)s/%%h-%%p-%%r
2.3.3 环境变量配置
# 设置 Ansible 环境变量
export ANSIBLE_CONFIG=./ansible.cfg
export ANSIBLE_INVENTORY=./inventory/hosts
export ANSIBLE_REMOTE_USER=ansible
export ANSIBLE_PRIVATE_KEY_FILE=~/.ssh/ansible_rsa
export ANSIBLE_HOST_KEY_CHECKING=False
export ANSIBLE_LOG_PATH=./ansible.log
# 保存到 .bashrc 或 .zshrc
echo 'export ANSIBLE_HOST_KEY_CHECKING=False' >> ~/.bashrc
source ~/.bashrc
2.4 SSH 密钥配置
2.4.1 生成 SSH 密钥对
# 生成 SSH 密钥对
ssh-keygen -t rsa -b 4096 -C "ansible@example.com" -f ~/.ssh/ansible_rsa
# 设置正确的权限
chmod 600 ~/.ssh/ansible_rsa
chmod 644 ~/.ssh/ansible_rsa.pub
# 查看公钥
cat ~/.ssh/ansible_rsa.pub
2.4.2 分发公钥到目标主机
# 使用 ssh-copy-id
ssh-copy-id -i ~/.ssh/ansible_rsa.pub user@target-host
# 手动复制(如果 ssh-copy-id 不可用)
cat ~/.ssh/ansible_rsa.pub | ssh user@target-host "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
# 批量分发脚本
#!/bin/bash
HOSTS=("web1.example.com" "web2.example.com" "db1.example.com")
for host in "${HOSTS[@]}"; do
echo "Copying key to $host"
ssh-copy-id -i ~/.ssh/ansible_rsa.pub ansible@$host
done
2.4.3 测试 SSH 连接
# 测试 SSH 连接
ssh -i ~/.ssh/ansible_rsa ansible@target-host
# 测试无密码连接
ssh -i ~/.ssh/ansible_rsa -o PasswordAuthentication=no ansible@target-host
# 配置 SSH 客户端
# ~/.ssh/config
Host *.example.com
User ansible
IdentityFile ~/.ssh/ansible_rsa
StrictHostKeyChecking no
UserKnownHostsFile /dev/null
2.5 创建 Inventory
2.5.1 INI 格式 Inventory
# inventory/hosts
[webservers]
web1.example.com ansible_host=192.168.1.10
web2.example.com ansible_host=192.168.1.11
web3.example.com ansible_host=192.168.1.12
[databases]
db1.example.com ansible_host=192.168.1.20 ansible_port=22
db2.example.com ansible_host=192.168.1.21 ansible_port=2222
[loadbalancers]
lb1.example.com ansible_host=192.168.1.30
[production:children]
webservers
databases
loadbalancers
[production:vars]
ansible_user=ansible
ansible_ssh_private_key_file=~/.ssh/ansible_rsa
ansible_python_interpreter=/usr/bin/python3
2.5.2 YAML 格式 Inventory
# inventory/hosts.yml
all:
children:
production:
children:
webservers:
hosts:
web1.example.com:
ansible_host: 192.168.1.10
web2.example.com:
ansible_host: 192.168.1.11
web3.example.com:
ansible_host: 192.168.1.12
databases:
hosts:
db1.example.com:
ansible_host: 192.168.1.20
ansible_port: 22
db2.example.com:
ansible_host: 192.168.1.21
ansible_port: 2222
loadbalancers:
hosts:
lb1.example.com:
ansible_host: 192.168.1.30
vars:
ansible_user: ansible
ansible_ssh_private_key_file: ~/.ssh/ansible_rsa
ansible_python_interpreter: /usr/bin/python3
2.5.3 动态 Inventory
#!/usr/bin/env python3
# inventory/dynamic_inventory.py
import json
import sys
def get_inventory():
inventory = {
'webservers': {
'hosts': ['web1.example.com', 'web2.example.com'],
'vars': {
'ansible_user': 'ansible',
'http_port': 80
}
},
'databases': {
'hosts': ['db1.example.com'],
'vars': {
'ansible_user': 'ansible',
'mysql_port': 3306
}
},
'_meta': {
'hostvars': {
'web1.example.com': {
'ansible_host': '192.168.1.10'
},
'web2.example.com': {
'ansible_host': '192.168.1.11'
},
'db1.example.com': {
'ansible_host': '192.168.1.20'
}
}
}
}
return inventory
if __name__ == '__main__':
if len(sys.argv) == 2 and sys.argv[1] == '--list':
print(json.dumps(get_inventory(), indent=2))
elif len(sys.argv) == 3 and sys.argv[1] == '--host':
print(json.dumps({}, indent=2))
else:
print("Usage: %s --list or %s --host <hostname>" % (sys.argv[0], sys.argv[0]))
# 使用动态 Inventory
chmod +x inventory/dynamic_inventory.py
ansible-inventory -i inventory/dynamic_inventory.py --list
2.6 验证安装
2.6.1 基本验证
# 检查 Ansible 版本
ansible --version
# 检查配置
ansible-config view
# 列出所有主机
ansible-inventory --list
# 检查主机连通性
ansible all -m ping
# 检查特定组
ansible webservers -m ping
2.6.2 连接测试
# 测试 SSH 连接
ansible all -m setup --limit web1.example.com
# 执行简单命令
ansible all -a "uptime"
ansible all -a "df -h"
ansible all -a "free -m"
# 使用不同的连接方式
ansible all -m ping --connection=ssh
ansible all -m ping --connection=paramiko
2.6.3 权限测试
# 测试 sudo 权限
ansible all -a "sudo whoami" --become
# 测试文件操作权限
ansible all -m file -a "path=/tmp/ansible-test state=touch" --become
# 清理测试文件
ansible all -m file -a "path=/tmp/ansible-test state=absent" --become
2.7 故障排除
2.7.1 常见问题
问题 1:SSH 连接失败
# 错误信息
"msg": "Failed to connect to the host via ssh"
# 解决方案
# 1. 检查 SSH 服务
sudo systemctl status ssh
# 2. 检查防火墙
sudo ufw status
sudo firewall-cmd --list-all
# 3. 检查 SSH 密钥
ssh -i ~/.ssh/ansible_rsa ansible@target-host
# 4. 启用详细输出
ansible all -m ping -vvv
问题 2:权限不足
# 错误信息
"msg": "Missing sudo password"
# 解决方案
# 1. 配置无密码 sudo
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible
# 2. 或者提供密码
ansible all -m ping --become --ask-become-pass
# 3. 或者在 inventory 中配置
ansible_become_pass=password
问题 3:Python 解释器问题
# 错误信息
"msg": "/usr/bin/python: not found"
# 解决方案
# 在 inventory 中指定 Python 解释器
ansible_python_interpreter=/usr/bin/python3
# 或者安装 Python
sudo apt install python3
sudo ln -s /usr/bin/python3 /usr/bin/python
2.7.2 调试技巧
# 启用详细输出
ansible all -m ping -v # 基本详细信息
ansible all -m ping -vv # 更多详细信息
ansible all -m ping -vvv # 最详细信息
ansible all -m ping -vvvv # 包括 SSH 调试信息
# 检查连接
ansible all -m setup --tree /tmp/facts
# 语法检查
ansible-playbook --syntax-check playbook.yml
# 干运行
ansible-playbook --check playbook.yml
# 逐步执行
ansible-playbook --step playbook.yml
2.7.3 日志分析
# 启用日志记录
# 在 ansible.cfg 中设置
log_path = /var/log/ansible.log
# 或者使用环境变量
export ANSIBLE_LOG_PATH=/var/log/ansible.log
# 实时查看日志
tail -f /var/log/ansible.log
# 分析日志
grep ERROR /var/log/ansible.log
grep FAILED /var/log/ansible.log
2.8 性能优化
2.8.1 连接优化
# ansible.cfg
[defaults]
# 增加并发数
forks = 50
# 启用 SSH 管道
pipelining = True
# 启用 SSH 连接复用
[ssh_connection]
ssh_args = -C -o ControlMaster=auto -o ControlPersist=60s
control_path = ~/.ansible/cp/%%h-%%p-%%r
2.8.2 事实收集优化
# ansible.cfg
[defaults]
# 智能事实收集
gathering = smart
# 事实缓存
fact_caching = memory
fact_caching_timeout = 86400
# 或者使用 Redis 缓存
fact_caching = redis
fact_caching_timeout = 86400
fact_caching_connection = localhost:6379:0
2.8.3 Playbook 优化
# 禁用事实收集(如果不需要)
- hosts: all
gather_facts: no
tasks:
- name: 简单任务
command: echo "Hello World"
# 异步执行长时间任务
- name: 长时间运行的任务
command: /usr/bin/long-running-command
async: 3600
poll: 0
register: long_task
# 检查异步任务状态
- name: 检查任务状态
async_status:
jid: "{{ long_task.ansible_job_id }}"
register: job_result
until: job_result.finished
retries: 30
delay: 60
2.9 安全配置
2.9.1 SSH 安全
# SSH 服务器配置 /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
ClientAliveInterval 300
ClientAliveCountMax 2
# 重启 SSH 服务
sudo systemctl restart ssh
2.9.2 用户权限
# 创建专用的 Ansible 用户
sudo useradd -m -s /bin/bash ansible
# 配置 sudo 权限
echo "ansible ALL=(ALL) NOPASSWD:ALL" | sudo tee /etc/sudoers.d/ansible
# 设置 SSH 密钥
sudo -u ansible mkdir -p /home/ansible/.ssh
sudo -u ansible chmod 700 /home/ansible/.ssh
sudo cp ~/.ssh/authorized_keys /home/ansible/.ssh/
sudo chown ansible:ansible /home/ansible/.ssh/authorized_keys
sudo chmod 600 /home/ansible/.ssh/authorized_keys
2.9.3 网络安全
# 防火墙配置(仅允许必要的端口)
# UFW (Ubuntu)
sudo ufw allow from 192.168.1.0/24 to any port 22
sudo ufw enable
# firewalld (CentOS/RHEL)
sudo firewall-cmd --permanent --add-rich-rule="rule family='ipv4' source address='192.168.1.0/24' port protocol='tcp' port='22' accept"
sudo firewall-cmd --reload
# iptables
sudo iptables -A INPUT -s 192.168.1.0/24 -p tcp --dport 22 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 22 -j DROP
2.10 多环境配置
2.10.1 目录结构
ansible-project/
├── inventories/
│ ├── production/
│ │ ├── hosts
│ │ ├── group_vars/
│ │ │ ├── all.yml
│ │ │ ├── webservers.yml
│ │ │ └── databases.yml
│ │ └── host_vars/
│ │ ├── web1.example.com.yml
│ │ └── db1.example.com.yml
│ ├── staging/
│ │ ├── hosts
│ │ └── group_vars/
│ └── development/
│ ├── hosts
│ └── group_vars/
├── playbooks/
├── roles/
├── ansible.cfg
└── requirements.yml
2.10.2 环境特定配置
# inventories/production/group_vars/all.yml
---
environment: production
app_version: "1.2.3"
db_host: db.prod.example.com
redis_host: redis.prod.example.com
# inventories/staging/group_vars/all.yml
---
environment: staging
app_version: "1.3.0-beta"
db_host: db.staging.example.com
redis_host: redis.staging.example.com
2.10.3 环境切换
# 使用不同环境
ansible-playbook -i inventories/production/hosts playbook.yml
ansible-playbook -i inventories/staging/hosts playbook.yml
ansible-playbook -i inventories/development/hosts playbook.yml
# 创建环境切换脚本
#!/bin/bash
# switch-env.sh
ENV=${1:-development}
export ANSIBLE_INVENTORY="inventories/$ENV/hosts"
echo "Switched to $ENV environment"
ansible-inventory --list
2.11 本章总结
本章详细介绍了 Ansible 的安装和环境配置,主要内容包括:
- 系统要求:控制节点和被管理节点的软硬件要求
- 安装方法:包管理器、pip、源码、Docker 等多种安装方式
- 配置文件:ansible.cfg 的配置选项和优先级
- SSH 配置:密钥生成、分发和连接测试
- Inventory 创建:INI、YAML、动态等格式
- 故障排除:常见问题的诊断和解决方法
- 性能优化:连接、缓存和执行优化
- 安全配置:SSH、用户权限和网络安全
- 多环境管理:生产、测试、开发环境的配置
2.12 练习题
基础练习
安装配置
- 在你的系统上安装 Ansible
- 创建基本的 ansible.cfg 配置文件
- 配置 SSH 密钥认证
Inventory 管理
- 创建包含多个主机组的 Inventory
- 使用 YAML 格式重写 INI 格式的 Inventory
- 编写简单的动态 Inventory 脚本
进阶练习
环境配置
- 配置生产和测试两套环境
- 实现环境间的配置隔离
- 编写环境切换脚本
性能优化
- 优化 Ansible 配置以提高执行速度
- 配置事实缓存
- 测试不同并发数的性能差异
实战练习
安全加固
- 配置专用的 Ansible 用户
- 实现基于密钥的认证
- 配置防火墙规则限制 SSH 访问
故障排除
- 模拟常见的连接问题并解决
- 分析 Ansible 日志文件
- 使用调试模式排查问题
下一章:第3章:基本概念与术语
返回目录:Ansible 自动化运维教程