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 按以下优先级查找配置文件:

  1. ANSIBLE_CONFIG 环境变量指定的文件
  2. 当前目录下的 ansible.cfg
  3. 用户主目录下的 ~/.ansible.cfg
  4. 系统配置文件 /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 练习题

基础练习

  1. 安装配置

    • 在你的系统上安装 Ansible
    • 创建基本的 ansible.cfg 配置文件
    • 配置 SSH 密钥认证
  2. Inventory 管理

    • 创建包含多个主机组的 Inventory
    • 使用 YAML 格式重写 INI 格式的 Inventory
    • 编写简单的动态 Inventory 脚本

进阶练习

  1. 环境配置

    • 配置生产和测试两套环境
    • 实现环境间的配置隔离
    • 编写环境切换脚本
  2. 性能优化

    • 优化 Ansible 配置以提高执行速度
    • 配置事实缓存
    • 测试不同并发数的性能差异

实战练习

  1. 安全加固

    • 配置专用的 Ansible 用户
    • 实现基于密钥的认证
    • 配置防火墙规则限制 SSH 访问
  2. 故障排除

    • 模拟常见的连接问题并解决
    • 分析 Ansible 日志文件
    • 使用调试模式排查问题

下一章第3章:基本概念与术语

返回目录Ansible 自动化运维教程