RHCE 学习笔记(一):Ansible 配置、ad-hoc 命令与 Playbook
学习红帽课程中的一些笔记,本系列共 2 篇,这是第 1 篇。
- RHCE 学习笔记(一):Ansible 配置、ad-hoc 命令与 Playbook(本篇)
- RHCE 学习笔记(二):变量、流程控制、Jinja2、角色、Vault 与 Navigator
认识 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 | yum install -y python3-pip |
- 通过源码包安装
1 | wget https://releases.ansible.com/ansible/ansible-2.9.0.tar.gz |
ansible 配置和使用
ansible.cfg 配置文件
配置优先级:
- (最高)
ANSIBLE_CONFIG环境变量指定的ansible.cfg位置(默认无)。 - 当前运行
ansible或ansible-navigator命令时所在的目录下的ansible.cfg。 - 用户家目录下的
~/.ansible.cfg,注意文件名前面有个点.。 - (最低) 系统默认全局路径
/etc/ansible/ansible.cfg,通过 RPM/Dnf 安装 Ansible 时生成的系统级默认配置文件。
| 区块名称 | 配置项 | 常见可选值 / 默认值 | 作用与配置说明 |
|---|---|---|---|
[defaults](基础通用配置) |
inventory |
./inventory/etc/ansible/hosts |
指定默认的主机清单(Inventory)文件路径或目录。 |
remote_user |
rootdevops (自定义) |
指定 Ansible 在受控节点上默认使用的 SSH 登录用户名。如果没有指定则以当前用户名登录远程主机。 | |
ask_pass |
FalseTrue |
SSH 登录受控节点时是否强制弹窗提示输入 SSH 密码(相当于 -k,密码登录时必须要有此项)。配合 SSH 公钥免密时设为 False。 |
|
host_key_checking |
FalseTrue |
首次连接受控节点时是否检查对方的 SSH Host Key。建议设为 False 避免交互式确认卡死。 |
|
forks |
5 (默认)1050 |
Ansible 并发执行任务的最大受控节点数量(进程池大小)。 | |
roles_path |
./roles/roles |
指定 Ansible 自动查找角色(Roles)的目录路径列表(多个路径用 : 分隔)。 |
|
log_path |
./ansible.log |
指定 Ansible 执行日志的存储路径(默认不留存文件日志)。 | |
[privilege_escalation](提权配置) |
become |
TrueFalse |
是否在登录受控节点后自动进行权限提升(提权)。 |
become_method |
sudosu |
指定提权的方式,几乎所有 Linux 环境均使用 sudo。 |
|
become_user |
root |
指定提权目标到的用户身份。 | |
become_ask_pass |
FalseTrue |
执行提权命令时是否弹窗提示输入 sudo 密码。设为 False 需配合受控节点 NOPASSWD: 配置。 |
|
[ssh_connection](连接优化) |
pipelining |
TrueFalse |
是否开启 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=0440 为 sudo 读取的硬性权限要求。 |
| 6. 修改本地 ansible.cfg | 编辑项目目录下的 ansible.cfg:[defaults]inventory = ./hostsremote_user = ansible-userhost_key_checking = Falseask_pass = False[privilege_escalation]become = Truebecome_method = sudobecome_user = rootbecome_ask_pass = False |
指定远程用户;明确关闭 ask_pass 与 become_ask_pass 密码询问,实现完全无人值守。 |
| 7. 最终连通与提权验证 | ansible all -m command -a 'id' |
验证控制节点使用 SSH 密钥登录 + 提权双重免密通道完全打通。 |
编辑 inventory 主机清单
ansible.cfg 中 inventory 字段指定的 inventory(主机清单)文件,用于定义 Ansible 所管理的受控节点。它可以是简单的 INI 格式或 YAML 格式。
1 | # 未分组主机 (Ungrouped Hosts) |
选择主机清单中的主机
| 选择需求 | 命令行写法 | 说明 / 匹配逻辑 |
|---|---|---|
| 选择所有主机 | 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: 权限(如 0644、0440)• 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 格式编写
- 基本文件结构:
- 文件开头:通常以三个连字符
---开头,表示 YAML 文档的开始(可省略)。 - 列表(List):用短横线加空格
- 表示一个元素。Playbook 的最外层本质上就是一个 Play 的列表。 - 键值对(Dictionary):使用
key: value格式,冒号后必须有一个空格。
- 文件开头:通常以三个连字符
- 三级层级关系:
- Play(剧本):定义在哪些主机(
hosts)上执行,以及以什么身份(become)执行。 - Tasks(任务列表):每个 Play 包含一个
tasks列表,按顺序向下执行。 - Module(模块及其参数):每个 Task 调用一个 Ansible 模块,并传入相应的参数。
- Play(剧本):定义在哪些主机(
- 缩进规则:
- 严格禁止使用 Tab 键,必须使用纯空格(建议统一使用 2 个空格作为一个缩进层级)。
- 同一层级的元素必须左对齐。
1 | # ============================================================================== |
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 | --- |