RHCE 学习笔记

学习红帽课程中的一些笔记。

认识 ansible

ansible 架构

flowchart LR
    subgraph ControlNode ["控制节点 Control Node"]
        CLI["Ansible CLI 工具"]
        
        subgraph CoreComponents ["核心组件"]
            Inventory["主机清单 Inventory"]
            Playbooks["剧本 Playbooks"]
            Modules["模块 Modules"]
            Plugins["插件 Plugins"]
        end
        
        Engine["Ansible 核心引擎"]
        
        CLI --> Engine
        Engine --> Inventory
        Engine --> Playbooks
        Engine --> Modules
        Engine --> Plugins
    end

    subgraph Transport ["传输层 Transport Layer"]
        SSH["SSH 协议 (Linux/Unix)"]
        WinRM["WinRM 协议 (Windows)"]
    end

    subgraph ManagedNodes ["被控节点 Managed Nodes"]
        Server1["Linux 服务器"]
        Server2["Windows 服务器"]
    end

    Inventory --> ManagedNodes
    Engine --> SSH
    Engine --> WinRM

    SSH --> Server1
    WinRM --> Server2

    style ControlNode fill:#f9f9f9,stroke:#333,stroke-width:2px
    style ManagedNodes fill:#f0f8ff,stroke:#03a9f4,stroke-width:2px
    style CoreComponents fill:#fff3e0,stroke:#ff9800,stroke-width:1px

ansible 安装

  • 基于 rpm 包安装
1
yum install -y ansible      # RHEL9 ISO 携带的是 ansible-core 版本
  • 通过 pip 工具安装
1
2
3
yum install -y python3-pip
# 指定国内镜像源,不指定则使用默认仓库
pip install ansible-core -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
  • 通过源码包安装
1
2
3
4
5
6
7
8
wget https://releases.ansible.com/ansible/ansible-2.9.0.tar.gz
tar xvf ansible-2.9.0.tar.gz
cd ansible-2.9.0
python setup.py build
python setup.py install
# 源码包安装之后,默认没有配置文件。提供了配置文件模板在 `examples` 目录下
mkdir /etc/ansible
cp ./examples/ansible.cfg /etc/ansible

ansible 配置和使用

ansible.cfg 配置文件

配置优先级:

  1. (最高) ANSIBLE_CONFIG 环境变量指定的 ansible.cfg 位置(默认无)。
  2. 当前运行 ansibleansible-navigator 命令时所在的目录下的 ansible.cfg
  3. 用户家目录下的 ~/.ansible.cfg,注意文件名前面有个点 .
  4. (最低) 系统默认全局路径 /etc/ansible/ansible.cfg,通过 RPM/Dnf 安装 Ansible 时生成的系统级默认配置文件。
区块名称 配置项 常见可选值 / 默认值 作用与配置说明
[defaults]
(基础通用配置)
inventory ./inventory
/etc/ansible/hosts
指定默认的主机清单(Inventory)文件路径或目录。
remote_user root
devops (自定义)
指定 Ansible 在受控节点上默认使用的 SSH 登录用户名。如果没有指定则以当前用户名登录远程主机。
ask_pass False
True
SSH 登录受控节点时是否强制弹窗提示输入 SSH 密码(相当于 -k,密码登录时必须要有此项)。配合 SSH 公钥免密时设为 False
host_key_checking False
True
首次连接受控节点时是否检查对方的 SSH Host Key。建议设为 False 避免交互式确认卡死。
forks 5 (默认)
10
50
Ansible 并发执行任务的最大受控节点数量(进程池大小)。
roles_path ./roles
/roles
指定 Ansible 自动查找角色(Roles)的目录路径列表(多个路径用 : 分隔)。
log_path ./ansible.log 指定 Ansible 执行日志的存储路径(默认不留存文件日志)。
[privilege_escalation]
(提权配置)
become True
False
是否在登录受控节点后自动进行权限提升(提权)。
become_method sudo
su
指定提权的方式,几乎所有 Linux 环境均使用 sudo
become_user root 指定提权目标到的用户身份。
become_ask_pass False
True
执行提权命令时是否弹窗提示输入 sudo 密码。设为 False 需配合受控节点 NOPASSWD: 配置。
[ssh_connection]
(连接优化)
pipelining True
False
是否开启 SSH 管道传输优化。开启后可减少 SSH 连接建立次数,大幅提升性能。
timeout 10 (秒) 指定与受控节点建立 SSH 连接的超时时间。

配置免密

步骤 执行命令 / 配置内容 说明 / 关键参数
1. 远程创建受控节点用户 ansible all -m user -a 'name=ansible-user state=present' -u root -k 仅当受控节点尚未创建目标运维用户时使用(以 root 登录并配合 -k 手动输入 root 密码)。
ansible all -m shell -a 'echo 123 | passwd --stdin ansible-user' -u root -k 为远程用户创建密码。
2. 生成 SSH 密钥对 ssh-keygen -t ed25519 -N '' -N '' 设置私钥为空密码。
3. 远程推送公钥 ssh-copy-id ansible-user@192.168.23.129 终端提示 Number of key(s) added: 1
4. 验证 SSH 免密 ssh ansible-user@192.168.23.129 确认公钥免密登录生效;验证完成后输入 exit 退出返回控制节点。
5. 远程配置 免密 ansible all -m copy -a 'content="ansible-user ALL=(ALL) NOPASSWD: ALL\n" dest=/etc/sudoers.d/ansible-user mode=0440' -u root -k 借由 copy 模块在受控节点写入 /etc/sudoers.d/ 规则;mode=0440sudo 读取的硬性权限要求。
6. 修改本地 ansible.cfg 编辑项目目录下的 ansible.cfg
[defaults]
inventory = ./hosts
remote_user = ansible-user
host_key_checking = False
ask_pass = False
[privilege_escalation]
become = True
become_method = sudo
become_user = root
become_ask_pass = False
指定远程用户;明确关闭 ask_passbecome_ask_pass 密码询问,实现完全无人值守。
7. 最终连通与提权验证 ansible all -m command -a 'id' 验证控制节点使用 SSH 密钥登录 + 提权双重免密通道完全打通。

编辑 inventory 主机清单

ansible.cfginventory 字段指定的 inventory(主机清单)文件,用于定义 Ansible 所管理的受控节点。它可以是简单的 INI 格式或 YAML 格式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 未分组主机 (Ungrouped Hosts)
# 直接写在文件顶部,等同于 [ungrouped] 组
standalone1.example.com ansible_host=192.168.1.1
192.168.1.2

# 基础主机组 (Basic Groups)
# 直接通过主机名或 IP 地址定义节点,未分组的主机可以写在任何组之外
[dbservers]
db1.example.com # 主机名需要在 /etc/hosts 写入解析记录,或由 DNS 服务器解析
192.168.1.50
[webservers]
web[1:3].example.com # [] 方括号表示范围匹配

# 嵌套组 / 组中组 (Children Groups)
# 使用 [父组名:children] 结构,将多个子组组合为一个大组,方便批量调用
[datacenter:children]
dbservers
webservers

选择主机清单中的主机

选择需求 命令行写法 说明 / 匹配逻辑
选择所有主机 ansible all --list-hosts 使用内置隐式组 all(或单字符 *
选择单个主机 ansible node1 --list-hosts 直接指定单台主机的名称
选择单个组 ansible webservers --list-hosts 指定组名,匹配该组内所有机器
选择多个组/主机(逻辑“或”) ansible 'webservers,dbservers' --list-hosts 逗号 ,冒号 : 分隔多个组或主机
选择组的交集(逻辑“与”) ansible 'webservers:&datacenter' --list-hosts 使用 & 符号,仅选择同时存在于两个组中的主机
排除特定组/主机(逻辑“非”) ansible 'datacenter:!dbservers' --list-hosts 使用 ! 符号,选择 datacenter 组但排除 dbservers
使用通配符匹配 ansible 'node*' --list-hosts 支持 * 匹配任意字符
选择未分组主机 ansible ungrouped --list-hosts 选择不属于任何自定义组的所有主机

ad-hoc 与常用模块

Ad-hoc(临时/即时命令) 指的是通过命令行直接执行的“单条临时指令”,不需要提前编写 YAML 格式的 Playbook(剧本)。它的本质是:“即用即弃,快速搞定”。

ansible-doc <模块名> 查询对应模块的说明。

命令执行模块

模块名称 命令示例 执行方式 特点
command
(默认模块)
ansible all -a 'id'
ansible all -m command -a 'uptime'
直接调用二进制可执行文件,不经过 Shell 解析。 Ansible 默认模块(不加 -m 即为此模块)。
最安全,避免 Shell 语法注入。
不支持 管道 |、重定向 >、通配符 * 和环境变量 $VAR
shell ansible all -m shell -a 'echo 123 | passwd --stdin devops'
ansible all -m shell -a 'ps -ef | grep nginx > /tmp/ps.txt'
在远端启动 Shell 进程(如 /bin/sh)解析并执行。 支持所有 Shell 特性(管道 |、重定向 >、链式逻辑 &&)。
• 灵活性极高,适合执行复杂系统指令。
• 存在 Shell 注入安全隐患,默认每次运行都会触发 CHANGED
script ansible all -m script -a '/root/scripts/init_node.sh' 控制节点本地的脚本传到受控节点临时目录并调用 Shell 执行。 受控节点无需预存脚本,自动分发并清理。
• 非常适合直接复用现有的旧 Shell/Python 运维脚本。
raw ansible node1 -m raw -a 'dnf install -y python3' 绕过 Python 模块框架,直接通过 SSH 发送原生 Shell 指令。 受控节点无需安装 Python 即可运行。
• 仅用于老旧系统、路由器设备或新节点安装 Python 环境“开荒”。

文件管理模块

模块名称 功能解释 常用参数 命令示例
copy 控制节点的文件或生成的内容复制传输到受控节点 src: 本地源文件路径
dest: 远端目标路径(必填)
content: 直接写入文件文本内容(与 src 二选一)
mode: 权限(如 06440440
owner / group: 属主与属组
backup: yes/no,覆写前是否备份原文件
复制本地文件
ansible all -m copy -a 'src=/tmp/nginx.conf dest=/etc/nginx/nginx.conf mode=0644'
直接写入文本
ansible all -m copy -a 'content='devops ALL=(ALL) NOPASSWD: ALL\n' dest=/etc/sudoers.d/devops mode=0440'
fetch 受控节点拉取/拉回文件到控制节点(与 copy 动作相反)。 src: 受控节点上的源文件路径(必须是文件,不能是目录)
dest: 控制节点保存文件的目标目录
flat: yes/no,是否改变保存路径结构(默认会按主机名建子目录)
拉取远端日志到本地
ansible all -m fetch -a 'src=/var/log/messages dest=/tmp/fetched_logs/'
扁平化保存(直接重命名)
ansible node1 -m fetch -a 'src=/etc/redhat-release dest=/tmp/node1-release flat=yes'
file 管理受控节点上的文件/目录状态(创建、删除、修改权限、创建软硬链接等)。 path: 目标路径(必填,也可写为 dest / name
state: directory (目录), touch (空文件), absent (删除), link (软链接)
src: 创建软链接时的源路径
mode / owner / group: 权限与属主属组
recurse: yes/no,递归修改目录权限
新建目录并设权限
ansible all -m file -a 'path=/data/www state=directory mode=0755 owner=nginx'
删除文件或目录
ansible all -m file -a 'path=/tmp/junk state=absent'
创建软链接
ansible all -m file -a 'src=/etc/nginx/sites-available/default dest=/etc/nginx/sites-enabled/default state=link'

软件管理模块

模块名称 功能解释 常用参数 命令示例
yum_repository 配置和管理受控节点上的 YUM/DNF 软件源(即自动生成/修改 /etc/yum.repos.d/*.repo 文件)。 name: Repo ID / 文件标识(必填)
description: Repo 描述(name 字段内容)
baseurl: 镜像源 URL 地址
gpgcheck: yes/no,是否开启 GPG 密钥校验
gpgkey: GPG 秘钥地址
enabled: yes/no,是否启用该软件源
state: present (创建) / absent (删除)
添加本地 AppStream 软件源
ansible all -m yum_repository -a 'name=AppStream description='AppStream Repo' baseurl=file:///media/AppStream gpgcheck=no enabled=yes'
删除指定的 repo 配置
ansible all -m yum_repository -a 'name=old_repo state=absent'
yum
(或 dnf)
在 RHEL/CentOS 等系统上安装、更新、卸载或批量管理 RPM 软件包。 name: 软件包名称(支持指定版本、.rpm 本地包路径或 * 全盘更新)
state: present / installed (安装), latest (更新到最新), absent / removed (卸载)
enablerepo / disablerepo: 临时启用或禁用特定的软件源
disable_gpg_check: yes/no,是否跳过 GPG 校验
安装最新版本的 httpd
ansible all -m yum -a 'name=httpd state=latest'
更新系统所有软件包
ansible all -m yum -a 'name='*' state=latest'
卸载指定软件包
ansible all -m yum -a 'name=mariadb-server state=absent'

服务管理模块

模块名称 功能解释 常用参数 命令示例
service 通用服务管理器(跨平台兼容 SysVinit、Systemd 等),控制服务的启动、停止、重载和开机自启。 name: 服务名称(如 httpd, sshd
state: started (启动), stopped (停止), restarted (重启), reloaded (重载配置)
enabled: yes/no,设置服务是否开机自启
启动服务并设为开机自启
ansible all -m service -a 'name=httpd state=started enabled=yes'
停止服务
ansible all -m service -a 'name=firewalld state=stopped enabled=no'
systemd
(或 systemd_service)
专用于 Linux Systemd 系统的主机管理,除常规服务控制外,还支持 daemon-reload 和 Unit 文件管理。 name state enabled:同上
daemon_reload: yes/no,在修改了 .service 服务单元配置文件后重新加载 systemd 管理器
重载配置并重启服务
ansible all -m systemd -a 'name=sshd state=restarted daemon_reload=yes'
刷新 systemd 规则
ansible all -m systemd -a 'daemon_reload=yes'

用户管理模块

模块名称 功能解释 常用参数 命令示例
user 管理 Linux 系统用户账户及其属性(创建、修改、删除、设置密码与 SSH 密钥)。 name: 用户名(必填)
state: present (创建) / absent (删除)
uid: 指定用户的 UID
group: 主组名称或 GID
groups: 附加组列表(多个用逗号隔开)
append: yes/no,将附加组增量追加而非覆盖
shell: 指定登录 Shell(如 /bin/bash
password: SHA-512 哈希密文
remove: yes/no,在 state=absent 删除用户时顺便删除家目录
创建运维账户并指定附加组与 Shell
ansible all -m user -a 'name=devops group=wheel groups=sysadmin append=yes shell=/bin/bash'
彻底删除用户及家目录
ansible all -m user -a 'name=testuser state=absent remove=yes'
group 管理 Linux 系统用户组(创建、修改 GID 或删除组)。 name: 组名(必填)
state: present (创建) / absent (删除)
gid: 指定组的 GID
system: yes/no,是否创建为系统组(GID < 1000)
创建指定 GID 的系统组
ansible all -m group -a 'name=deploy gid=1050 system=yes'
删除用户组
ansible all -m group -a 'name=oldgroup state=absent'

计划任务模块 cron

模块名称 功能解释 常用参数 命令示例
cron 管理受控节点上的 crontab 定时任务(支持增、删、改、查与环境变量设置)。 name: 任务描述/标识名称(必填,对应 crontab 中的注释头)
minute / hour / day / month / weekday: 时间设定(默认皆为 *
job: 要执行的脚本或命令(必填)
user: 指定属于哪个用户的 crontab(默认当前连接用户)
state: present (创建/更新) / absent (删除)
disabled: yes/no,禁用/注释掉该任务但不删除
cron_file: 指定定时任务在哪个文件
新建定时清理任务
ansible all -m cron -a "name='clean tmp log' minute='0' hour='2' job='/usr/bin/find /tmp -name \"*.log\" -mtime +7 -delete'"
删除指定的计划任务
ansible all -m cron -a 'name="clean tmp log" state=absent'

文件下载模块 get_url

模块名称 功能解释 常用参数 命令示例
get_url 从 HTTP/HTTPS/FTP 等网络协议节点下载文件到受控节点(类似于 wget / curl)。 url: 下载资源的网络 URL(必填)
dest: 远端保存的目标路径或文件名(必填)
mode / owner / group: 保存文件的权限与属主属组
下载文件并指定保存权限
ansible all -m get_url -a 'url=https://example.com/app.tar.gz dest=/tmp/app.tar.gz mode=0644'
带 checksum 校验下载
ansible all -m get_url -a 'url=https://example.com/repo.key dest=/etc/pki/repo.key checksum=sha256:d3b07384...'

解压缩模块 unarchive

模块名称 功能解释 常用参数 命令示例
unarchive 解压压缩包(支持 .tar, .tar.gz, .zip, .tgz 等)。默认将控制节点上的压缩包解压传输到受控节点 src: 压缩包文件路径(必填)
dest: 受控节点上的目标解压目录(必填,目录必须已存在)
remote_src: yes/no,为 yes 时表示 src 为受控节点目录
从控制节点解压并传输到远端
ansible all -m unarchive -a 'src=/root/app.zip dest=/var/www/html/ mode=0755'
解压远端受控节点已有的压缩包
ansible all -m unarchive -a 'src=/tmp/nginx.tar.gz dest=/opt/ remote_src=yes'

文件同步模块 synchronize

模块名称 功能解释 常用参数 命令示例
synchronize 基于 rsync 算法高效同步文件或目录(比 copy 模块更适合增量同步与大文件传输)。 src: 源文件或目录路径(必填)
dest: 目标文件或目录路径(必填)
mode: push (控制节点推向受控节点,默认) / pull (从受控节点拉取到控制节点)
delete: yes/no,同步时删除目标目录中源目录没有的文件(保持严格一致)
archive: yes/no,归档模式,相当于 rsync 的 -a 参数(保留权限,默认 yes
增量同步本地网页目录至远端
ansible all -m synchronize -a 'src=/var/www/site/ dest=/var/www/html/'
镜像同步(带 –delete 保持完全一致)
ansible all -m synchronize -a 'src=/data/backup/ dest=/mnt/backup/ delete=yes'

文件内容编辑模块

模块名称 功能解释 常用参数 命令示例
lineinfile 用于在文件中匹配、替换、插入或删除单行内容。适合管理单一配置项(如修改某个变量值、确保特定行存在/不存在)。 path: 目标文件路径(必填)
regexp: 用于匹配目标行的正则表达式
line: 要写入的目标行内容
state: present(确保存在,默认)或 absent(删除匹配行)
insertafter: 匹配正则或 EOF,在此行之后插入
insertbefore: 匹配正则或 BOF,在此行之前插入
create: yes(文件不存在时自动创建)
backrefs: 若未匹配到 regexp 时,yes 不进行修改,no (默认)作为新行追加插入到文件末尾或指定位置
修改或插入单行配置:
ansible all -m lineinfile -a "path=/etc/ssh/sshd_config regexp='^PermitRootLogin' line='PermitRootLogin no' state=present"

删除指定行:
ansible all -m lineinfile -a "path=/etc/hosts regexp='.*old-server.*' state=absent"
blockinfile 用于在文件中插入、更新或删除一段多行文本块。默认会在文本块前后自动加上标记行(Marker),以便后续精确更新或移除该区块。 path: 目标文件路径(必填)
block: 要插入的多行文本内容
marker: 自定义标记行格式,默认包含 # BEGIN ANSIBLE MANAGED BLOCK
state: present(确保文本块存在)或 absent(移除该文本块)
insertafter: 匹配正则或 EOF,在此行之后插入块
insertbefore: 匹配正则或 BOF,在此行之前插入块
create: yes(文件不存在时自动创建)
插入多行配置块:
ansible all -m blockinfile -a "path=/etc/hosts block='192.168.1.10 db-server\n192.168.1.11 web-server' marker='# {mark} ANSIBLE MANAGED HOSTS' state=present"

移除指定的文本块:
ansible all -m blockinfile -a "path=/etc/hosts marker='# {mark} ANSIBLE MANAGED HOSTS' state=absent"

playbook 剧本

yaml 格式编写

  1. 基本文件结构:
    • 文件开头:通常以三个连字符 --- 开头,表示 YAML 文档的开始(可省略)。
    • 列表(List):用短横线加空格 -&nbsp;&nbsp;&nbsp;表示一个元素。Playbook 的最外层本质上就是一个 Play 的列表。
    • 键值对(Dictionary):使用 key: value 格式,冒号后必须有一个空格。
  2. 三级层级关系:
    • Play(剧本):定义在哪些主机(hosts)上执行,以及以什么身份(become)执行。
    • Tasks(任务列表):每个 Play 包含一个 tasks 列表,按顺序向下执行。
    • Module(模块及其参数):每个 Task 调用一个 Ansible 模块,并传入相应的参数。
  3. 缩进规则:
    • 严格禁止使用 Tab 键,必须使用纯空格(建议统一使用 2 个空格作为一个缩进层级)。
    • 同一层级的元素必须左对齐。
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# ==============================================================================
# Play 1: 部署并配置 Nginx Web 服务器
# ==============================================================================
- name: Deploy and configure Nginx web server # Play 的名称,描述这个 Play 的总体目标
hosts: webservers # 目标主机组(对应 Ansible Inventory 清单中的组名)
become: true # 开启提权(相当于 sudo),以便执行安装软件和管理服务操作
vars: # 定义该 Play 内使用的局部变量
http_port: 80
max_clients: 200

tasks: # 任务列表开始(按从上到下的顺序依次执行)

# --------------------------------------------------------------------------
# Task 1: 确保安装了最新版本的 Nginx
# --------------------------------------------------------------------------
- name: Install Nginx package # Task 的名称,执行时会打印在终端中
dnf: # 推荐使用全称模块名 (Namespace.Collection.Module)
name: nginx # 要安装的软件包名称
state: present # 确保包存在(present 表示安装,latest 表示升级到最新,absent 表示卸载)

# --------------------------------------------------------------------------
# Task 2: 自定义 Web 首页内容(使用 copy 模块)
# --------------------------------------------------------------------------
- name: Create index.html with custom text
copy:
content: "<h1>Welcome to Ansible Managed Webserver on port {{ http_port }}</h1>\n" # 使用 {{ }} 引用 vars 中定义的变量
dest: /usr/share/nginx/html/index.html # 目标文件路径
owner: root # 设置文件所有者
group: root # 设置文件所属组
mode: '0644' # 设置文件权限(推荐加单引号防止被解析为八进制异类)

# --------------------------------------------------------------------------
# Task 3: 确保 Nginx 服务已启动并设置开机自启
# --------------------------------------------------------------------------
- name: Ensure Nginx service is running and enabled
service:
name: nginx # 服务名称
state: started # 状态:started(启动), stopped(停止), restarted(重启)
enabled: true # 是否设置开机自启 (true/false)

# ==============================================================================
# Play 2: 验证部署结果(演示多 Play 结构,在控制节点本地运行)
# ==============================================================================
- name: Verify Web server status
hosts: localhost # 在控制节点本地运行测试
gather_facts: false # 关闭受控节点信息收集(Gathering Facts),提高执行效率

tasks:
- name: Print success message
debug: # 用于打印调试信息的模块
msg: "Nginx deployment completed successfully!"

playbook 的执行

常用参数 / 选项 典型命令示例 作用与适用场景
标准执行 ansible-playbook site.yml 直接运行剧本。按顺序执行 site.yml 中定义的所有 Play 和 Task。
指定清单文件 ansible-playbook -i hosts site.yml 覆盖默认主机清单。使用 -i 指定特定环境的 Inventory 文件(如开发、测试、生产环境清单)。
语法检查 ansible-playbook site.yml --syntax-check 仅检查 YAML 语法与结构。不会连接受控节点,常用于 CI/CD 流水线或上机前的静态校验。
模拟预演 (Dry Run) ansible-playbook site.yml -C
(或 --check)
预演执行。模拟运行并预测哪些 Task 会返回 changed,但不会对远端系统做任何实际修改
限制执行主机 ansible-playbook site.yml -l 'web01,web02'
(或 --limit)
临时缩小目标主机范围。仅在清单中的指定主机或主机组上运行 Playbook,无需修改剧本中的 hosts 属性。
传入外部变量 ansible-playbook site.yml -e "http_port=8080 env=prod"
(或 --extra-vars)
动态注入最高优先级变量。支持传递 key=value、JSON 字符串或外部 YAML 变量文件(-e "@vars.yml")。
提权交互式密码 ansible-playbook site.yml -K 手动输入 sudo/become 密码。当受控节点上的普通用户配置了需要输入密码才能 sudo 提权时使用。
详细调试输出 ansible-playbook site.yml -v
(或 -vvv / -vvvv)
增强日志级别。增加 -v 的数量(最多 4 个)来查看模块返回细节、SSH 建立连接过程及底层 Command 细节。
单步确认模式 ansible-playbook site.yml --step 交互式逐步执行。每准备执行一个 Task 前都会暂停,提示用户输入 y(执行)、n(跳过)或 a(中止后续)。

handlers

Handlers(触发器 / 处理器) 是一种特殊类型的 Task(任务),它的核心特点是:“按需触发,延迟执行”。
它最常见的应用场景是:当配置文件发生改动(状态变为 changed)时,才触发重启服务。

Handlers 通常定义在 Play 的 handlers: 关键字下,并由普通 Tasks 中的 notify 关键字来进行触发。

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
---
- name: Configure and restart Apache
hosts: webservers
become: true

tasks:
# --------------------------------------------------------------------------
# Task 1: 部署主配置文件
# --------------------------------------------------------------------------
- name: Copy httpd configuration file
copy:
src: httpd.conf
dest: /etc/httpd/conf/httpd.conf
notify: Restart httpd service # 对应 handler 的 name(必须完全一致)

# --------------------------------------------------------------------------
# Task 2: 部署端口配置文件
# --------------------------------------------------------------------------
- name: Copy ports configuration file
copy:
src: ports.conf
dest: /etc/httpd/conf.d/ports.conf
notify: Restart httpd service # 同样通知该 handler

# ============================================================================
# Handlers 区域(独立于 tasks 之外)
# ============================================================================
handlers:
- name: Restart httpd service # Handler 名称
service:
name: httpd
state: restarted # 执行重启操作

ansible 的变量

列表与字典的概念

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
users:                          <--- 【变量名】指向整个列表

- name: bob <--- 【列表中的元素 1】(一个字典)
job: developer ├── 键: "name" -> 值: "bob"
uid: 1101 ├── 键: "job" -> 值: "developer"
└── 键: "uid" -> 值: 1101

- name: sally <--- 【列表中的元素 2】(一个字典)
job: manager ├── 键: "name" -> 值: "sally"
uid: 1102 ├── 键: "job" -> 值: "manager"
└── 键: "uid" -> 值: 1102

- name: fred <--- 【列表中的元素 3】(一个字典)
job: developer ├── 键: "name" -> 值: "fred"
uid: 1103 ├── 键: "job" -> 值: "developer"
└── 键: "uid" -> 值: 1103

定义变量的方式

类别 定义方式 / 位置 典型语法 / 示例 作用域与特点 优先级排序
1. 命令行变量 Extra Vars (外部变量) ansible-playbook site.yml -e "http_port=8080"
-e "@vars.yml"
全局生效。优先级最高(Level 22),可覆盖其他所有位置定义的同名变量。 最高 (1)
2. Playbook 级变量 vars 关键字 hosts: webservers
vars:
   http_port: 80
Play 内部生效。在 Playbook 顶层显式定义,直观易读。 中 (4)
vars_files 外部文件 hosts: webservers
vars_files:
   - vars/web.yml
Play 内部生效。将变量解耦写在单独的 YAML 文件中,适合多变量管理。 中 (4)
vars_prompt 交互式输入 vars_prompt:
   - name: db_password
      prompt: "Enter DB password"
Play 内部生效。运行时在终端弹窗提示人工手动输入(常用于敏感密码)。 中 (4)
3. Inventory 清单变量 主机变量 (Host Vars) 清单文件 hosts 中:
web01.example.com http_port=8080
或创建文件 host_vars/web01.yml
单台主机生效。针对具体节点单独设置(如某台节点的特有端口或 IP)。 低 (6)
组变量 (Group Vars) 清单文件 hosts 中:
[web:vars]
http_port=80
group_vars/web.yml
特定主机组生效。对整个组内的所有主机生效(如 web 组统一使用 80 端口)。 低 (7)
4. Role (角色) 变量 vars/main.yml Role 目录结构下的 vars/main.yml Role 内部生效。随 Role 调用的高优先级变量,通常存放不希望被用户随意覆盖的内部变量。 中上 (3)
defaults/main.yml Role 目录结构下的 defaults/main.yml Role 内部生效优先级最低(Level 2),作为 Role 的默认兜底值,非常方便调用者二次覆盖。 最低 (8)
5. Task (任务) 级变量 vars 关键字 - name: Install pkg
   dnf: name={{ pkg }}
   vars:
      pkg: nginx
仅当前 Task 生效。作用域极小,专门服务于单个任务。 高 (2)
register 注册变量 - name: Check file
   command: cat /etc/issue
   register: issue_out
后续 Tasks 全局生效。捕获上游 Task 的运行返回结果(包含 stdout, rc, changed 等)。 高 (2)
6. 系统自动采集 Facts 变量 {{ ansible_facts['default_ipv4']['address'] }}
{{ ansible_distribution }}
全局生效。由 setup 模块自动在受控节点采集(如操作系统版本、网卡 IP、内存等)。 特殊 (预定义)

fact var 事实变量

收集与查看

用于探知、查看受控节点的系统客观状态,以及控制剧本执行时的采集行为。

操作类型 核心命令 / 语法位置 代码示例 说明与最佳实践
命令行查看全量 Fact Ad-hoc setup 模块 ansible node1 -m setup 连接目标主机,实时收集并打印结构化的全量 JSON 格式系统信息。
命令行过滤特定 Fact Ad-hoc setup 模块 + filter ansible node1 -m setup -a "filter=ansible_default_ipv4"
ansible node1 -m setup -a "filter=ansible_distribution*"
使用通配符对返回结果进行精准筛选,避免全量输出刷屏,常用于调试或排查变量名。
Playbook 自动采集 (默认) Play 顶层 gather_facts - hosts: webservers
   gather_facts: true
Play 运行的第 1 步自动执行 setup 模块。如果 Task 或 Template 中需要使用系统变量,必须保证此选项为 true
关闭采集以提升性能 Play 顶层 gather_facts - hosts: webservers
   gather_facts: false
如果剧本纯粹用于执行命令、复制文件等不依赖系统变量的任务,置为 false 可省去连接采集过程,显著提升执行速度。
剧本中途手动重新采集 Task 模块 setup - name: Re-gather facts after network change
   setup:
如果前面的 Task 修改了系统配置(如修改了主机名或配置了网卡 IP),可在 Task 中显式调用 setup 刷新 Fact 字典。

set_fact 模块

用于在 Playbook 执行过程中,将计算好的值、拼接的字符串或 Task 返回值即时固化为新的 Fact 变量。

功能/特性 语法结构 代码示例 关键注意事项
基础变量定义 set_fact:
   <var_name>: <value>
- name: Set environment fact
   set_fact:
      app_env: "production"
定义的变量会直接注入当前主机的 Fact 字典中,作用域为当前主机后续的所有 Tasks
结合现有 Fact 组合新变量 配合 Jinja2 表达式 - name: Build custom node ID
   set_fact:
      node_id: "{{ ansible_hostname }}-{{ ansible_default_ipv4.address }}"
相比在 vars 中定义,set_fact 会在当前 Task 执行的瞬间进行即时求值并固化,后续调用时不会重复计算。
配合条件判断 (when) set_fact + when - name: Set package name based on OS
   set_fact:
      web_pkg: "httpd"
   when: ansible_os_family == "RedHat"
极适合根据受控节点的系统差异(如 OS 家族、内存大小),动态赋予变量不同的值。
变量逻辑兜底 结合 Jinja2 default 过滤器 - name: Set safe IP fact
   set_fact:
      listen_ip: "{{ ansible_default_ipv4.address \| default('127.0.0.1') }}"
防止目标主机缺乏某个特定 Fact(如无默认网卡)导致后续 Tasks 发生未定义变量错误。

lookup

用于在控制节点(Control Node)端读取外部数据(如文件、环境变量、Vault 密钥等),通常与 set_fact 结合将外部数据转化为受控节点的 Fact。

数据源类型 lookup 语法格式 代码示例 (结合 set_fact) 执行位置与应用场景
读取控制节点文件 lookup('file', '<path>') - set_fact:
      pub_key: "{{ lookup('file', '~/.ssh/id_rsa.pub') }}"
控制节点端执行。把控制节点本地的文件内容读取并存入变量,方便后续 copyauthorized_key 模块使用。
读取控制节点环境变量 lookup('env', '<VAR_NAME>') - set_fact:
      deploy_token: "{{ lookup('env', 'CI_JOB_TOKEN') }}"
控制节点端执行。常用于 CI/CD 流水线中提取 GitLab/GitHub Actions 注入的环境变量。
读取模板渲染内容 lookup('template', '<path>') - set_fact:
      rendered_config: "{{ lookup('template', './nginx.j2') }}"
控制节点端执行。直接把 Jinja2 模板渲染后的纯文本内容存在变量中,无需直接写出到磁盘。
查找通配符文件列表 lookup('fileglob', '<pattern>') - set_fact:
      cert_files: "{{ lookup('fileglob', 'certs/*.crt') }}"
控制节点端执行。返回控制节点匹配指定通配符的文件路径列表(逗号分隔)。

自定义事实变量

通过在目标主机放置静态 .fact 文件或动态脚本,扩展 Ansible 的事实采集能力,将业务相关的元数据存入 ansible_local 命名空间。

维度 配置/调用方式 代码/结构示例 说明与最佳实践
受控节点存储路径 固定目录规范 /etc/ansible/facts.d/ 必须在目标主机上创建此目录。路径下的所有 .fact 格式文件都会被 setup 模块自动扫描并解析。
静态配置文件 (INI 格式) /etc/ansible/facts.d/app.fact [settings]
max_connections=500
role=web_primary
解析后生成的变量层级为:
ansible_local.app.settings.max_connections
静态配置文件 (JSON 格式) /etc/ansible/facts.d/datacenter.fact {\n "dc_name": "shanghai-zone-a",\n "rack_id": 102\n} 解析后生成的变量层级为:
ansible_local.datacenter.dc_name
动态生成脚本 可执行脚本 (需加 chmod +x) #!/bin/sh
echo "{\"uptime_seconds\": $(cut -d' ' -f1 /proc/uptime)}"
必须输出合法的 JSON 格式。每次 Ansible 采集 Facts 时会自动运行该脚本并捕获标准输出。
在 Playbook 中调用 统一前缀 ansible_local - debug:
      msg: "Server is in {{ ansible_local.datacenter.dc_name }}"
变量统一存放在 ansible_local.<文件名(无后缀)>.<内部层级> 中。

magic var 魔法变量

四种魔法变量

魔法变量名 类型/数据结构 主要作用与说明 常见使用场景与语法示例
inventory_hostname 字符串 (String) 当前任务正在运行的目标主机标识
即在 Inventory 清单中为该主机定义的别名或名称,不受受控端系统真实主机名修改的影响。
单个节点独有配置/标识
· 动态生成节点专属文件:path: "/etc/app/{{ inventory_hostname }}.conf"
· 作为字典的主键在模板中查找数据。
group_names 列表 (List) 当前主机所在的所有主机组名称集合
按当前运行的主机视角,列出它在 Inventory 中被分配到了哪些组。
按节点角色/组别进行条件过滤
when: "'webservers' in group_names"
(当且仅当当前主机属于 webservers 组时才执行任务)。
groups 字典 (Dictionary) 全量 Inventory 清单的“组-主机”映射表
包含了清单中定义的所有组名称,以及各个组内包含的所有主机列表({ 组名: [主机1, 主机2...] })。
获取指定组内的全量主机列表
在 Jinja2 模板中循环渲染集群节点:
{% for host in groups['db_servers'] %}`
   `server {{ host }};`
`{% endfor %}
hostvars 字典 (Dictionary) 跨主机数据检索聚合表
包含了所有主机的变量与 Fact 数据(格式为 { 主机名: { 变量名: 变量值 } }),允许当前主机跨节点读取其他主机的变量
跨节点提取配置(如提取数据库节点的 IP)
{{ hostvars['db01']['ansible_default_ipv4']['address'] }}
或结合 groups 遍历生成负载均衡/集群 Upstream 配置。

联合使用的场景

假设清单中包含 webserversdbservers 两个组。

业务逻辑:在数据库节点(dbservers)上配置访问限制,允许所有 Web 节点(webservers)的 IP 访问;如果其中某个 Web 节点正好就是当前运行 Task 的数据库节点自身(即单机兼任两角),则额外打上本地环回标记。

  1. 主机清单
1
2
3
4
5
6
7
[webservers]
web01 ansible_host=192.168.1.11
web02 ansible_host=192.168.1.12

[dbservers]
db01 ansible_host=192.168.1.21
web01 # web01 既是 web 也是 db
  1. Playbook
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- name: 组合使用 4 个魔法变量配置数据库访问白名单
hosts: all
gather_facts: true

tasks:
- name: 仅在数据库节点上打印允许访问的 Web 节点列表
# 1. 使用 group_names 判断:只有当前主机属于 dbservers 组时才执行此 Task
when: "'dbservers' in group_names"
debug:
msg:
- "当前正在配置的主机 (inventory_hostname): {{ inventory_hostname }}"
- "允许访问本数据库的 Web 节点 (来自 groups): {{ item }}"
- "该 Web 节点对应的 IP 地址 (来自 hostvars): {{ hostvars[item]['ansible_host'] }}"
- "特殊标记: {{ '【注意:该 Web 节点就是本机自身】' if item == inventory_hostname else '【远程 Web 节点】' }}"
# 2. 使用 groups 获取 webservers 组里的所有主机列表进行循环
loop: "{{ groups['webservers'] }}"
loop_control:
label: "{{ item }}" # 简化终端输出展示

ansible 的条件判断

在 Ansible 中,when 是用于控制 Task(任务)是否执行的条件判断关键字。

它的作用类似于编程语言中的 if 语句:只有当 when 后面的条件计算结果为 True(真)时,Ansible 才会执行该任务;如果条件为 False(假),Ansible 会直接跳过(Skipped)该任务。

比较运算符

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
- name: 综合比较运算符应用示例
hosts: all
gather_facts: true # 默认
tasks:
- name: 检查并部署高可用 Web 节点
debug:
msg: "系统满足高可用 Web 节点部署条件!"
when:
# 1. 成员关系判断 (in):当前主机必须属于 webservers 组
# group_names 是一个列表,单台主机可以同时属于多个组
- "'webservers' in group_names"
# 2. 数值转换与逻辑比较 (>=):总物理内存必须大于等于 4096MB (4GB)
# 通过管道符 | int 将其强制转换为整数,再与 4096 进行数值比较
- (ansible_memtotal_mb | int) >= 4096
# 3. 逻辑非与变量状态测试 (not / is defined):系统未处于维护模式
# 管道符 | bool 将其强转为布尔值
- not (is_maintenance_mode is defined and is_maintenance_mode | bool)
# 4. 正则搜索匹配 (is search):主机名必须以 shanghai-web 或 beijing-web 开头
- inventory_hostname is search("^(shanghai|beijing)-web")

基础比较运算符

运算符 名称 / 含义 示例表达式 规则与说明
== 等于 ansible_distribution == "Ubuntu" 判断两端的值是否完全一致(区分大小写)。
!= 不等于 ansible_os_family != "RedHat" 判断两端的值是否不相等。
> 大于 ansible_processor_vcpus > 4 通常用于数值比较。若用于字符串,则按字典序比较。
< 小于 memtotal_mb < 2048 通常用于数值比较。
>= 大于或等于 ansible_memtotal_mb >= 8192 数值或字符顺序比较。
<= 小于或等于 ansible_distribution_major_version | int <= 7 常配合 | int 过滤器将字符串版本号转换为整数后再比较。

包含关系运算符

运算符 名称 / 含义 示例表达式 常见应用场景
in 包含于 "webservers" in group_names 判断元素是否存在于列表中,或子串是否存在于字符串中。
· 判断主机所属组:"'db' in group_names"
· 检查输出信息:"'success' in result.stdout"
not in 不包含于 "prod" not in inventory_hostname 判断元素或子串不存在于目标集合/字符串中。

逻辑运算符

运算符 含义 示例表达式 说明
and 逻辑与 ansible_os_family == "RedHat" and ansible_distribution_major_version == "8" 多个条件必须同时满足。在 when 中也可以写成列表形式(列表项之间默认即为 and 关系)。
or 逻辑或 'web' in group_names or 'lb' in group_names 多个条件满足其一即可。
not 逻辑非 not (is_production | default(false) | bool) 对后面的布尔值或表达式结果取反。

register 注册变量

register 是 Ansible 中用于将某个任务(Task)的执行结果保存到一个自定义变量中的关键字,以便后续任务随时读取和判断。

.rc 是 Return Code(返回码 / 退出状态码) 的缩写。
当使用 shellcommandscript 等模块在目标主机上执行了一条 Linux 命令,并使用 register 关键字将执行结果保存到一个变量中时,这个变量实际上是一个包含许多详细信息的字典(对象)。其中,.rc 专门用来记录那条命令执行后的状态。

在 Linux 和 Ansible 的标准规范中:

  • .rc == 0:代表命令执行成功。
  • .rc != 0(例如 1, 2, 127 等):代表命令执行失败或出现错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- name: 演示 register 的用法
hosts: localhost
# connection: local 不要通过 SSH 连接到远程受控节点,而是直接在本地机器上执行该任务。
connection: local
tasks:
# Task 1: 执行命令并把结果存入变量 my_ip
- name: 获取当前机器的公网 IP
command: curl -s ifconfig.me
register: my_ip

# Task 2: 读取上一步保存的结果
- name: 打印获取到的 IP 地址
debug:
msg: "当前机器的公网 IP 是:{{ my_ip.stdout }}"
when: my_ip.rc == 0 # 只有上一步执行成功(返回码为0)时才打印

错误处理机制

  • block(主任务块): 存放主要业务逻辑的任务集合。只要其中任何一个 task 执行失败(Failed),后续的 block 任务将立即中断,并跳转至 rescue
  • rescue(错误捕获与补救): 类似于编程语言中的 catch。只有当 block 内部发生错误时才会执行,通常用于日志记录、服务回滚(Rollback)或故障告警。若 rescue 内的任务成功执行,整个 Task 块将被 Ansible 认定为已恢复(State: OK)。
  • always(必须执行): 类似于编程语言中的 finally。无论 block 成功执行,还是触发了 rescue,抑或是发生严重错误,always 里的任务都保证会被无条件执行,常用于环境清理、状态重置或释放锁。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
- name: Ansible 错误处理机制示例 (Block / Rescue / Always)
hosts: localhost
gather_facts: no
tasks:
- name: 执行部署逻辑区块
block:
- name: 步骤 1:尝试执行可能失败的任务
command: ls /path/to/non_existent_file
register: task_result

- name: 步骤 2:如果步骤 1 成功,则继续执行
debug:
msg: "主任务执行成功!"

rescue:
- name: 补救措施:当 Block 内任何任务报错时触发
debug:
msg: "捕获到 Block 内部任务报错!正在执行回滚或补救操作..."

always:
- name: 收尾工作:无论成功还是失败,必定会执行
debug:
msg: "清理临时文件,释放资源。"

playbook 循环语句

关键字 支持数据类型 核心适用场景 循环变量语法 历史与当前状态
loop 列表 (List) 现代推荐标准。配合过滤器(如 dict2itemsflatten 等)可处理任何数据结构。 {{ item }} 现代标准(Ansible 2.5+ 引入,官方推荐首选)
with_items 列表 (List) / 嵌套列表 自动展平单层嵌套列表。 {{ item }} 传统 Lookup(逐渐被 loop + flatten 替代)
with_dict 字典 (Dictionary) 直接遍历字典的键值对。 {{ item.key }} / {{ item.value }} 传统 Lookup(逐渐被 loop + dict2items 替代)
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
35
---
- name: 演示 with_items, with_dict loop 的用法
hosts: localhost
gather_facts: no
vars:
# 供 with_items 使用的嵌套列表
packages_list:
- ['curl', 'wget']
- ['git']

# 供 with_dict 使用的字典
user_roles:
alice: "admin"
bob: "developer"

# 供 loop 使用的标准列表
service_names:
- nginx
- redis

tasks:
- name: Task 1 - 使用 with_items 遍历并自动展平列表
debug:
msg: "安装软件包: {{ item }}"
with_items: "{{ packages_list }}"

- name: Task 2 - 使用 with_dict 遍历字典键值对
debug:
msg: "用户 {{ item.key }} 的角色是 {{ item.value }}"
with_dict: "{{ user_roles }}"

- name: Task 3 - 使用 loop 遍历标准列表 (现代标准写法)
debug:
msg: "重启服务: {{ item }}"
loop: "{{ service_names }}"

Jinja2

jinja2 模板

在 Ansible 中,Jinja2 是内置的模板引擎(Template Engine)。它的核心作用是将静态的配置文件转换为动态模板,通过结合 Ansible 的变量、Facts(系统信息)以及逻辑判断,在部署时动态生成符合目标主机环境的定制配置文件。

Ansible 通常使用 template 模块 来处理以 .j2 为后缀的 Jinja2 模板文件(如 nginx.conf.j2),渲染后再分发到目标主机的指定位置。

  • 示例 Jinja2 模板文件 app.ini.j2
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
{# ==================== INI 模板文件 ==================== #}
[global]
; 1. 格式 & 简单引用:直接输出 Playbook 变量和系统的 Facts 信息
app_name = {{ app_name }}
host_ip = {{ ansible_default_ipv4.address | default('127.0.0.1') }}

; 2. 条件判断 (if/else):根据环境类型(environment_type)动态决定配置
{% if environment_type == 'production' %}
debug = false
log_level = ERROR
{% else %}
debug = true
log_level = DEBUG
{% endif %}

[database]
; 3. 条件判断 (if):判断可选变量是否定义,定义了才渲染出连接串
{% if db_host is defined %}
db_url = mysql://{{ db_user }}:{{ db_pass }}@{{ db_host }}:3306/{{ db_name }}
{% endif %}

[redis_cluster]
; 4. 循环 (for) + -% 消除空行:遍历 Redis 节点列表,生成节点清单
; {%- 和 -%} 可以吃掉多余的换行符,保证 INI 文件的格式整洁
{% for node in redis_nodes -%}
node_{{ loop.index }} = {{ node.ip }}:{{ node.port }}
{% endfor -%}
  • 示例 Playbook 文件
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
- name: 演示 Jinja2 模板在 INI 配置文件中的渲染
hosts: localhost
gather_facts: yes # 开启 Facts 采集,以便获取目标机的 IP (ansible_default_ipv4)

vars:
# --- 全局基础变量 ---
app_name: "MyCoreService"
environment_type: "production" # 可选: production 或 development

# --- 数据库变量(测试 is defined 逻辑)---
db_host: "192.168.1.100"
db_user: "app_user"
db_pass: "SecretPass123"
db_name: "prod_db"

# --- 列表变量(供 for 循环遍历使用)---
redis_nodes:
- { ip: "10.0.0.1", port: 6379 }
- { ip: "10.0.0.2", port: 6379 }
- { ip: "10.0.0.3", port: 6380 }

tasks:
- name: 渲染 Jinja2 模板并生成最终的 INI 配置文件
template:
src: app.ini.j2 # 本地/控制端上的 .j2 模板文件路径
dest: /tmp/app.ini # 目标主机上最终生成的 INI 文件路径
mode: '0644' # 设置生成文件的系统权限
  • 渲染后的文件 app.ini
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[global]
; 1. 格式 & 简单引用:直接输出 Playbook 变量和系统的 Facts 信息
app_name = MyCoreService
host_ip = 192.168.1.10

; 2. 条件判断 (if/else):根据环境类型(environment_type)动态决定配置
debug = false
log_level = ERROR

[database]
; 3. 条件判断 (if):判断可选变量是否定义,定义了才渲染出连接串
db_url = mysql://app_user:SecretPass123@192.168.1.100:3306/prod_db

[redis_cluster]
; 4. 循环 (for) + -% 消除空行:遍历 Redis 节点列表,生成节点清单
; {%- 和 -%} 可以吃掉多余的换行符,保证 INI 文件的格式整洁
node_1 = 10.0.0.1:6379
node_2 = 10.0.0.2:6379
node_3 = 10.0.0.3:6380

Jinja2 过滤器

过滤器名称 功能解释 常见参数 / 选项 使用示例 渲染/执行结果
default
(或 d)
当变量未定义(默认)或为假值时,返回指定的默认值,防止因变量缺失导致 Playbook 报错中断。 default_value: 变量缺失时使用的回退值(必填)
boolean: 设为 true 时,即便变量已定义,但值为空字符串 ""Nonefalse 等假值时也会触发默认值(可选,默认 false
{{ http_port | default(8080) }}

{{ custom_title | default('Untitled', true) }}
http_port 未定义 → 8080

custom_title""Untitled
password_hash 将明文密码转换为目标系统(如 Linux /etc/shadow 或 htpasswd)支持的加密哈希散列值 hashtype: 哈希算法,如 sha512(默认)、sha256md5blowfish
salt: 自定义盐值(可选,留空则自动生成随机盐)
{{ 'MySecretPass' | password_hash('sha512') }}

{{ 'MySecretPass' | password_hash('sha512', 'mycustomsalt') }}
输出形如 $6$rounds=65536$... 的加盐哈希串(常用于 user 模块创建系统用户密码)
dict2items 字典(Dict)转换为键值对列表(List of K/V Dicts)。常与 loop 配合使用,替代传统的 with_dict key_name: 自定义输出列表中表示“键”的字段名(默认 'key'
value_name: 自定义输出列表中表示“值”的字段名(默认 'value'
输入变量:
users: { alice: admin, bob: dev }

模板调用:
{{ users | dict2items }}
转换结果:
[
   {'key': 'alice', 'value': 'admin'},
   {'key': 'bob', 'value': 'dev'}
]

角色与集合

在项目根目录或家目录下创建/修改 ansible.cfg,配置 roles_pathcollections_path

1
2
3
4
5
6
7
[defaults]
# 指定 Roles 的搜寻路径,多个路径用冒号 : 分隔
# 查找顺序:从左到右依次查找
roles_path = ./roles

# 指定 Collections 的搜寻路径
collections_path = ./collections

ansible-galaxy 常用命令

ansible-galaxy 是 Ansible 官方提供的一个命令行包管理工具,同时也是红帽官方运维社区的开源组件共享平台(类似 Python 的 pip、Node.js 的 npm 或 Linux 的 apt/dnf)。

简单来说,它的核心作用有两个:“自己造轮子时帮你建模板”,以及“不想重造轮子时帮你找现成的代码”。

功能分类 常用命令 参数说明与示例 适用场景 / 核心用途
初始化角色 ansible-galaxy role init <role_name> <role_name>:角色目录路径
例如:ansible-galaxy role init roles/webserver
一键生成包含 tasks, vars, templates 等目录的标准 Role 文件夹结构。
搜索角色 ansible-galaxy search <keyword> --author <author>:按作者检索
例如:ansible-galaxy search nginx --author geerlingguy
在 Galaxy 线上平台或配置的私有仓库中搜索可用的 role。
安装角色 ansible-galaxy role install <author.role_name> -p <path>:指定安装保存的本地路径
例如:ansible-galaxy role install geerlingguy.nginx -p ./roles
从 Galaxy 平台下载指定社区 Role 到本地项目。
角色列表 ansible-galaxy role list -p <path>:指定查看的 Roles 目录 列出本地或特定路径下已经安装的所有 Role 及其版本号。
安装集合 ansible-galaxy collection install <namespace.collection> --force:强制重新下载覆盖
例如:ansible-galaxy collection install community.general
安装包含特殊模块或插件的 Ansible Collection 扩展包。
集合列表 ansible-galaxy collection list 例:ansible-galaxy collection list 列出当前 Python/Ansible 环境中已安装的所有 Collection。
安装依赖 ansible-galaxy install -r <file> -r <file>:指定清单文件,默认为 requirements.yml
-p <path>:指定 Roles 安装安装目录
根据配置文件批量安装项目中定义的所有 Roles 和 Collections(RHCE 考试与 CI/CD 必考)。

角色 Role

在 Ansible 中,Role(角色) 是将变量、任务、模板、处理程序(Handlers)等按标准目录结构组织起来的“可复用模块”。它能够让你把复杂的 Playbook 拆解为结构清晰、易于维护的代码块。

rhel-system-roles.noarch 是 RHEL 官方提供的一个 RPM 软件包,包含了一套由红帽官方编写、测试和维护的 Ansible Roles 和 Collections,专门用来帮运维人员通过自动化方式快速配置 Linux 系统的各项核心功能(如网络、防火墙、存储、时间同步、SELinux 等)。

  • Role 的文件结构
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
项目根目录/
├── ansible.cfg
└── roles/webserver/
├── defaults/
│ └── main.yml # 最低优先级的默认变量(建议在此写基础默认配置)
├── vars/
│ └── main.yml # 高优先级的变量(不希望被轻易覆盖的固定变量)
├── tasks/
│ └── main.yml # 核心:角色要执行的任务列表(入口)
├── handlers/
│ └── main.yml # 触发器:如配置文件修改后重启服务的任务
├── templates/
│ └── nginx.conf.j2 # 存放 Jinja2 模板文件(如配置文件模板)
├── files/
│ └── index.html # 存放静态文件(使用 copy 模块直接下发的文件)
├── meta/
│ └── main.yml # 角色的元数据(如作者、许可证、依赖的其他 Role)
└── README.md # 角色的说明文档
  • 在 Playbook 调用 Role
1
2
3
4
5
6
- name: 部署 Web 服务器
hosts: webservers
become: true

roles:
- webserver # <--- 这里直接写文件夹名字 webserver

集合 Collection

Ansible Collections(集合)是从 Ansible 2.9 版本开始引入的标准化包管理格式,也是目前 Ansible 社区和官方推荐的最高层级代码分发与打包机制。

  • Collection 的文件结构
1
2
3
4
5
6
7
8
9
10
11
12
13
项目根目录/
├── ansible.cfg
└── collection/my_namespace/my_collection
├── docs/ # 文档
├── plugins/ # 核心:自定义扩展插件
│ ├── modules/ # 自定义 Ansible 模块 (如 Python 写的 Task 模块)
│ ├── lookup/ # 查找插件
│ └── filter/ # 自定义 Jinja2 过滤器
├── roles/ # 核心:包含的多个标准化 Roles
│ ├── webserver/
│ └── database/
├── playbooks/ # 预置的 Playbook 剧本
└── meta/runtime.yml # 元数据与依赖说明

ansible-vault 加密

Ansible Vault 常用指令与核心概念速查表

功能分类 常用命令 参数说明与示例 适用场景 / 核心用途
文件创建 ansible-vault create <file> <file>:新建的加密 YAML 文件路径
例:ansible-vault create vars/secrets.yml
从零创建一个全新的密文文件(会自动弹出文本编辑器提示输入并确认密码)。
文件编辑 ansible-vault edit <file> 例:ansible-vault edit vars/secrets.yml 安全地解密并打开现有的加密文件进行编辑,保存退出后自动重新加密。加密过的文件不能使用 vim 编辑。
现有文件加密 ansible-vault encrypt <file> --vault-id <id>:可选,指定特定的密钥标识
例:ansible-vault encrypt vars/db_passwords.yml
将已存在的明文 YAML 变量文件直接加密转化为密文形态。
现有文件解密 ansible-vault decrypt <file> --output=<new_file>:解密并另存为新文件
例:ansible-vault decrypt vars/db_passwords.yml
将加密文件永久还原为明文格式(生产环境中请谨慎使用)。
密钥查看与管理 ansible-vault view <file> 例:ansible-vault view vars/secrets.yml 在终端直接只读查看加密文件的明文内容,不会在磁盘上留下解密文件
密码变更 ansible-vault rekey <file> 例:ansible-vault rekey vars/secrets.yml 修改加密文件的解密密码(需先输入旧密码,再输入新密码)。
字符串级加密 ansible-vault encrypt_string '<text>' --name '<var_name>':指定变量名
例:ansible-vault encrypt_string 'MySecretPass' --name 'db_password'
仅加密单个敏感变量值(如密码或 API Token),输出格式可直接粘贴进普通明文 YAML 文件中。
Playbook 运行解密 ansible-playbook --ask-vault-pass 例:ansible-playbook -i inventory site.yml --ask-vault-pass 运行含有 Vault 加密内容的剧本时,在终端交互式提示输入解密密码(RHCE 常用)。
ansible-playbook --vault-password-file <path> 例:ansible-playbook site.yml --vault-password-file ~/.vault_pass 运行剧本时从指定的明文密码文件或可执行脚本中自动获取密钥(适合 CI/CD 自动化)。

ansible-navigator 导航器

ansible-navigator 的核心设计理念是“开发与运行环境解耦”。它不再直接利用宿主机(Control Node)本地的 Python 或 Ansible 环境,而是将运行所需的所有依赖(Ansible Core、模块、Collections、系统依赖等)打包在一个标准的容器镜像——执行环境(Execution Environment, 简称 EE) 中运行。

graph TD
    A[用户终端 CLI/TUI] -->|1. 执行 ansible-navigator| B[ansible-navigator Engine]

    subgraph Host [控制节点]
        B -->|2. 读取项目文件| C[项目目录: Playbook/ansible.cfg/Vault/SSH Key]
        B -->|3. 启动并挂载文件| D[容器引擎 Podman / Docker]
    end

    subgraph EE [执行环境容器 EE]
        D -->|4. 运行容器| E[ansible-runner]
        E --> F[Ansible Core]
        F --> G[容器内预装的 Collections / Python 包]
    end

    subgraph Managed [被控节点]
        F -->|5. SSH / WinRM 发送指令| H[目标服务器 1]
    end

    E -.->|6. 返回 TUI 结果 / 生成 Artifact JSON| A

常用命令

功能分类 子命令 / 命令行指令 常用参数与示例 核心用途与作用
剧本运行 ansible-navigator run <playbook.yml> -m stdout:切回传统终端输出模式
--eei <image_name>:指定 EE 镜像
例如:ansible-navigator run site.yml -m stdout
在 EE 容器中执行 Playbook,默认进入交互式 TUI 界面查看任务进度。
文档查阅 ansible-navigator doc <module_name> -t plugin_type:查看特定类型插件
例如:ansible-navigator doc ansible.builtin.copy
替代传统的 ansible-doc,从 EE 镜像内实时查阅模块/插件的参数与 Example。
环境与镜像管理 ansible-navigator images 例:ansible-navigator images 交互式浏览本地及配置仓库中的 EE 镜像列表、内置 Python 包及 Collections 版本。
ansible-navigator exec <command> 例:ansible-navigator exec -- ansible --version 直接在 EE 容器环境内部执行原生的 Ansible 底层指令(如 ansible-playbookansible)。
配置管理 ansible-navigator config 例:ansible-navigator config 查看或交互式排查当前生效的 Ansible 配置文件(ansible.cfg)参数与解析路径。
ansible-navigator --help-config 例:ansible-navigator --help-config > ansible-navigator.yml 快速生成带有详细注释的 ansible-navigator.yml 默认配置文件模板。
清单文件管理 ansible-navigator inventory -i <inventory_file>:指定主机清单
例如:ansible-navigator inventory -i inventory
交互式树状浏览、校验与审查主机清单(Inventory)的主机分组与变量设置。
历史记录复盘 ansible-navigator replay <artifact.json> 例:ansible-navigator replay artifact.json 重新加载并交互式浏览先前运行 Playbook 时自动生成的 Artifact(JSON 格式日志)历史。
环境信息诊断 ansible-navigator builder 例:ansible-navigator builder 辅助查阅与诊断容器镜像构建工具 ansible-builder 的运行状态与环境属性。

配置文件

navigator.ymlansible-navigator 工具的核心配置文件。

如果把 ansible.cfg 比作 Ansible 自动化逻辑与引擎的配置文件(控制主机清单路径、并发数、SSH 连接参数等),那么 ansible-navigator.yml 就是执行环境(Execution Environment, EE)与界面交互的配置文件

ansible-navigator.yml 绝大多数情况下都直接与 ansible.cfg 放置在同一个目录下

  • ansible-navigator.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
35
36
37
38
39
# ansible-navigator 的核心配置根节点
ansible-navigator:
# -------------------------------------------------------------------
# 1. 运行模式与输出设置 (Execution & Mode)
# -------------------------------------------------------------------
mode: stdout # 运行模式:可选 'stdout' (传统终端日志模式) 或 'interactive' (TUI 交互界面)
# 💡 建议设为 stdout,排错更直观,行为与经典 ansible-playbook 保持一致

# -------------------------------------------------------------------
# 2. 执行环境容器设置 (Execution Environment - EE)
# -------------------------------------------------------------------
execution-environment:
enabled: true # 是否启用容器环境运行 (默认为 true)
container-engine: podman # 指定容器引擎:可选 'podman' 或 'docker' (RHCE/RHEL 默认使用 podman)
image: registry.redhat.io/ansible-automation-platform-24/ee-supported-rhel8:latest
# 指定运行 Playbook 所使用的 EE 容器镜像路径
pull:
policy: missing # 镜像拉取策略:可选 'missing' (不存在才拉取)、'always' (总是拉取)、'never' (仅使用本地镜像)

# 容器目录挂载配置 (用于将宿主机的文件/目录映射到容器内部)
volume-mounts:
- src: "/etc/ansible" # 宿主机源路径
dest: "/etc/ansible" # 容器内目标路径
options: "Z" # 挂载选项:在开启 SELinux 的系统上,必须加上 "Z" (私有标签) 或 "z" (共享标签) 以避免权限拒绝

# -------------------------------------------------------------------
# 3. 关联 Ansible 引擎参数 (Ansible Core Configuration)
# -------------------------------------------------------------------
ansible:
config:
path: ./ansible.cfg # 显式指定使用的 ansible.cfg 配置文件路径 (默认会优先寻找当前目录下的 ansible.cfg)

# -------------------------------------------------------------------
# 4. 运行日志与 Artifact 历史记录 (Logging & Artifacts)
# -------------------------------------------------------------------
playbook-artifact:
enable: true # 是否在运行完毕后生成 JSON 格式的执行结果日志 (Artifact)
save-as: ./artifacts/{playbook_name}-artifact-{time_stamp}.json
# 指定 Artifact 文件的保存路径与命名模板