Skip to content

基础概念

什么是Ansible?

答:Ansible 是一个开源的自动化配置管理工具,由 Michael DeHaan 创建。它基于 Python 开发,使用 SSH 协议与远程主机通信,无需在目标机器上安装客户端(agentless)。Ansible 主要用于应用部署、配置管理和任务编排。

Ansible 的核心组件有哪些?

  1. Inventory(清单):定义被管理主机的列表
  2. Modules(模块):执行具体任务的代码单元
  3. Plugins(插件):扩展核心功能的代码
  4. Playbooks(剧本):YAML 格式的配置文件,定义任务序列
  5. Roles(角色):组织 Playbook 的结构化方式

Ansible 的工作原理是什么?

答:Ansible 采用 Push 模式工作:

  1. 控制节点读取 Inventory 和 Playbook
  2. 通过 SSH 连接到远程主机
  3. 将模块代码推送到远程主机执行
  4. 收集执行结果并返回给控制节点

Ansible 与其他自动化工具(SaltStack、Puppet、Chef)的区别是什么?

特性AnsibleSaltStackPuppetChef
架构AgentlessAgent/AgentlessAgentAgent
语言YAMLYAML/SaltDSL (Puppet)Ruby
学习难度
通信方式SSHZeroMQ/SSHXMLRPCChef Server
适用规模中小型大型大型大型

安装与配置

如何安装 Ansible?

bash
# CentOS/RHEL
yum install -y epel-release
yum install -y ansible

# Ubuntu/Debian
apt update
apt install -y ansible

# 使用 pip 安装
pip install ansible

Ansible 的主要配置文件有哪些?

  1. ansible.cfg:主配置文件,搜索顺序为:

    • 当前目录下的 ansible.cfg
    • ~/.ansible.cfg
    • /etc/ansible/ansible.cfg
  2. hosts/Inventory:主机清单文件,默认路径 /etc/ansible/hosts

  3. 常用配置项

ini
[defaults]
inventory = ./inventory
remote_user = root
private_key_file = ~/.ssh/id_rsa
host_key_checking = False
timeout = 30
forks = 5

如何配置 SSH 免密登录?

bash
# 生成密钥对
ssh-keygen -t rsa -b 4096

# 复制公钥到远程主机
ssh-copy-id user@remote_host

# 或使用 ansible 自带模块
ssh-keyscan remote_host >> ~/.ssh/known_hosts

Inventory 清单

什么是 Inventory?如何定义?

答:Inventory 是 Ansible 管理的主机列表,支持多种格式:

INI 格式

ini
[webservers]
web1.example.com
web2.example.com
web[01:10].example.com

[dbservers]
db1.example.com
db2.example.com

[all:vars]
ansible_user=root
ansible_ssh_pass=your_password

YAML 格式

yaml
all:
  vars:
    ansible_user: root
  children:
    webservers:
      hosts:
        web1.example.com:
        web2.example.com:
    dbservers:
      hosts:
        db1.example.com:
        db2.example.com:

动态 Inventory 是什么?如何使用?

答:动态 Inventory 通过外部脚本动态获取主机列表,适用于云环境:

bash
# 使用 AWS EC2 动态 Inventory
./aws_ec2.yml --list

# 在 ansible.cfg 中指定
[inventory]
enable_plugins = aws_ec2, host_list, script

主机变量和组变量如何使用?

bash
# 目录结构
inventory/
├── group_vars/
   ├── all.yml          # 所有组通用变量
   └── webservers.yml   # webservers 组变量
├── host_vars/
   └── web1.yml         # 单个主机变量
└── hosts                # 主机清单文件

Playbook 剧本

什么是 Playbook?基本结构是什么?

答:Playbook 是 Ansible 的任务编排文件,使用 YAML 格式编写:

yaml
---
- name: 安装和配置 Nginx
  hosts: webservers
  become: yes
  vars:
    nginx_port: 80
  tasks:
    - name: 安装 Nginx
      yum:
        name: nginx
        state: present
    
    - name: 启动 Nginx 服务
      service:
        name: nginx
        state: started
        enabled: yes

Playbook 中的常用关键字有哪些?

关键字说明
name任务名称描述
hosts目标主机或主机组
become是否提权执行(sudo)
vars定义变量
tasks任务列表
handlers触发器,特定条件触发
pre_tasks在 tasks 之前执行的任务
post_tasks在 tasks 之后执行的任务

Handlers 是什么?如何使用?

答:Handlers 是特殊的任务,只有在被通知时才会执行,常用于服务重启等操作:

yaml
---
- name: 配置 Nginx
  hosts: webservers
  tasks:
    - name: 更新 Nginx 配置
      template:
        src: nginx.conf.j2
        dest: /etc/nginx/nginx.conf
      notify: 重启 Nginx
  
  handlers:
    - name: 重启 Nginx
      service:
        name: nginx
        state: restarted

常用模块

列举 Ansible 常用的模块及其用途

文件类模块

模块用途
copy复制文件到远程主机
template使用 Jinja2 模板渲染后复制
file设置文件属性(权限、所有者等)
fetch从远程主机拉取文件
lineinfile确保文件中存在某一行
blockinfile插入/更新/删除文本块

包管理模块

模块用途
yumRedHat 系包管理
aptDebian 系包管理
pipPython 包管理
gemRuby gem 管理

服务模块

模块用途
service管理系统服务
systemd管理 systemd 服务
supervisorctl管理 supervisor 进程

系统信息模块

模块用途
setup收集系统事实信息
ping测试连通性
command执行命令(不经过 shell)
shell执行命令(经过 shell)
script执行本地脚本

copy 和 template 模块有什么区别?

特性copytemplate
功能直接复制文件渲染模板后复制
变量支持不支持支持 Jinja2 模板语法
适用场景静态文件配置文件(含变量)
示例src: file.confsrc: file.conf.j2

command、shell、raw 模块有什么区别?

模块特点是否需要 Python
command不经过 shell,不支持管道、重定向需要
shell经过 shell,支持管道、重定向需要
raw通过 SSH 直接执行,不依赖 Python不需要
yaml
# command - 推荐,更安全
- name: 查看磁盘空间
  command: df -h

# shell - 需要使用 shell 特性时
- name: 统计日志行数
  shell: wc -l /var/log/syslog | awk '{print $1}'

# raw - 目标主机无 Python 时
- name: 安装 Python
  raw: yum install -y python3

Roles 角色

什么是 Role?它的目录结构是什么?

答:Role 是组织和复用 Playbook 的结构化方式:

roles/
└── nginx/
    ├── defaults/        # 默认变量(优先级最低)
    │   └── main.yml
    ├── files/           # 静态文件
    │   └── nginx.conf
    ├── handlers/        # handlers
    │   └── main.yml
    ├── meta/            # 元数据、依赖
    │   └── main.yml
    ├── tasks/           # 任务列表
    │   └── main.yml
    ├── templates/       # Jinja2 模板
    │   └── nginx.conf.j2
    ├── tests/           # 测试
    │   └── test.yml
    └── vars/            # 变量
        └── main.yml

如何创建和使用 Role?

bash
# 自动生成 role 目录结构
ansible-galaxy init myrole
yaml
# playbook 中使用 role
---
- name: 部署 Web 应用
  hosts: webservers
  roles:
    - common
    - { role: nginx, port: 80 }
    - { role: mysql, when: "ansible_distribution == 'CentOS'" }
    - role: custom_role
      vars:
        custom_var: value

ansible-galaxy 是什么?如何使用?

答:ansible-galaxy 是 Ansible 官方的角色分享平台:

bash
# 搜索角色
ansible-galaxy search nginx

# 下载角色
ansible-galaxy install geerlingguy.nginx

# 创建角色
ansible-galaxy init myrole

# 从 requirements.yml 安装
ansible-galaxy install -r requirements.yml

变量与条件判断

Ansible 变量的优先级顺序是怎样的?

从高到低:

  1. -e 命令行指定的变量
  2. register 注册的变量
  3. set_fact 定义的变量
  4. role defaultsinclude_vars
  5. Play 中的 varsvars_files
  6. Host vars / Group vars
  7. Inventory 中的变量
  8. Role defaults(默认值)

如何在 Playbook 中使用条件判断?

yaml
tasks:
  - name: 仅在 CentOS 上安装 httpd
    yum:
      name: httpd
      state: present
    when: ansible_distribution == "CentOS"

  - name: 当变量存在时执行
    debug:
      msg: "{{ my_var }}"
    when: my_var is defined

  - name: 多条件判断
    yum:
      name: nginx
      state: present
    when:
      - ansible_os_family == "RedHat"
      - ansible_distribution_major_version|int >= 7

循环语句如何使用?

yaml
# 简单列表循环
- name: 安装多个软件包
  yum:
    name: "{{ item }}"
    state: present
  loop:
    - nginx
    - mysql
    - python3

# 字典循环
- name: 创建多个用户
  user:
    name: "{{ item.name }}"
    groups: "{{ item.groups }}"
  loop:
    - { name: alice, groups: wheel }
    - { name: bob, groups: docker }

# with_items(旧写法)
- name: 循环示例
  debug:
    msg: "{{ item }}"
  with_items:
    - a
    - b
    - c

进阶特性

Ansible Vault 是什么?如何加密敏感数据?

答:Ansible Vault 用于加密敏感信息(密码、密钥等):

bash
# 创建加密文件
ansible-vault create secrets.yml

# 编辑加密文件
ansible-vault edit secrets.yml

# 加密已有文件
ansible-vault encrypt secrets.yml

# 解密文件
ansible-vault decrypt secrets.yml

# 更改密码
ansible-vault rekey secrets.yml

# 查看加密内容
ansible-vault view secrets.yml
bash
# 执行时提供密码
ansible-playbook playbook.yml --ask-vault-pass
# 或使用密码文件
ansible-playbook playbook.yml --vault-password-file=vault_pass.txt

Ansible 的幂等性是如何实现的?

答:幂等性是指多次执行相同操作结果一致:

  1. 大多数模块内置幂等性检查
  2. 模块执行前会检查当前状态
  3. 只有状态不符合预期时才执行变更
  4. 返回 changed 状态标识是否发生变更
yaml
# 幂等示例 - 只在不存在时安装
- name: 确保 Nginx 已安装
  yum:
    name: nginx
    state: present  # 不是 latest,保证幂等性

如何进行错误处理?

yaml
tasks:
  - name: 可能失败的任务
    command: /bin/false
    ignore_errors: yes  # 忽略错误继续执行
    register: result

  - name: 根据上一步结果处理
    debug:
      msg: "上一步失败了"
    when: result is failed

  - name: 强制执行失败处理程序
    block:
      - name: 正常任务
        command: echo "正常"
    rescue:
      - name: 错误处理
        command: echo "出错了"
    always:
      - name: 无论成功失败都执行
        command: echo "清理工作"

如何优化 Ansible 执行性能?

  1. 开启 SSH pipelining
ini
[ssh_connection]
pipelining = True
  1. 调整并发数
bash
# 增加 forks 数量
ansible-playbook playbook.yml -f 20
  1. 使用策略插件
yaml
- hosts: all
  strategy: free  # 并行执行,不等待每个 host 完成
  tasks:
    ...
  1. 关闭 facts 收集(不需要时)
yaml
- hosts: all
  gather_facts: no
  tasks:
    ...
  1. 使用异步执行
yaml
- name: 耗时较长的任务
  command: /long_running_task
  async: 3600
  poll: 0
  register: long_task

常见问题排查

Ansible 连接超时怎么办?

  1. 检查 SSH 配置和网络连通性
  2. 增加 timeout 时间
  3. 检查防火墙规则
  4. 验证主机名解析是否正确

如何调试 Playbook?

bash
# 详细输出模式
ansible-playbook playbook.yml -v

# 更详细的输出
ansible-playbook playbook.yml -vvv

# 只执行特定任务
ansible-playbook playbook.yml --tags "install"

# 跳过某些任务
ansible-playbook playbook.yml --skip-tags "cleanup"

# 干跑模式(不实际执行)
ansible-playbook playbook.yml --check

# 显示主机差异
ansible-playbook playbook.yml --diff

常见报错及解决方案

报错信息原因解决方案
Permission denied权限不足使用 become: yes
module not found缺少 Python 依赖安装所需库
unreachable网络不通检查 SSH 和网络
variable undefined变量未定义定义变量或设置默认值