【Day 73】Linux-自动化工具-Ansible
一、自动化工具
在自动化运维领域,Puppet、Ansible、SaltStack 是主流的三款工具,均能实现 “批量管控、配置管理、任务编排” 核心需求,但在架构设计、使用场景、操作复杂度上差异显著。
维度 | Puppet | Ansible | SaltStack |
---|---|---|---|
核心定位 | 企业级配置管理 | 轻量级自动化工具 | 分布式混合工具 |
开发语言 | Ruby | Python | Python |
架构模式 | 主从架构(C/S) 需 Agent 常驻 | 无服务架构(无 C/S) 基于 SSH/API | 混合架构(支持 C/S Agent 模式、无 Agent 模式) |
默认通信协议 | HTTPS(443 端口) | SSH(22 端口,默认)/Ansible Tower API | ZeroMQ(4505/4506 端口) |
配置语法 | 自定义 DSL (Puppet Language) | YAML/INI | YAML(States/Modules) Python(自定义模块) |
并发能力 | 中等(依赖主节点调度,并发数受限) | 低(SSH 串行 / 并行需手动配置,大规模易卡顿) | 高(ZeroMQ 异步通信,支持万级节点并发) |
二、Ansible
(一)介绍
Ansible 是基于 Python 语言开发的轻量级自动化运维工具,核心作用是通过统一的控制节点,实现对多台被管理节点的 “批量管控”,涵盖命令执行、配置管理、软件部署、任务编排等场景,广泛应用于中小型运维团队或无复杂分布式需求的自动化场景。
特性 | 说明 |
---|---|
轻量级架构 | 对比 SaltStack(重量级分布式工具),Ansible 无需在被管理节点部署 Agent 进程,降低运维复杂度和资源占用 |
基于 SSH 协议 | 依赖系统原生 SSH 协议实现通信(默认 22 端口),无需额外配置通信组件,兼容性强 |
无服务 / 无代理(No Server & No Agent) | 控制节点无需启动常驻服务,被管理节点无需安装 Agent,仅需确保 SSH 可连接且 Python 环境正常 |
丰富的 API 接口 | 支持通过 API 与其他系统(如 Jenkins、Zabbix)集成,实现自动化流程联动 |
模块化设计 | 内置上千个模块,可直接调用完成常见运维操作,也支持自定义模块扩展 |
支持幂等性 | 重复执行同一任务不会产生异常结果(如 “安装软件” 任务,已安装则跳过),确保操作安全性 |
(二)Ansible 安装部署(CentOS 7)
1、安装 Ansible
CentOS 7 默认 yum 源不含 Ansible,需先配置 EPEL 源,再通过 yum 安装。
- 对于 CentOS 7/RHEL 7,EPEL 源默认提供的 Ansible 最高稳定版为 2.9.27(长期维护版,已停止主要功能更新,但仍有安全补丁支持);
- 对于 Ansible 2.10 和更高版本,可以使用
pip
安装 Ansible 软件包。有关详细信息,请参见安装 Ansible。可以从https://releases.ansible.com/ansible/下载较旧的 Ansible 版本。 - 在 Ansible 2.10 版本之前,不存在 “ansible-core” 这个概念。之后Ansible 官方做了拆分:
- 拆分出 ansible-core:作为 Ansible 的 “核心引擎”,是 Ansible 运行的 “最小依赖”,仅包含最基础的功能(如 Playbook 解析器、任务调度器、核心模块(command/shell/file 等)、通信层(SSH 连接));保留 Ansible 发行版(如 Ansible 10、Ansible 9):作为 “完整套装”,基于 ansible-core 构建,额外包含 大量社区维护的模块 / 插件 / 集合(如 ansible.posix(系统模块)、community.general(通用模块)、amazon.aws(AWS 云模块)等)。
- 可以简单理解为:Ansible 发行版 = ansible-core + 一堆常用模块/集合
- GitHub - ansible/ansible at stable-2.20
[root@zabbix_server ~] wget -O /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
[root@zabbix_server ~] yum install -y ansible[root@zabbix_server ~] rpm -q ansible
# ansible-2.9.27-1.el7.noarch # 显示版本,说明安装成功[root@zabbix_server ~] ansible --version
# ansible 2.9.27
# config file = /etc/ansible/ansible.cfg # 默认配置文件路径
// 这里直接用 2.9.27简单学习。
2、配置主机清单文件
//(/etc/ansible/hosts)
Ansible 的 “主机清单” 是核心配置文件,用于定义 “哪些节点需要被管理”,支持 “未分组” 和 “分组” 两种写法,便于按业务场景(如 web 服务器、数据库服务器)批量操作。
(1) 未分组的写法
//(适用于节点数量少、无业务分类的场景)
# 直接在 /etc/ansible/hosts 中写入被管理节点的 IP 或主机名:
[root@zabbix_server ~] vim /etc/ansible/hosts
192.168.140.11
192.168.140.12 # 通过 ansible all -m ping 命令,测试所有节点的连通性(all 代表 “所有清单中的节点”,-m ping 代表调用 ping 模块):
[root@zabbix_server ~] ansible all -m ping
192.168.140.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python" # 自动识别被管理节点的Python路径}, "changed": false, # 任务未修改节点状态(幂等性体现)"ping": "pong" # 连通成功的标志
}
192.168.140.12 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "ping": "pong"
}
(2)分组的写法
//(适用于节点多、按业务分类的场景)
# 通过 [组名] 定义分组,同一节点可属于多个组(如 192.168.140.12 既属于 web 组,也属于 db 组):
[root@zabbix_server ~] vim /etc/ansible/hosts
# 清空或注释之前的未分组内容,添加以下分组配置
[web] # 定义“web服务器组”
192.168.140.158[db] # 定义“数据库服务器组”
192.168.140.20 # 同一节点可加入多个组# 指定组名(如 web、db)测试连通性,仅对目标组的节点生效: 测试 web 组节点
[root@zabbix_server ~] ansible web -m ping
# 此时没有设置免密、也没有配置密码信息,所以会出错
3、解决Permission denied
(1)配置 SSH 免密登录
Ansible 默认通过 SSH 连接被管理节点,配置免密登录可避免每次执行任务输入密码,提升操作效率(非强制)。
① 在控制节点生成 SSH 密钥对
在 Ansible 控制节点(如 zabbix_server
)执行以下命令,生成 RSA 密钥对(一路回车,不设置密码,简化操作):
[root@zabbix_server ~] ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): # 回车默认路径
Enter passphrase (empty for no passphrase): # 回车不设密码
Enter same passphrase again: # 再次回车确认
Your identification has been saved in /root/.ssh/id_rsa. # 私钥(本地保存,不可泄露)
Your public key has been saved in /root/.ssh/id_rsa.pub. # 公钥(需分发到被管理节点)
② 将公钥分发到被管理节点
通过 ssh-copy-id
命令,将控制节点的公钥复制到被管理节点(如 192.168.140.11
、192.168.140.12
),首次执行需输入被管理节点的 root 密码:
# 分发到 192.168.140.11
[root@zabbix_server ~] ssh-copy-id root@192.168.140.11
root@192.168.140.11 password: # 输入被管理节点root密码# 分发到 192.168.140.12
[root@zabbix_server ~] ssh-copy-id root@192.168.140.12
③ 验证免密登录
无需输入密码即可登录被管理节点,说明配置成功:
[root@zabbix_server ~]# ssh root@192.168.140.11
Last login: Wed Oct 11 10:00:00 2024 from zabbix_server.linux.com
[root@node1 ~]# # 成功登录,无需密码
(2)添加非免密的主机
若部分被管理节点未配置 SSH 免密(如临时节点),可在主机清单中直接指定 SSH 用户名、密码、端口(需先安装 sshpass 工具,用于处理密码输入)。
① 安装 sshpass 工具
[root@host_21 ~] yum install -y sshpass # 可能被当成依赖下过
② 在主机清单中配置非免密节点
[root@host_21 ~] vim /etc/ansible/hosts
# 通过 ansible_ssh_user(SSH 用户名)、ansible_ssh_pass(SSH 密码)、
# ansible_ssh_port(SSH 端口,默认 22 可省略)指定节点信息:
[web] # 定义“web服务器组”
192.168.140.158 ansible_ssh_user="root" ansible_ssh_pass="548165634" ansible_ssh_port=22
192.168.140.159 ansible_ssh_user="root" ansible_ssh_pass="548165634" ansible_ssh_port=22[no]
192.168.140.51 ansible_ssh_user="root" ansible_ssh_pass="548165634" ansible_ssh_port=22
[db] # 定义“数据库服务器组”
192.168.140.20 ansible_ssh_user="root" ansible_ssh_pass="548165634" ansible_ssh_port=55555
③ 验证非免密节点连通性
[root@host_21 ~] ansible db -m ping
[root@host_21 ~] ansible no -m ping
[root@host_21 ~] ansible web -m ping
4、解决 “Host Key checking” 错误
Ansible 默认会检查被管理节点的 SSH 指纹(保存在 ~/.ssh/known_hosts
),非免密节点首次连接时会因指纹未记录报错,需修改 Ansible 配置关闭该检查:
[root@zabbix_server ~] vim /etc/ansible/ansible.cfg
# 找到并修改以下配置项(默认注释,取消注释并设为 False)
host_key_checking = False # 关闭 SSH 指纹检查
(三)Ansible 命令基本用法
# 基本语法格式
ansible 被管理机 -m 模块 -a 模块参数
(1)ansible-doc 是 Ansible 自带的模块文档查询工具,用于查看各模块的详细说明、参数列表和使用示例。
# 查看指定模块的文档(以 lineinfile 模块为例)
ansible-doc lineinfile# 查看模块的简要信息(仅显示参数和示例)
ansible-doc -s lineinfile
-s
或--snippet
:显示模块的简洁信息,包括参数说明和示例(最常用)-l
或--list
:列出所有可用模块(此版本有3k多个模块)-F
或--list_files
:列出所有模块的文档文件路径-v
或--verbose
:显示更详细的文档内容
(2)Ansible.Builtin — Ansible 社区文档
- 直接搜索模块:页面顶部有搜索框,输入模块名(如
fetch
、cron
),可快速定位到目标模块的文档。
常用模块及示例:
1. shell 模块
作用:在远程主机上执行 shell 命令,并且支持所有 shell 特性,如管道操作(|)、重定向(>、>>)、环境变量引用等
# 查看系统负载
ansible db -m shell -a 'uptime'# 查看内存使用情况
ansible db -m shell -a 'free -m'# 多命令组合执行
ansible db -m shell -a 'df -h | grep /opt'
// 由于 shell 模块会通过远程主机的 shell(默认是 /bin/sh)执行命令,因此在使用特殊字符(如 $、引号等)时,可能需要进行适当的转义,避免本地解析导致命令执行不符合预期。
虽然 shell 模块非常灵活(能执行任意 shell 命令),但 Ansible 仍然提供了大量专用模块(如 copy、file、yum 等),核心原因是 专用模块更安全、更可靠、更易于维护,且能更好地适配自动化场景。
- name: 错误示例:未转义 $HOME,被控制节点解析hosts: webtasks:- name: 打印被管理节点的 $HOMEshell: echo "被管理节点HOME: $HOME" # 问题:$HOME 会被控制节点优先解析- name: 正确示例:转义 $HOME,由被管理节点解析hosts: webtasks:- name: 打印被管理节点的 $HOMEshell: echo "被管理节点HOME: \$HOME" # 关键:\$ 转义,控制节点不解析- name: 错误示例:未转义双引号,被控制节点拆分命令hosts: webtasks:- name: 匹配日志中的 "error" 行shell: grep "error" /var/log/messages # 问题:双引号被控制节点当作字符串边界# 最终传递给被管理节点的命令会变成 grep error /var/log/messages(丢失了双引号);- name: 正确示例:转义双引号,保留命令中的引号hosts: webtasks:- name: 匹配日志中的 "error" 行shell: grep \"error\" /var/log/messages # 关键:\" 转义,双引号被保留- name: 错误示例:复杂命令未转义,管道和变量被破坏hosts: webtasks:- name: 拼接当前用户信息shell: whoami | xargs -I {} echo "当前用户: {}" # 问题:双引号和 {} 被解析# 双引号问题:控制节点会丢失 echo "当前用户: {}" 中的双引号,导致命令变成 echo 当前用户: {};# 缺少双引号会导致 xargs 传递的 {} 被 shell 当作普通字符,而非占位符。
- name: 正确示例:转义双引号,保留管道和占位符hosts: webtasks:- name: 拼接当前用户信息shell: whoami | xargs -I {} echo \"当前用户: {}\" # 关键:\" 转义双引号
具体来说,使用专用模块而非直接依赖 shell 有以下关键优势:
(1)避免 “命令注入” 和 “意外操作” 风险
shell 模块执行的是原始 shell 命令,若命令中包含变量(尤其是用户输入或动态生成的内容),可能存在命令注入风险。
例如,假设用 shell 模块删除一个动态生成的文件:# 危险!若 filename 包含特殊字符(如 "; rm -rf /"),会执行恶意命令
ansible db -m shell -a "rm -f /tmp/{{ filename }}"而专用模块(如 file)会自动处理变量中的特殊字符,避免解析错误或恶意注入:# 安全!file 模块会将 path 作为字符串处理,不解析特殊字符
ansible db -m file -a "path=/tmp/{{ filename }} state=absent"
(2)幂等性(Idempotency)保障
Ansible 自动化的核心原则是幂等性:即多次执行同一任务,结果应完全一致(不会重复修改或产生副作用)。shell 模块本身不保证幂等性,需要手动编写复杂命令来实现。例如:
# 繁琐且易出错:先检查是否存在,不存在才追加
ansible db -m shell -a 'grep -q "192.168.1.1" /etc/hosts || echo "192.168.1.1 test" >> /etc/hosts'# 简洁且安全:无论执行多少次,最终文件中只会有一行目标内容
ansible db -m lineinfile -a 'path=/etc/hosts line="192.168.1.1 test"'
(3)更精细的参数控制和状态管理
专用模块针对特定场景设计了丰富的参数,能实现精确控制,而 shell 模块需要用冗长的命令组合才能实现同等功能。例如管理服务:
# 兼容性差:CentOS 7 用 systemctl,CentOS 6 用 chkconfig
ansible db -m shell -a 'systemctl start vsftpd && systemctl enable vsftpd'# 跨系统兼容:自动识别 systemd、sysvinit 等,确保状态正确
ansible db -m service -a 'name=vsftpd state=started enabled=yes'
(4)清晰的返回结果和错误处理
专用模块执行后会返回结构化的结果(如是否修改、错误原因等),便于在 Playbook 中判断任务状态或调试。例如复制文件:
[root@host_21 ~]# ansible db -m shell -a 'cp /root/file /opt'
192.168.140.20 | CHANGED | rc=0 >>
[root@host_21 ~]# ansible db -m shell -a 'cp /root/file1 /opt'
192.168.140.20 | FAILED | rc=1 >>
cp: 无法获取"/root/file1" 的文件状态(stat): 没有那个文件或目录non-zero return code[root@host_21 ~]# ansible db -m copy -a 'src=/root/file dest=/opt remote_src=yes'
192.168.140.20 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "checksum": "da39a3ee5e6b4b0d3255bfef95601890afd80709", "dest": "/opt/file", "gid": 0, "group": "root", "md5sum": "d41d8cd98f00b204e9800998ecf8427e", "mode": "0644", "owner": "root", "size": 0, "src": "/root/file", "state": "file", "uid": 0
}
[root@host_21 ~]# ansible db -m copy -a 'src=/root/file1 dest=/opt remote_src=yes'
192.168.140.20 | FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Source /root/file1 not found"
}
(5)可读性和可维护性
专用模块的意图更明确,无需阅读复杂的命令逻辑就能理解任务目的。例如:
看到 ansible db -m yum -a 'name=vsftpd state=present',立刻能知道是 “安装 vsftpd 软件”。
而看到 ansible db -m shell -a 'yum install -y vsftpd',需要确认命令是否有副作用(如是否会升级依赖)。
# 若安装过程中出现依赖冲突等错误,模块会尝试回滚操作,避免系统处于 “半安装” 的不一致状态;
# 而 shell 执行 yum install 失败时,可能残留部分安装文件,需要手动清理。
2. copy 模块
作用:将控制节点的普通文件或目录推送到被管理节点,原样复制文件(不解析变量)
ansible.builtin.copy 模块 – 将文件复制到远程位置 — Ansible 社区文档
- src= 控制节点上的源文件 / 目录路径(必填,除非用
content
直接生成内容)。 - dest= 被管理节点上的目标路径(必填)
- mode= 目标文件 / 目录的权限(如
0644
、0755
,八进制格式,需带前导0
)。 - owner= 属主(用户名或 UID)
- group= 属组(组名或 GID
- force=yes/no # 是否强制覆盖目标文件(
yes
/no
,默认yes
- content=字符串 # 直接将字符串作为文件内容写入目标文件
- remote_src=yes/no #
- directory_mode=权限 # 递归复制目录时,设置目录的权限(文件权限仍由
mode
控制)。 - backup=yes/no # 若为 yes,覆盖目标文件前会备份原文件(后缀 .bak)
- copy 模块默认不会解析文件中的变量,如果需要推送带有变量的文件并让变量生效(即替换为实际值),应该使用 template 模块而非 copy 模块。
# 推送文件
ansible db -m copy -a 'src=/root/file01 dest=/opt'
# 推送目录(会递归推送目录内所有内容)
ansible db -m copy -a 'src=/root/configs/ dest=/etc/app/'[root@host_21 ~] ansible db -m copy -a 'src=/opt/work dest=/opt'
[root@host-20 ~]# ls /opt/
# work
[root@host_21 ~] ansible db -m copy -a 'src=/opt/work/ dest=/opt'
[root@host-20 ~]# ls /opt/
# file001 file002 file003# 推送并指定权限和属主
[root@host_21 ~] ansible db -m copy -a 'src=/etc/hosts dest=/opt/hosts mode=0644 owner=root group=root'
[root@host_21 ~] ansible db -m copy -a 'src=/etc/hosts dest=/opt/hosts mode=0755 owner=root group=root'
# 传两次则会覆盖上一次的
[root@host-20 ~]# ls -dl /opt/hosts
# -rw-r--r-- 1 root root 360 9月 28 20:23 /opt/hosts
[root@host-20 ~]# ls -dl /opt/hosts
# -rwxr-xr-x 1 root root 360 9月 28 20:23 /opt/hosts# 仅当源文件比目标文件新时才推送(增量更新)
ansible db -m copy -a 'src=/root/script.sh dest=/usr/local/bin/ mode=0755 force=no'
# force=no:复制策略为 “不强制覆盖”—— 若被管理节点的 /usr/local/bin/script.sh 已存在,则不执行复制(即使源文件与目标文件内容不同);仅当目标文件不存在时,才会复制。ansible db -m copy -a 'content="export PATH=/usr/local/bin:$PATH" dest=/etc/profile.d/custom.sh mode=0644'
# content直接写入字符串作为文件内容
- 若 src 是目录且末尾不带 /,会将目录本身及内容推送到 dest;若带 /,则只推送目录内的内容
- force=yes(默认)表示强制覆盖目标文件,force=no 则仅在源文件更新时才覆盖
- 推送大文件时,可配合 validate 参数先验证文件完整性(如 validate='/usr/bin/checksum %s')
3.template模块
- 严格来说,template 模块不能直接在 ad-hoc 命令(ansible 命令行)中使用,因为 ad-hoc 主要用于简单任务,而 template 依赖本地模板文件和 Jinja2 解析,命令行无法便捷地指定模板内容。
- playbook、角色、独立任务文件等可以使用 template 模块。
4. fetch 模块
作用:从远程主机拉取文件到控制节点的重要工具
ansible.builtin.fetch 模块 – 从远程节点获取文件 — Ansible 社区文档
- src= 被管理节点上的源文件路径(必须是文件,不能是目录)。
- dest= 控制节点上的保存路径(会自动创建以远程主机 IP 为名的子目录)
- 默认会在本地的 dest 路径下,自动创建以「远程主机 IP」命名的子目录,然后把拉取的文件存到这个 IP 子目录里。
- 比如远程主机 IP 是 192.168.140.11,最终本地路径会是:/opt/192.168.140.11/var/log/messages(连远程文件的原始路径结构也会保留)。
- flat=yes/no # 若为为yes,则不创建 “远程 IP + 原始路径” 的嵌套目录,直接按指定文件名保存(覆盖模式)。
- validate_checksum=yes/no # yes(默认),则校验文件哈希值,仅当远程文件与本地文件不一致时才拉取;no 则强制拉取。
- fail_on_missing=yes/no # yes(默认),当远程文件不存在时任务失败;no 则忽略不存在的文件,继续执行。
- fetch 模块只能拉取单个文件,若需拉取目录,需先在远程节点打包(如 tar),再拉取压缩包,最后在控制节点解压。
# 拉取远程日志文件
ansible db -m fetch -a 'src=/var/log/messages dest=/opt'# 拉取文件并自定义保存路径结构(不自动创建IP目录)
ansible db -m fetch -a 'src=/var/log/messages dest=/opt/logs/ flat=yes'# 拉取文件时重命名(避免同名文件覆盖)
ansible db -m fetch -a 'src=/var/log/messages dest=/opt/logs/{{inventory_hostname}_messages flat=yes'# 仅拉取比本地新的文件(增量拉取)
ansible db -m fetch -a 'src=/var/log/messages dest=/opt/logs/ validate_checksum=yes'# 查看拉取结果
ls /opt/
# 192.168.140.11 192.168.140.12 ...(以远程主机IP命名的目录)
5. file 模块
作用:管理文件 / 目录(创建、删除、权限修改等)
# 修改文件权限和属主
ansible db -m file -a 'path=/opt/file01 mode=600 owner=nobody group=nobody'# 递归修改目录权限(包括子文件和子目录)
ansible db -m file -a 'path=/opt/app state=directory mode=0755 recurse=yes'# 创建空文件
ansible db -m file -a 'path=/opt/file02 state=touch'# 创建目录
ansible db -m file -a 'path=/opt/linux state=directory mode=755'# 删除文件或目录(递归删除)
ansible db -m file -a 'path=/opt/file02 state=absent'# 创建符号链接
ansible db -m file -a 'src=/opt/linux path=/opt/link state=link'# 设置文件的访问时间和修改时间(类似touch命令的 -t 参数)
ansible db -m file -a 'path=/opt/file01 state=file access_time=202405010830.00 modification_time=202405010830.00'# 创建临时文件(设置特殊权限,如粘滞位sticky bit)
ansible db -m file -a 'path=/tmp/shared state=directory mode=1777'# 强制删除非空目录(即使目录内有文件也会递归删除)
ansible db -m file -a 'path=/opt/old_data state=absent force=yes'
关键参数补充说明:
- recurse=yes:对目录生效,递归修改其下所有子文件和子目录的属性
- force=yes:删除目录时若目录非空,会强制递归删除;创建链接时若目标已存在,会强制覆盖
- 使用 state=absent 删除文件 / 目录时要格外谨慎,建议先通过 stat 模块确认目标存在性
# 先检查文件是否存在,再删除(在Playbook中更常用)
ansible db -m stat -a 'path=/opt/file02'
- 创建符号链接时,src 建议使用绝对路径,避免因工作目录变化导致链接失效。
- mode 参数支持两种格式:
- 数字格式:mode=0755(注意前导 0 不能省略)
- 符号格式:mode='u=rwx,g=rx,o=rx'(不受 umask 影响,权限设置更精确)
6. lineinfile 模块
作用:管理文件内容(添加、修改、删除行)
# 向/etc/hosts添加一行记录
ansible db -m lineinfile -a 'path=/etc/hosts line="192.168.140.10 zabbix_server.linux.com"'# 替换匹配行(使用regexp)
ansible db -m lineinfile -a 'path=/etc/sysctl.conf regexp="^net.ipv4.ip_forward" line="net.ipv4.ip_forward=1"'# 删除匹配行
ansible db -m lineinfile -a 'path=/etc/hosts regexp="^192.168.140.10" state=absent'# 确保行存在且唯一(重复行只保留最后一次设置的内容)
ansible db -m lineinfile -a 'path=/etc/sysctl.conf regexp="^net.core.somaxconn" line="net.core.somaxconn=1024" state=present'# 在匹配行之前插入新行(insertbefore)
ansible db -m lineinfile -a 'path=/etc/nginx/nginx.conf regexp="^http {" insertbefore=yes line="worker_rlimit_nofile 65535;"'# 在匹配行之后插入新行(insertafter)
ansible db -m lineinfile -a 'path=/etc/ssh/sshd_config regexp="^Port 22" insertafter=yes line="Port 2222"'# 仅当文件存在时才操作(避免对不存在的文件报错)
ansible db -m lineinfile -a 'path=/etc/optional.conf line="log_level=info" state=present creates=/etc/optional.conf'# 备份原文件(修改前自动创建.bak备份)
ansible db -m lineinfile -a 'path=/etc/sudoers regexp="^%wheel" line="%wheel ALL=(ALL) NOPASSWD: ALL" backup=yes'
7. cron 模块
作用:管理计划任务
# 添加定时任务(每30分钟同步时间)
ansible db -m cron -a 'name=TimeSync minute=*/30 job="/usr/sbin/ntpdate ntp.aliyun.com &> /dev/null" state=present'# 禁用定时任务
ansible db -m cron -a 'name=TimeSync state=disabled'# 删除定时任务
ansible db -m cron -a 'name=TimeSync state=absent'# 设置每日凌晨 2 点执行备份脚本(指定小时和分钟)
ansible db -m cron -a 'name=BackupScript hour=2 minute=0 job="/root/backup.sh &> /var/log/backup.log" state=present'# 设置每周日凌晨 3 点清理日志(指定星期)
ansible db -m cron -a 'name=CleanLogs weekday=0 hour=3 minute=0 job="find /var/log -name *.log -mtime +7 -delete" state=present'# 设置每月 1 号执行系统更新(指定日期)
ansible db -m cron -a 'name=SystemUpdate day=1 hour=4 minute=0 job="yum update -y &> /dev/null" state=present'# 添加带环境变量的定时任务(如指定 PATH)
ansible db -m cron -a 'name=CustomJob env=yes job="PATH=/usr/local/bin:$PATH; script.sh" state=present'# 为特定用户添加定时任务(默认是执行 ansible 的用户,通常是 root)
ansible db -m cron -a 'name=UserJob user=test minute=*/10 job="echo hello > /home/test/hello.txt" state=present'
name
:任务名称,用于唯一标识任务(修改或删除时必须一致)env=yes
:将任务标记为环境变量定义(而非执行命令),适合设置PATH
、MAILTO
等user
:指定任务所属用户(默认是当前执行 ansible 的用户)comment
:为任务添加注释(会显示在 crontab 中)
8. yum 模块
作用:管理 RPM 包(适用于 CentOS/RHEL 系统)参数:
- state: present(安装)、absent(卸载)、latest(更新到最新版)
# 安装vsftpd
ansible db -m yum -a 'name=vsftpd state=present'# 卸载vsftpd
ansible db -m yum -a 'name=vsftpd state=absent'# 更新到最新版
ansible db -m yum -a 'name=vsftpd state=latest'# 批量安装多个包
ansible db -m yum -a 'name=httpd,mysql-server state=present'# 从指定 yum 仓库安装包(需提前配置好仓库)
ansible db -m yum -a 'name=nginx enablerepo=epel state=present'# 安装特定版本的包
ansible db -m yum -a 'name=httpd-2.4.6-97.el7.centos state=present'# 安装本地 RPM 包(需先通过 copy 模块推送至远程)
ansible db -m yum -a 'name=/tmp/nginx-1.20.1.rpm state=present'# 卸载包并清除依赖(仅删除无其他依赖的包)
ansible db -m yum -a 'name=vsftpd state=absent autoremove=yes'# 更新所有已安装的包(慎用,可能导致兼容性问题)
ansible db -m yum -a 'name=* state=latest'# 清理 yum 缓存
ansible db -m yum -a 'name=* state=clean'
enablerepo
/disablerepo
:临时启用 / 禁用指定仓库(逗号分隔多个仓库名)autoremove=yes
:卸载包时自动删除无用依赖(类似yum autoremove
)disable_gpg_check=yes
:跳过 GPG 签名验证(不推荐,仅临时用于无签名包)installroot
:指定安装根目录(适用于容器或 chroot 环境)-
使用
state=latest
时需谨慎,尤其是生产环境:- 可能将包升级到不兼容的新版本(如从 PHP 7.4 升级到 8.0)
- 建议针对特定包使用,而非
name=*
(更新所有包)
9. service 模块
作用:管理系统服务
# 启动vsftpd并设置开机自启
ansible db -m service -a 'name=vsftpd state=started enabled=yes'# 停止服务
ansible db -m service -a 'name=vsftpd state=stopped'# 重启服务
ansible db -m service -a 'name=vsftpd state=restarted'# 重新加载配置
ansible db -m service -a 'name=vsftpd state=reloaded'# 检查服务状态(不改变状态,仅返回当前运行情况)
ansible db -m service -a 'name=vsftpd state=started'# 禁用服务开机自启(但保持当前运行状态)
ansible db -m service -a 'name=vsftpd enabled=no'# 强制重启服务(即使服务未运行也尝试启动)
ansible db -m service -a 'name=nginx state=restarted force=yes'# 为服务指定运行用户(部分服务支持,如 nginx、apache)
ansible db -m service -a 'name=nginx state=started user=nginx'# 启动服务并设置超时时间(默认30秒,适用于启动较慢的服务)
ansible db -m service -a 'name=mysql state=started timeout=60'
-
对于
reloaded
状态,并非所有服务都支持(如vsftpd
通常不支持 reload,需用restarted
)
10. user/group 模块
作用:管理用户和用户组
# 创建用户并加入组
ansible db -m user -a 'name=test groups=it uid=2000 shell=/sbin/nologin home=/home/test state=present'# 删除用户(保留家目录)
ansible db -m user -a 'name=test state=absent remove=no'
# 创建系统用户(无家目录,UID 通常小于 1000)
ansible db -m user -a 'name=nginx system=yes shell=/sbin/nologin state=present'# 设置用户密码(需提供加密后的密码,可通过 python 生成)
# 生成加密密码:python -c 'import crypt; print(crypt.crypt("明文密码", crypt.mksalt(crypt.METHOD_SHA512)))'
ansible db -m user -a 'name=test password="$6$rounds=656000$abc123$xyz..." state=present'# 锁定/解锁用户
ansible db -m user -a 'name=test lock=yes' # 锁定
ansible db -m user -a 'name=test lock=no' # 解锁# 指定用户的附加组(groups 为主要组,append=yes 表示不覆盖原有附加组)
ansible db -m user -a 'name=test groups=it append=yes groups=wheel,admin'# 创建用户时指定过期时间(YYYY-MM-DD)
ansible db -m user -a 'name=tempuser expires=2024-12-31 state=present'# 创建用户组
ansible db -m group -a 'name=it state=present gid=1000'# 删除用户组
ansible db -m group -a 'name=it state=absent'
# 创建附加组(系统组)
ansible db -m group -a 'name=devops system=yes gid=3000 state=present'# 修改用户组 GID
ansible db -m group -a 'name=it gid=1001 state=present'# 创建嵌套组(将组作为另一个组的成员)
ansible db -m group -a 'name=admin state=present'
ansible db -m group -a 'name=dev members=admin state=present' # dev 组包含 admin 组
设置密码时,必须使用加密后的字符串(Ansible 不支持直接传入明文密码)。生成方法:
# 在控制节点执行 python 命令生成 SHA512 加密密码
python3 -c 'import crypt; print(crypt.crypt("你的明文密码", crypt.mksalt(crypt.METHOD_SHA512)))'
删除用户时:
remove=yes
会同时删除用户的家目录和邮件目录(谨慎使用)remove=no
(默认)仅删除用户账号,保留家目录
11. script 模块
作用:在远程主机执行本地脚本
# 执行本地脚本(脚本权限需可执行)
ansible db -m script -a '/root/test.sh'# 带参数执行脚本
ansible db -m script -a '/root/backup.sh /data 7'# 执行脚本时指定远程执行用户(默认使用ansible连接用户,通常是root)
ansible db -m script -a 'sudo_user=test /root/script.sh'# 执行脚本时传递环境变量
ansible db -m script -a 'environment="PATH=/usr/local/bin:$PATH" /root/script.sh'# 为脚本设置执行超时时间(单位秒,默认30秒)
ansible db -m script -a 'timeout=60 /root/long_running_script.sh'# 执行脚本时忽略错误(即使脚本返回非0状态码也视为成功)
ansible db -m script -a 'args="--ignore-errors" /root/script.sh'
sudo_user
:指定在远程主机上执行脚本的用户(需要该用户有执行权限)environment
:设置执行脚本时的环境变量(如 PATH、LD_LIBRARY_PATH 等)timeout
:脚本执行的超时时间,超过此时间会被终止args
:传递给脚本的额外参数(也可以直接跟在脚本路径后,如示例中的/root/backup.sh /data 7
)
12、unarchive 模块作用:解压压缩包(支持本地解压和从远程拉取后解压)
# 解压本地压缩包到远程主机
ansible db -m unarchive -a 'src=/root/files.tar.gz dest=/opt/ mode=0755'# 从远程URL下载并解压
ansible db -m unarchive -a 'src=https://example.com/files.tar.gz dest=/opt/ remote_src=yes'