XYCOVO CONSOLE KURISU · WEB 渗透 / AI 辅助攻防 ONLINE
#005 · 2025-07-15✓ PASS

Ansible 自动化运维

RHEL 环境下 Ansible 自动化运维的完整入门指南,涵盖 Inventory 管理、Playbook 编写、变量与事实、循环与条件控制,从零掌握 IT 自动化。
linux网络安全ansible自动化AUTHOR: KURISU

Ansible 是一个开源的自动化平台,使用简单易读的 YAML 格式编写 Playbook,无需在被管理节点安装任何代理,通过 SSH 即可实现配置管理、应用部署和工作流编排。


一、自动化与 Ansible 概述

1.1 自动化与基础架构即代码(IaC)

大多数系统管理长期依赖于图形界面或命令行手动操作,这种做法存在诸多问题:

  • 系统管理员容易跳过某个步骤或在某个步骤出错
  • 对步骤执行是否正确或是否产生预期结果的验证通常有限
  • 以手动方式管理多台服务器容易出现微小差异,给 IT 环境带来不一致性

基础架构即代码 (IaC) 让自动化语言来定义和描述所需的 IT 基础架构状态:

  • 自动化语言表现为简单的文本文件,可使用版本控制系统轻松管理
  • 开发人员定义所需配置,操作员查看更改并提供反馈
  • 通过自动化重复确保系统处于期望状态

1.2 Ansible 特性

特性说明
SimplePlaybook 易读、易懂、易改,不需要特殊编码技能
Powerful可部署应用、配置管理、工作流自动化和网络自动化
Agentless使用 OpenSSH/WinRM 连接管理主机,无需在被管节点安装代理
跨平台支持 Linux、Windows、UNIX、网络设备和容器
幂等性可在相同主机上多次安全运行 Playbook,不会重复更改
版本控制所有配置均为文本文件,可纳入 Git 等版本控制系统管理

1.3 Ansible 架构

Ansible 架构中有两种计算机类型:

角色说明
控制节点 (Control Node)安装 Ansible 软件,维护所有组件和配置
受管主机 (Managed Hosts)在 Inventory 清单文件中列出,通过 SSH 接收任务

工作流程:

  1. 管理员编写 Playbook(YAML 格式)
  2. 控制节点通过 SSH 连接受管主机
  3. 向受管主机推送 Ansible 模块(Python 小程序)
  4. 执行任务后,推送的模块被自动删除

二、部署 Ansible

2.1 安装

# 安装 Ansible
dnf install ansible -y

# 查看版本信息
ansible --version
# ansible [core 2.13.3]
#   config file = /etc/ansible/ansible.cfg
#   configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']

2.2 安装额外模块

# 安装 Ansible Galaxy 集合
ansible-galaxy collection install ansible.posix

三、Inventory 清单管理

3.1 清单概述

清单定义 Ansible 将要管理的一批主机,这些主机可以分配到组中,以方便管理。组可以包含子组,主机可以是多个组的成员。

默认的清单文件为 /etc/ansible/hosts

3.2 INI 格式清单

清单文件的基本规则:

  • # 开头的行是注释
  • 空行会被忽略
  • 组和主机使用 [name] 来定义
  • 可以使用主机名或 IP 地址
  • 一个主机可以是多个组的成员
# 没有指定组的主机要写在所有组的最前面
green.example.com
blue.example.com
192.168.100.1

# webservers 组
[webservers]
alpha.example.org
beta.example.org
192.168.1.100
www[001:006].example.com

# dbservers 组
[dbservers]
db01.intranet.mydomain.net
db02.intranet.mydomain.net
10.25.1.56

# test 组包含其他组(组嵌套)
[test:children]
webservers
dbservers

3.3 创建清单文件

# 配置本地解析
cat /etc/hosts
# 192.168.115.128 web1 web1.example.com
# 192.168.115.133 web2 web2.example.com

# 创建自定义清单
cat inventory
# [webserver]
# web1.example.com
# web2.example.com
#
# [dbserver]
# 192.168.115.128
# 192.168.115.133
#
# [test:children]
# webserver
# dbserver

# 查看清单结构
ansible-inventory --graph -i inventory
# @all:
#   |--@test:
#   |  |--@dbserver:
#   |  |  |--192.168.115.128
#   |  |  |--192.168.115.133
#   |  |--@webserver:
#   |  |  |--web1.example.com
#   |  |  |--web2.example.com
#   |--@ungrouped:

3.4 内置主机组

组名说明
all包含清单中明确列出的每一个主机
ungrouped包含清单中明确列出但不属于任何组的主机

四、ansible.cfg 配置文件

4.1 配置文件优先级

Ansible 从控制节点上的多个可能位置选择其配置文件(按优先级排序):

  1. ANSIBLE_CONFIG 环境变量指定的文件
  2. 当前目录的 ./ansible.cfg
  3. 用户家目录的 ~/.ansible.cfg
  4. /etc/ansible/ansible.cfg(默认)

Ansible 不会融合多个配置文件,只会使用选定的一个。

4.2 常用配置项

[defaults]
inventory = ./inventory        # 清单文件路径
remote_user = root             # SSH 远程用户
ask_pass = false               # 是否提示输入 SSH 密码

[privilege_escalation]
become = true                  # 是否自动提权
become_method = sudo           # 提权方法
become_user = root             # 提权目标用户
become_ask_pass = false        # 是否提示输入 sudo 密码

4.3 生成示例配置

# 生成禁用的默认配置
ansible-config init --disabled > ansible2.cfg

# 生成所有配置项
ansible-config init --disabled -t all > ansible3.cfg

五、临时命令 (Ad-Hoc Commands)

5.1 基本格式

ansible host-pattern -m module [-a 'module arguments'] [-i inventory]

5.2 常用模块

模块类别模块用途
文件模块copy复制文件到远程主机
file管理文件属性和权限
lineinfile管理文件中的行
软件包模块package通用包管理
yumYUM 包管理
dnfDNF 包管理
pipPython 包管理
系统模块firewalld防火墙管理
reboot重启系统
service服务管理
user用户管理
group组管理
网络模块get_url下载文件
nmcliNetworkManager 管理
uriHTTP 请求

5.3 临时命令示例

# 测试连通性
ansible all -m ping

# 创建用户
ansible -m user -a 'name=haha uid=4000 state=present' web1.example.com

# 执行 shell 命令
ansible -m shell -a 'id haha' web1.example.com

# 安装软件包
ansible webserver -m dnf -a 'name=httpd state=present'

5.4 执行命令的三种模块

模块说明
shell按 Linux Shell 方式运行,支持管道和重定向
command单纯执行命令,不支持管道
raw当目标没有 Python 环境时使用

尽量避免使用这三个模块,大多数专用模块是幂等的,可自动进行更改追踪。


六、Playbook 编写

6.1 YAML 基础

YAML 格式两种基本规则:

  • 处于层级结构中同一层级的数据元素,必须具有相同的缩进量
  • 如果项目属于其他项目的子项,其缩进量必须大于父项

只能使用空格缩进,不能使用制表符。

Vim 配置autocmd FileType yaml setlocal ai ts=2 sw=2 et

6.2 YAML 语法速查

# 注释
# This is a YAML comment

# 字符串(通常不需要引号)
this is a string
'this is a string'
"this is yet another string"

# 多行字符串(保留换行)
include_newlines: |
  Example Company
  123 Main Street
  Atlanta, GA 30303

# 多行字符串(折叠为单行)
fold_newlines: >
  This is an example
  of a long string,
  that will become
  a single sentence once folded.

# 字典(缩进格式)
name: svcrole
svcservice: httpd
svcport: 80

# 字典(内联格式)
{name: svcrole, svcservice: httpd, svcport: 80}

# 列表(短横线格式)
hosts:
  - servera
  - serverb
  - serverc

# 列表(内联格式)
hosts: [servera, serverb, serverc]

6.3 Playbook 基本结构

---
- name: play 名称
  hosts: 目标主机或组
  tasks:
    - name: 任务描述
      module_name:
        param1: value1
        param2: value2

6.4 简单 Playbook 示例

---
- name: create user
  hosts: web1.example.com
  tasks:
    - name: create user haha
      user:
        name: haha
        uid: 4000
        state: present

6.5 多任务 Playbook

---
- name: configure web server
  hosts: webservers
  tasks:
    - name: web server is enabled
      service:
        name: httpd
        enabled: true

    - name: ntp server is enabled
      service:
        name: chronyd
        enabled: true

    - name: postfix is enabled
      service:
        name: postfix
        enabled: true

6.6 多 Play 的 Playbook

---
- name: first play
  hosts: web1.example.com
  tasks:
    - name: install httpd
      dnf:
        name: httpd
        state: present

    - name: start httpd
      service:
        name: httpd
        enabled: true

- name: second play
  hosts: 192.168.115.128
  tasks:
    - name: start mariadb
      service:
        name: mariadb
        enabled: true

6.7 运行 Playbook

# 检查语法
ansible-playbook --syntax-check site.yml

# 运行 Playbook
ansible-playbook user.yml

# 增加详细程度
ansible-playbook user.yml -v      # 显示任务结果
ansible-playbook user.yml -vv     # 显示任务结果和配置
ansible-playbook user.yml -vvv    # 包含连接信息
ansible-playbook user.yml -vvvv   # 包含额外详细选项

七、变量管理

7.1 变量定义位置

变量可在三个基本范围级别定义:

范围说明优先级
全局范围命令行或 Ansible 配置设置的变量最高
Play 范围在 play 和相关结构中设置的变量
主机范围由清单、事实收集或注册任务设置的变量最低

7.2 在 Playbook 中定义变量

- hosts: all
  vars:
    user: joe
    home: /home/joe

7.3 使用外部变量文件

# Playbook 中引用
- hosts: all
  vars_files:
    - vars/users.yml

# vars/users.yml 内容
user: joe
home: /home/joe

7.4 在任务中使用变量

vars:
  user: joe
tasks:
  - name: Create the user {{ user }}
    user:
      name: "{{ user }}"

当变量用作值的第一个元素时,必须使用引号。这可以防止 Ansible 将变量引用视为 YAML 字典的开头。

7.5 主机变量和组变量(推荐做法)

首选做法是创建 group_varshost_vars 目录:

project/
├── group_vars
│   ├── datacenter1
│   ├── datacenter2
│   └── datacenters
├── host_vars
│   ├── demo1.example.com
│   ├── demo2.example.com
│   ├── demo3.example.com
│   └── demo4.example.com
└── inventory
# group_vars/datacenters
package: httpd

# group_vars/datacenter1(覆盖父组变量)
package: httpd

# group_vars/datacenter2
package: apache

# host_vars/demo1.example.com(最高优先级)
package: httpd

7.6 从命令行覆盖变量

ansible-playbook main.yml -e "package=apache"

7.7 使用注册变量捕获命令输出

---
- name: Install a package and prints the result
  hosts: all
  tasks:
    - name: Install the package
      dnf:
        name: httpd
        state: installed
      register: install_result

    - debug:
        var: install_result

八、Ansible Facts(事实)

8.1 事实概述

Ansible 事实是 Ansible 在受管主机上自动检测到的变量。每个 play 在执行第一个任务之前会先自动运行 setup 模块来收集事实。

事实变量
短主机名ansible_facts['hostname']
完全限定域名ansible_facts['fqdn']
主要 IPv4 地址ansible_facts['default_ipv4']['address']
所有网络接口名称ansible_facts['interfaces']
DNS 服务器列表ansible_facts['dns']['nameservers']
内核版本ansible_facts['kernel']

8.2 在 Playbook 中使用事实

---
- hosts: all
  tasks:
    - name: Print various Ansible facts
      debug:
        msg: >
          The default IPv4 address of {{ ansible_facts.fqdn }}
          is {{ ansible_facts.default_ipv4.address }}

8.3 关闭事实收集

---
- name: This play gathers no facts automatically
  hosts: large_farm
  gather_facts: no

九、循环与条件

9.1 简单循环

- name: Postfix and Dovecot are running
  service:
    name: "{{ item }}"
    state: started
  loop:
    - postfix
    - dovecot

9.2 使用变量列表循环

vars:
  mail_services:
    - postfix
    - dovecot
tasks:
  - name: Postfix and Dovecot are running
    service:
      name: "{{ item }}"
      state: started
    loop: "{{ mail_services }}"

9.3 循环散列/字典列表

- name: Users exist and are in the correct groups
  user:
    name: "{{ item.name }}"
    state: present
    groups: "{{ item.groups }}"
  loop:
    - name: jane
      groups: wheel
    - name: joe
      groups: root

9.4 when 条件语句

操作示例
等于(字符串)ansible_machine == "x86_64"
等于(数字)max_memory == 512
小于min_memory < 128
大于min_memory > 256
不等于min_memory != 512
变量存在min_memory is defined
变量不存在min_memory is not defined
布尔变量为 truememory_available
布尔变量为 falsenot memory_available
值在列表中ansible_distribution in supported_distros

9.5 when 使用示例

# 条件安装
- name: "{{ my_service }} package is installed"
  dnf:
    name: "{{ my_service }}"
  when: my_service is defined

# 布尔条件
- name: httpd package is installed
  dnf:
    name: httpd
  when: run_my_task

# 判断发行版
- name: Install httpd using dnf
  dnf:
    name: httpd
    state: present
  when: ansible_distribution in supported_distros

9.6 组合条件

# OR 条件
when: ansible_distribution == "Redhat" or ansible_distribution == "Fedora"

# AND 条件
when: ansible_distribution_version == "7.5" and ansible_kernel == "3.10.0-327.el7.x86_64"

# 列表形式(默认 AND)
when:
  - ansible_distribution_version == "7.5"
  - ansible_kernel == "3.10.0-327.el7.x86_64"

# 括号分组
when: >
  ( ansible_distribution == "Redhat" and
    ansible_distribution_major_version == "7" )
  or
  ( ansible_distribution == "Fedora" and
    ansible_distribution_major_version == "28" )

9.7 组合循环与条件

# 仅在根分区有足够空间时安装
- name: install mariadb-server if enough space on root
  dnf:
    name: mariadb-server
    state: latest
  loop: "{{ ansible_mounts }}"
  when: item.mount == "/" and item.size_available > 300000000

十、最佳实践

  1. 使用版本控制:将 Playbook、清单和配置文件纳入 Git 管理
  2. 优先使用专用模块:比直接使用 shell/command 模块更可靠且幂等
  3. 命名规范:变量使用下划线 (web_server),不用连字符 (web-server)
  4. 目录变量管理:使用 group_varshost_vars 目录,而非在清单文件中混入变量
  5. 语法检查:运行前使用 --syntax-check 验证
  6. 从小处开始:先用临时命令验证连通性,再编写 Playbook
  7. 使用 roles:当 Playbook 变得复杂时,使用 Ansible Roles 组织代码
  8. 敏感信息:使用 ansible-vault 加密密码等敏感变量

← #004 RHCSA 学习笔记…#006 Shell 脚本编程… →