Ansible: 自动化运维的利器

导言

在当今复杂的 IT 环境中,手动管理和配置服务器既耗时又容易出错。自动化运维工具应运而生,旨在解决这一挑战。Ansible 就是其中最受欢迎的工具之一。它是一个开源的自动化平台,可以帮助您轻松实现配置管理、应用部署、任务自动化等。

本文将带您深入了解 Ansible,从其工作原理、优缺点,到详细的部署步骤和实用教程,助您快速上手并精通这款强大的工具。

Ansible 是什么?

Ansible 是一个极其简单的 IT 自动化引擎,可以自动化云供应、配置管理、应用部署、服务内编排和许多其他 IT 需求。它使用人类可读的 YAML 语言来描述自动化作业,使得即使非开发人员也能轻松理解和编写自动化任务。

为什么选择 Ansible?

  • 简单性: Ansible 使用 YAML,一种简洁的配置语言,非常易于学习和使用。
  • 无代理: Ansible 是无代理的,这意味着您无需在被管理的节点上安装任何客户端软件。它通过标准的 SSH 协议进行通信,大大简化了管理和维护工作。
  • 幂等性: Ansible 的操作是幂等的,这意味着多次执行同一个任务会得到相同的结果。这确保了系统状态的一致性,避免了意外的副作用。
  • 跨平台: Ansible 可以管理 Linux、Windows、网络设备等多种类型的节点。

Ansible 的工作原理

理解 Ansible 的核心概念是掌握它的关键。

  • 控制节点 (Control Node): 任何安装了 Ansible 的机器都可以作为控制节点。您可以从控制节点运行命令和 Playbook 来管理其他服务器。
  • 被管节点 (Managed Nodes): 您希望使用 Ansible 管理的服务器或设备。
  • Inventory (清单): 一个描述被管节点列表的文件。它可以是 INI 或 YAML 格式。您可以在清单中对节点进行分组,方便批量管理。
  • Playbooks (剧本): Ansible 的配置、部署和编排语言。它们是 YAML 格式的文本文件,用于描述您希望在被管节点上执行的一系列有序任务。
  • Modules (模块): Ansible 执行任务的单元。每个模块都有特定的功能,例如 yum 模块用于软件包管理,copy 模块用于文件复制。Ansible 拥有数千个内置模块,您也可以编写自己的自定义模块。
  • Plugins (插件): 插件是扩展 Ansible 核心功能的代码片段。例如,连接插件(如 SSH)、回调插件(用于自定义输出)等。

Ansible 的工作流程非常直观:

  1. Ansible 从控制节点读取您的 Playbook。
  2. 根据 Playbook 中定义的 hosts,Ansible 从 Inventory 文件中找到需要操作的目标主机。
  3. Ansible 通过 SSH 连接到这些目标主机。
  4. 在目标主机上,Ansible 执行 Playbook 中定义的各个任务(task)。每个任务会调用相应的模块。
  5. 执行完成后,Ansible 会收集结果并返回给控制节点。

Ansible 的优缺点

优点

  • 简单易学: 基于 YAML,语法简单,没有复杂的编程语言背景也能快速上手。
  • 无代理架构: 无需在客户端安装代理,降低了维护成本和安全风险。通过 SSH 实现通信,轻量且高效。
  • 幂等性 (Idempotency): 这是 Ansible 的核心特性之一。一个操作无论执行多少次,结果都是相同的。例如,一个确保某个软件包已安装的任务,如果软件包已存在,Ansible 不会做任何事情;如果不存在,则会安装它。这保证了配置的一致性。
  • 强大的社区和模块支持: Ansible 拥有一个庞大而活跃的社区,提供了数千个模块来管理各种系统和服务。无论是管理用户、安装软件、配置服务还是操作云平台,几乎总能找到现成的模块。
  • 可读性好: Playbook 使用 YAML 编写,结构清晰,易于阅读和理解,非常适合团队协作和代码审查。

缺点

  • 执行速度: 对于大规模的服务器集群(数千台),Ansible 基于 SSH 的推送模式可能会比基于代理的拉取模式(如 Puppet, Chef)慢一些。
  • 对 Windows 的支持: 虽然 Ansible 支持 Windows 管理,但它依赖于 PowerShell Remoting,配置相对比 Linux 的 SSH 要复杂一些。社区对 Windows 的支持也不如 Linux 完善。
  • YAML 的局限性: YAML 语法虽然简单,但在处理复杂逻辑(如复杂的条件判断和循环)时,会显得有些笨拙和受限。

详细部署步骤

下面我们将在一个典型的 Linux 环境(例如 CentOS/RHEL 或 Ubuntu)中部署 Ansible。

1. 环境准备

  • 一台控制节点: 用于安装 Ansible 和存放 Playbook。可以是您的笔记本电脑,也可以是一台专用的服务器。本教程假设使用 CentOS 8。
  • 一到多台被管节点: 您希望通过 Ansible 管理的服务器。本教程假设使用两台 CentOS 8 服务器。
  • 网络连通性: 确保控制节点可以访问所有被管节点(通常是通过 SSH 的 22 端口)。
  • 用户权限: 准备一个在所有节点上都存在的用户(例如 admin),并且该用户在被管节点上拥有 sudo 权限。

2. 在控制节点上安装 Ansible

对于 CentOS/RHEL 系统:

1
2
3
4
# 安装 EPEL 源
sudo yum install -y epel-release
# 安装 Ansible
sudo yum install -y ansible

对于 Ubuntu/Debian 系统:

1
2
3
4
5
6
7
8
# 更新 apt 软件包索引
sudo apt update
# 安装 software-properties-common
sudo apt install -y software-properties-common
# 添加 Ansible PPA
sudo add-apt-repository --yes --update ppa:ansible/ansible
# 安装 Ansible
sudo apt install -y ansible

安装完成后,验证安装:

1
ansible --version

您应该能看到 Ansible 的版本信息。

3. 配置 SSH 免密登录

为了让 Ansible 能够无需密码连接到被管节点,我们需要配置 SSH 密钥认证。

控制节点 上,使用您准备好的用户(例如 admin)执行以下操作:

1
2
3
4
5
6
7
# 如果还没有 SSH 密钥,生成一个新的
ssh-keygen -t rsa

# 将公钥复制到每个被管节点
# 假设被管节点 IP 分别为 192.168.1.11 和 192.168.1.12
ssh-copy-id [email protected]
ssh-copy-id [email protected]

根据提示输入被管节点用户的密码。完成后,尝试 SSH 登录,确认不再需要密码:

1
ssh [email protected]

4. 创建 Inventory 文件

Inventory 文件是 Ansible 的核心配置文件之一,它定义了您要管理的主机。默认的 Inventory 文件是 /etc/ansible/hosts。我们也可以在项目目录下创建自己的 Inventory 文件。

在您的项目目录下创建一个名为 inventory 的文件:

1
2
3
4
5
6
7
8
9
10
[webservers]
web1.example.com ansible_host=192.168.1.11
web2.example.com ansible_host=192.168.1.12

[dbservers]
db1.example.com ansible_host=192.168.1.21

[all:vars]
ansible_user=admin
ansible_ssh_private_key_file=~/.ssh/id_rsa
  • [webservers][dbservers] 是主机组,方便对一组主机进行操作。
  • web1.example.com 是主机的别名。
  • ansible_host 是主机的实际 IP 地址或域名。
  • [all:vars] 定义了适用于所有主机的通用变量,例如登录用户和 SSH 密钥路径。

5. 测试连接

现在,我们可以使用 Ansible 的 ping 模块来测试是否能成功连接到所有被管节点。

1
2
3
# -i 指定 inventory 文件路径
# all 是一个特殊的组,代表 inventory 中的所有主机
ansible all -i inventory -m ping

如果一切正常,您会看到类似以下的输出,每个主机的 ping 都返回了 pong

1
2
3
4
5
6
7
8
9
10
11
12
13
14
web1.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
web2.example.com | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}

至此,您的 Ansible 环境已经成功部署!


常用使用教程

Ad-Hoc 命令

Ad-Hoc 命令是简单、单行的 Ansible 命令,用于执行快速、一次性的任务,而无需编写完整的 Playbook。

语法: ansible <host-pattern> -i <inventory> -m <module> -a "<args>"

示例 1: 检查所有 web 服务器的磁盘空间

1
ansible webservers -i inventory -m shell -a "df -h"

示例 2: 在所有服务器上创建一个新目录

1
ansible all -i inventory -m file -a "path=/tmp/testdir state=directory"

示例 3: 将本地文件分发到所有 web 服务器

1
2
# -b 表示以 sudo 权限执行 (become)
ansible webservers -i inventory -m copy -a "src=/path/to/local/index.html dest=/var/www/html/index.html" -b

Playbook 教程

Playbook 是 Ansible 的真正强大之处。它们允许您定义复杂、可重复的自动化工作流。

示例:部署一个 Nginx Web 服务器

我们的目标是:在 webservers 组的所有主机上安装并启动 Nginx。

1. 创建 Playbook 文件

创建一个名为 deploy_nginx.yml 的文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
---
- name: Deploy and configure Nginx
hosts: webservers
become: yes
tasks:
- name: Install Nginx package
ansible.builtin.yum:
name: nginx
state: present

- name: Ensure Nginx service is started and enabled
ansible.builtin.service:
name: nginx
state: started
enabled: yes

- name: Copy custom index.html
ansible.builtin.copy:
src: ./files/index.html
dest: /usr/share/nginx/html/index.html
owner: root
group: root
mode: '0644'

2. Playbook 结构解释

  • ---: YAML 文件的开始标记。
  • - name: ...: Playbook 的描述,会显示在执行输出中。
  • hosts: webservers: 指定这个 Playbook 将在 inventory 文件中定义的 webservers 组上执行。
  • become: yes: 相当于在命令行中使用 -b,表示后续的任务需要提升权限(通常是 sudo)。
  • tasks:: 任务列表。
    • 每个任务都有一个 name,用于描述任务的目的。
    • 每个任务调用一个模块(例如 ansible.builtin.yum, ansible.builtin.service)。
    • 模块后面是传递给模块的参数(例如 name: nginx, state: present)。

3. 准备 index.html 文件

在 Playbook 所在的目录下,创建一个 files 目录,并在其中创建一个 index.html 文件:

1
2
mkdir files
echo "<h1>Welcome to Nginx, managed by Ansible!</h1>" > files/index.html

4. 运行 Playbook

1
2
# --ask-become-pass 会提示你输入 sudo 密码
ansible-playbook -i inventory deploy_nginx.yml --ask-become-pass

Ansible 将会执行 Playbook 中定义的任务。您会看到每个任务的执行状态(ok, changed, failed)。

执行成功后,在浏览器中访问 http://192.168.1.11http://192.168.1.12,您应该能看到我们自定义的欢迎页面。

使用变量和 Handler

为了让 Playbook 更灵活和强大,我们可以引入变量和 Handler。

重构 deploy_nginx.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
---
- name: Deploy and configure Nginx
hosts: webservers
become: yes
vars:
nginx_package_name: nginx
nginx_service_name: nginx
tasks:
- name: Install Nginx package
ansible.builtin.yum:
name: "{{ nginx_package_name }}"
state: present

- name: Copy Nginx configuration file
ansible.builtin.copy:
src: ./templates/nginx.conf.j2
dest: /etc/nginx/nginx.conf
owner: root
group: root
mode: '0644'
notify:
- Restart Nginx

- name: Ensure Nginx service is started and enabled
ansible.builtin.service:
name: "{{ nginx_service_name }}"
state: started
enabled: yes

handlers:
- name: Restart Nginx
ansible.builtin.service:
name: "{{ nginx_service_name }}"
state: restarted

新概念解释:

  • vars:: 定义了这个 Play 内部可用的变量。使用 {{ variable_name }} 来引用变量。
  • notify: Restart Nginx: 当 copy 任务发生变化时(即配置文件被更新),它会 “通知” 一个名为 Restart Nginx 的 handler。
  • handlers:: Handler 是一种特殊的任务,它只有在被 notify 通知时才会执行。这非常有用,例如,只有在配置文件更改后才需要重启服务。
  • templates/nginx.conf.j2: 这是一个 Jinja2 模板文件。Ansible 使用 Jinja2 模板引擎,允许我们在文件中使用变量和逻辑。

这个重构后的 Playbook 更加模块化和高效。


结论

Ansible 以其简单、无代理和幂等的特性,成为了自动化运维领域的佼佼者。通过 Ad-Hoc 命令和强大的 Playbook,您可以轻松管理从几台到数千台服务器的庞大集群,极大地提高了工作效率和系统稳定性。

本文只是 Ansible 世界的冰山一角。希望通过这篇详细的入门指南,您已经对 Ansible 有了深入的了解,并能够开始在您的工作中实践它。继续探索 Ansible 的角色(Roles)、动态清单(Dynamic Inventories)和 Ansible Tower/AWX,您会发现更多自动化的可能性。