ansible
文章目录
Ansible 是一款开源的自动化工具,主要用于 配置管理、应用部署、任务自动化 和 IT 流程编排 。它基于 Python 开发,采用 "无代理" 架构(通过 SSH 协议与目标主机通信,无需在目标主机安装客户端),操作简单且功能强大,广泛应用于云环境、服务器集群等场景。
核心特点
- 无代理架构:仅需控制节点安装 Ansible,目标主机通过 SSH 即可被管理(支持密码或密钥认证)。
- 简单易用:使用 YAML 格式编写自动化脚本(Playbook),语法直观,易于阅读和维护。
- 模块化设计:内置数千个模块(Module),覆盖用户管理、文件操作、服务控制、包管理等场景,也支持自定义模块。
- 并行执行:可同时对多台主机执行任务,提高自动化效率。
- 幂等性:重复执行相同任务不会产生意外结果(如 "确保服务启动",多次执行仍为启动状态)。
批量管理工具选型
| 工具 | 说明 | 缺点 | 核心定位与适用场景 |
|---|---|---|---|
| xshell | 不适应机器过多场景,需要连接后才能用。 | - | 交互式 SSH 工具,适合单台 / 少量机器的手动远程操作(如临时命令执行、日志查看),但无法批量自动化。 |
| for+ssh/scp + 秘钥认证 | 秘钥认证,免密码登录;scp 传输文件 / 脚本;ssh 远程执行命令或脚本。 | 串行(逐台执行,效率低) | 脚本化 SSH 方案,通过 Shell 脚本结合 SSH/SCP 实现简单自动化(如批量传文件、执行命令),但缺乏并行能力,机器多时光伏化严重。 |
| saltstack | 需要安装客户端。 | - | 客户端 - 服务端架构的配置管理工具,需在被管理节点安装 Salt 客户端,优势是执行速度快、适合超大规模集群,但部署门槛高于无客户端工具。 |
| ansible | 无客户端(秘钥认证);批量部署环境。 | python 版本不要太旧;红帽的(依赖 Python 环境,旧版本可能兼容问题) | 无代理配置管理工具,仅控制节点需装 Ansible,目标节点通过 SSH 通信,适合中小规模批量配置、应用部署、任务自动化,学习成本低且易用性强。 |
| Terraform | 关注基础设施(云环境),一键创建 100 台云服务器,1 键创建负载均衡、数据库产品。 | - | 基础设施即代码(IaC)工具,专注于云资源(如服务器、负载均衡、数据库)的批量创建与编排,而非已有服务器的配置管理,适合云环境的资源自动化交付。 |
ansible管理架构
- 先配置好密钥认证
- 主机清单,通过主机清单(inventory)连接管理被控端
- ad-hoc:命令执行模块
- playbook:使用playbook剧本(核心)

环境准备
| 作用 | 主机 | ip |
|---|---|---|
| ansible管理端 | m01(增加核心输,4c或8c) | 10.0.0.61/172.16.1.61 |
| 被管理端:其他所有机器 | web01,web02,db01,nfs01,backup | |
部署ansible
bash
如何部署ansible,使用pip工具安装.
pip 安装python软件包.
#0.安装pip工具
yum install -y python3-pip
#1.升级pip
python3 -m pip install -i https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple --upgrade pip
#2.pip源(加速pip下载软件)
pip3 config set global.index-url https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple
#3.安装ans
pip3 install ansible
#4.配置ans
mkdir -p /etc/ansible/
cat >/etc/ansible/ansible.cfg<<'EOF'
[defaults]
host_key_checking = False
deprecation_warnings = False
interpreter_python=/usr/bin/python3
[inventory]
[privilege_escalation]
[paramiko_connection]
[ssh_connection]
[persistent_connection]
[accelerate]
[selinux]
[colors]
[diff]
EOF
bash
可以尝试升级python(所有节点)
#升级python到python3.11
下载,解压,进入目录
配置
#./configure --enable-optimizations --with-ssl
#make -j `nproc`
#make install
配置主机清单
bash
[root@m01 ~]# cat /etc/ansible/hosts
#主机清单文件 inventory
[lb]
#指定用户,端口,密码
172.16.1.5 ansible_user=root ansible_port=22 ansible_password=Lidao66
172.16.1.6
[web]
172.16.1.7
172.16.1.8
[db]
172.16.1.51
172.16.1.52
[backup]
172.16.1.41
[nfs]
172.16.1.31
#创建data分组,子组有db,nfs,backup
[data:children]
db
backup
nfs
ansible -i hosts data -m ping
- windows服务器的ansible lnventory(主机清单)
bash
[win_servers]
10.0.0.10 ansible_user=administrator ansible_password=xxxx
10.0.0.10 ansible_user=administrator ansible_password=xxxx
10.0.0.10 ansible_user=administrator ansible_password=xxxx
10.0.0.10 ansible_user=administrator ansible_password=xxxx
10.0.0.10 ansible_user=administrator ansible_password=xxxx
10.0.0.10 ansible_user=administrator ansible_password=xxxx
ansible_connection="winrm" # 连接方式:使用WinRM(Windows远程管理协议,替代SSH)
ansible_port=5985 # WinRM端口:5985为HTTP端口(非加密),5986为HTTPS端口(加密,生产环境推荐)
ansible_winrm_transport="ntlm" # WinRM认证方式:NTLM(适用于非域环境,域环境可改用kerberos)
ansible_winrm_server_cert_validation=ignore # 忽略服务器证书验证(测试环境常用,生产环境建议启用验证)
使用脚本分发密钥
bash
#!/bin/bash
##############################################################
# File Name: change.sh
# Version: V1.0
# Author: song
# Organization:
# Description:
##############################################################
# 颜色输出函数
redecho(){
str=$*
echo -e "\E[1;31m${str}\E[0m"
}
greenecho(){
str=$*
echo -e "\E[1;32m${str}\E[0m"
}
yellowecho(){
str=$*
echo -e "\E[1;33m${str}\E[0m"
}
blueecho(){
str=$*
echo -e "\E[1;34m${str}\E[0m"
}
ips=/shf/ip.txt
key_dir="$HOME/.ssh/"
error_exit(){
redecho "Error: $1"
exit 1
}
#检查系统
dir_OS=/etc/os-release
if [ -f $dir_OS ];then
source $dir_OS
else
echo "没有此版本"
exit 1
fi
check_cmd(){
case $ID in
kylin)
if ! which sshpass ;then
yum install -y sshpass >/dev/null || error_exit "安装失败,请检查网络"
greenecho "安装成功"
fi
if ! which nc >/dev/null 2>&1;then
yum install -y nc >/dev/null 2>&1 || error_exit "安装失败,请检查网络"
greenecho "安装成功"
fi
;;
ubuntu)
if ! which sshpass ;then
apt install -y sshpass >/dev/null || error_exit "安装失败,请检查网络"
greenecho "安装成功"
fi
if ! which nc ;then
apt install -y netcat >/dev/null || error_exit "安装失败,请检查网络"
greenecho "安装成功"
fi
;;
*)
yellowecho "没有这个版本"
exit 1
;;
esac
}
#创建密钥
create_key(){
local key_file="$HOME/.ssh/id_rsa"
[ ! -f ${key_file} ] && {
ssh-keygen -t rsa -f ${key_file} -P '' >/dev/null 2>&1 || error_exit "创建密钥失败"
greenecho "密钥创建成功,在${key_dir}目录下"
}
}
fenfa_check(){
local user_ip
if [ -f "${HOME}/.ssh/known_hosts" ];then
user_ip=`cat ~/.ssh/known_hosts |awk '{print $1}'`
fi
if [ ! -f ${ips} ];then
cat >/shf/ip.txt<<EOF
10.0.0.5,root,Lidao666,22
10.0.0.6,root,Lidao666,22
10.0.0.7,root,Lidao666,22
10.0.0.8,root,Lidao666,22
10.0.0.9,root,Lidao666,22
10.0.0.10,root,Lidao666,22
10.0.0.31,root,Lidao666,22
10.0.0.41,root,Lidao666,22
10.0.0.51,root,Lidao666,22
10.0.0.52,root,Lidao666,22
10.0.0.211,root,Lidao666,22
10.0.0.141,root,1,22
EOF
fi
while IFS= read -r line;do
[ -z "$line" ] || [[ "$line" =~ ^# ]] && continue
IFS=',' read -r ip user passwd port <<< "$line"
if [ -z "$ip" ] || [ -z "$user" ] || [ -z "$passwd" ]; then
yellowecho "配置行格式错误:'$line',跳过"
continue
fi
local is_known=0
while read -r know_ip;do
if [[ "${know_ip}" == "$ip" ]];then
is_known=1
break
fi
done <<< "$user_ip"
if [ $is_known -eq 1 ];then
greenecho "IP $ip:$port(用户${user}) 已配置秘钥"
continue
fi
if ! nc -z -w 1 "${ip}" "${port}" >/dev/null 2>&1;then
yellowecho "IP $ip 不可达(或不在线),跳过"
continue
fi
sshpass -p "$passwd" ssh-copy-id -o StrictHostKeyChecking=no -o Port="${port}" ${user}@${ip} >/dev/null 2>&1 || error_exit "$IP $line 密钥分发失败"
greenecho "IP ${ip}:${port}(用户${user}) 密钥分发成功"
done<${ips}
}
main(){
check_cmd
create_key
fenfa_check
}
main
检查秘钥认证
- ping模块,检查秘钥认证是否ok
bash
#全部检查
ansible all -m ping
#指定组检查
ansible web,db -m ping
#指定hosts文件
ansible -i /server/ansible/hosts web,db -m ping
模块
- 应用:
- 命令行使用,一般是临时
- 写在剧本中(playbook)
| 模块分类 | 模块 | 说明 / 选项 |
|---|---|---|
| 执行命令 / 脚本 | command | 一般用于执行简单命令;不支持特殊符号!() ...`` $;默认的模块。 |
| 执行命令 / 脚本 | shell | 与command类似,支持特殊符号。 |
| 执行命令 / 脚本 | script | 1. 分发 - 脚本 (管理端指定的文件);2. 执行脚本 (运行);3. 删除脚本 |
| 文件,目录 | file | 支持touch、mkdir、rm、chown、chmod、ln -s操作;用于文件、目录、软连接管理;path= 路径 (目录或目录下文件);src= 源文件 (创建链接);mode=0644、0755、user、group;state=touch (文件)/directory (目录)/link (软连接)/absent (删除) |
| 用户模块 | user | 支持useradd、userdel、passwd批量添加 / 删除用户、修改密码;参数包括name、uid、shell、create_home;state: present (添加)、absent (删除) |
| 用户组模块 | group | 参数包括name、gid、state |
| 安装软件包 | yum/apt | name: 软件包名字;state: present (安装)、absent (删除) |
| 分发配置文件 | copy | 类似scp,用于分发配置文件、压缩包(不要分发目录 );src= 管理机文件路径;dest= 被管理机路径;可设置mode=0644、0755、user、group |
| 服务管理 | systemd | 用于服务的启动、停止、重启及开机自启管理;name= 服务名字;enabled= 是否开机自启动 (yes/no);state=started、stopped、restarted、reloaded |
模块文档查询
bash
#列出所有模块
ansible-doc -l
#查看模块简要参数
ansible-doc -s copy
#查看模块完整文档
ansible-doc file
执行命令(shell/command)
bash
#默认就是command
ansible -i hosts data -m command -a 'hostname'
#包含特殊符号
ansible -i hosts data -m shell -a 'touch /tmp/shf{1..10}.txt'
| 参数名 | 作用 | 示例 |
|---|---|---|
free_form |
(核心,无显式参数名)要执行的命令内容 | command: docker pull xxx |
chdir |
执行命令前,先切换到指定目录 | chdir: /server/ansible |
creates |
若指定文件存在,则跳过执行该命令(幂等性) | creates: /usr/bin/docker(docker 存在则跳过安装) |
removes |
若指定文件不存在,则跳过执行该命令(幂等性) | removes: /var/run/docker.sock(docker 未启动则跳过) |
register |
将命令执行结果(输出、返回码等)保存到变量,供后续使用 | register: pull_result |
changed_when |
自定义 "任务是否标记为 changed"(默认命令执行成功就标 changed) | changed_when: "'Downloaded' in pull_result.stdout" |
failed_when |
自定义 "任务失败的条件"(默认非 0 返回码则失败) | failed_when: pull_result.rc != 0 and 'exists' not in pull_result.stderr |
warn |
是否开启命令告警(比如使用不安全的 shell 语法),默认 yes |
warn: no(关闭告警) |
timeout |
命令超时时间(秒),默认无超时 | timeout: 60(docker pull 超时 1 分钟) |
执行脚本(script)
- 分发脚本,执行脚本,删除脚本
bash
#执行脚本
ansible -i hosts data -m script -a '/server/scripts/check_cfg.sh'
#被管理端的脚本位置
root@web01 ~]# tree .ansible/
.ansible/
└── tmp
├── ansible-tmp-1762749237.7139132-7195-73449827837603
│ └── AnsiballZ_command.py
└── ansible-tmp-1762765984.5945835-3536-158988386023671
└── check_cfg.sh
输出调试信息(debug)
Ansible 的 debug 模块是用于在 Playbook 执行过程中输出调试信息的核心工具,主要用于验证变量值、任务执行结果、条件判断逻辑等,帮助排查 Playbook 中的问题。它是 Ansible 调试中最常用的模块之一
| 参数 | 作用 |
|---|---|
msg |
自定义输出消息(支持 Jinja2 变量引用,如 msg: "当前主机: {``{ inventory_hostname }}")。 |
var |
直接指定要打印的变量名(无需 {``{ }} 包裹,如 var: ansible_facts['os_family'])。 |
verbosity |
控制输出级别(默认 0,即总是显示;设为 1 则需 ansible-playbook -v 才显示,以此类推)。 |
示例
yaml
- name: 示例:输出自定义消息
hosts: all
vars:
app_name: "myapp"
version: "1.0.0"
tasks:
- name: 打印应用信息
ansible.builtin.debug:
msg: "正在部署 {{ app_name }},版本:{{ version }},目标主机:{{ inventory_hostname }}"
文件/目录(file)
| 参数 | 说明 | 示例 |
|---|---|---|
path/dest/name |
目标文件 / 目录 / 软链接的路径(必选参数) | path: /tmp/test.txt``dest: /data/app |
state |
控制资源的状态 :- file:确保是文件(默认,若路径不存在则创建空文件)- directory:确保是目录(不存在则创建)- link:创建软链接(需配合src使用)- absent:删除文件 / 目录(递归删除目录需显式指定) |
state: directory(确保是目录)state: link(创建软链接) |
owner |
设置文件 / 目录的所有者(用户名或 UID) | owner: www``owner: 1000 |
group |
设置文件 / 目录的所属组(组名或 GID) | group: nginx``group: 1001 |
mode |
设置文件 / 目录的权限 (八进制格式,如0644、0755) |
mode: 0600(仅所有者可读写)mode: 0775(所有者 / 组可读写执行,其他只读执行) |
src |
创建软链接时,指定源文件 / 目录的路径 (仅state: link时生效) |
src: /usr/bin/python3``dest: /usr/bin/python``state: link |
recurse |
对目录递归设置权限 / 所有者 / 组 (仅state: directory时生效) |
recurse: yes``mode: 0755``owner: appuser |
access_time |
修改文件的访问时间 (格式:YYYYMMDDhhmm.ss 或 preserve 保持原时间) |
access_time: 202511101030.00``access_time: preserve |
modification_time |
修改文件的修改时间 (格式同access_time) |
modification_time: 202511101030.00 |
attributes |
设置文件系统属性 (如immutable(不可变)、hidden(隐藏),不同系统支持不同) |
attributes: +i(设置文件为不可变,Linux 适用)attributes: -i(取消不可变) |
force |
强制创建软链接(若dest已存在文件,会被软链接覆盖) |
force: yes``src: /new/path``dest: /old/path``state: link |
创建目录并设置权限
yaml
- name: 确保/data/logs目录存在且权限为755
ansible.builtin.file:
path: /data/logs
state: directory
mode: 0755
创建软连接
yaml
- name: 把python3链接为python
ansible.builtin.file:
src: /usr/bin/python3
dest: /usr/bin/python
state: link
force: yes # 若已存在python文件,强制替换为软链接
递归设置目录权限和所有者
yaml
- name: 递归设置/webroot目录的权限和所有者
ansible.builtin.file:
path: /webroot
state: directory
owner: webuser
group: webgroup
mode: 0750
recurse: yes
- 创建目录
bash
ansible -i hosts data -m file -a 'path=/app/ans state=directory'
- 创建文件
bash
ansible -i hosts data -m file -a 'path=/app/ans/shf.txt state=touch'
- 删除文件/目录
bash
#path=指定文件/目录路径,absent是删除
ansible -i hosts data -m file -a 'path=/app/ans/shf.txt state=absent'
- 创建软连接
bash
#src=源文件,path=目标文件,link创建软连接
ansible -i hosts data -m file -a 'src=/etc/hosts path=/app/ans/hosts.pcom state=link'
- 创建文件/目录的同时,修改所有者,用户组
bash
chown nginx:nginx /app/ans/
#mode 权限 owner 文件所有者 group 文件所属组
ansible -i hosts data -m file -a 'path=/app/ans/ mode=0700 owner=nginx group=nginx state=directory'
- 递归修改所有者,用户组,权限
bash
chown -R nobody:nobody /app/ans
#recurse=true 递归修改
ansible -i hosts data -m file -a 'path=/app/ans/ owner=nobody group=nobody recurse=true state=directory'
用户模块(user)
| 参数 | 作用 |
|---|---|
name |
必选,用户名(唯一标识)。 |
state |
用户状态:present(创建 / 确保存在,默认)、absent(删除)。 |
password |
用户密码(必须是加密后的字符串 ,不能用明文,需用 openssl passwd 生成)。 |
shell |
用户默认登录 shell(如 /bin/bash、/sbin/nologin,默认 /bin/bash)。 |
create_home |
是否创建家目录:yes(默认)、no(不创建,适合系统用户)。 |
home |
指定家目录路径(默认 /home/用户名)。 |
groups |
用户所属的附加组(多个组用逗号分隔,默认仅属于同名主组)。 |
append |
配合 groups 使用:yes 表示追加附加组(不覆盖原有),no 表示覆盖(默认)。 |
uid |
指定用户的 UID(用户 ID),需唯一。 |
group |
指定用户的主组(默认创建同名主组)。 |
system |
若为 yes,创建系统用户(UID 通常小于 1000,用于服务账号)。 |
remove |
配合 state: absent 使用:yes 表示删除用户时同时删除家目录和邮件目录。 |
- 创建用户并配置基本属性
yaml
- name: 创建testuser用户
ansible.builtin.user:
name: testuser # 用户名
uid: 1002 # UID
group: testgroup # 主组(名称)
groups: sudo,dev # 附加组
append: yes # 不覆盖现有附加组
home: /data/testuser # 家目录
shell: /bin/bash # 登录shell
comment: "Dev Test User" # 注释
password: "$6$randon_salt$abcdef..." # 加密密码
create_home: yes # 创建家目录
- 删除用户并清理家目录
yaml
- name: 删除testuser用户
ansible.builtin.user:
name: testuser
state: absent # 删除用户
remove: yes # 同时删除家目录和邮件
- 创建用户
bash
useradd www-data
#添加用户
ansible -i hosts data -m user -a 'name=oldboy state=present'
#添加虚拟用户
useradd -s /sbin/nologin -M www-data
ansible -i hosts data -m user -a 'name=www-data shell=/sbinshell=/sbin/nologin create_home=false state=present'
#添加虚拟用户,指定uid,gid
groupadd -g 2999 www-data
useradd -s /sbin/nologin -M -u 2999 -g www-data www-data
#创建用户组www-data,gid=2999
ansible -i hosts data -m group -a 'name=www-data gid=2999 state=present'
#创建虚拟用户www-data,并指定uid,gid为2999
ansible -i hosts data -m user -a 'name=www-data uid=2999 group=www-data shell=/sbin/nologin create_home=no state=present'
- 删除用户
bash
#删除用户并删除家目录
userdel -r www-data
ansible -i hosts data -m user -a 'name=www-data remove=yes state=absent'
用户组(group)
| 参数 | 作用 |
|---|---|
name |
必选,组名称(唯一标识)。 |
state |
组的状态:present(创建 / 确保存在,默认)、absent(删除)。 |
gid |
指定组的 GID(组 ID),需唯一(避免与现有组冲突)。 |
system |
若为 yes,创建系统组(GID 通常小于 1000,用于服务账号)。 |
- 创建用户组
bash
#创建用户组,指定gid
ansible -i hosts data -m group -a 'name=www-nfs gid=2999 state=present'
- 批量修改密码
bash
ansible -i hosts data -m user -a 'name=lidao password={{ "oldboy"|password_hash("sha512", "fdsaklfdsajlk234") }} state=present '
安装软件(yum/apt)
| 参数 | 说明 | 示例 |
|---|---|---|
name |
必选,指定软件包名称(支持通配符、版本号,或从文件安装)。 | name: nginx(安装最新版)name: nginx-1.20.1(指定版本)name: /tmp/nginx.rpm(从本地 RPM 安装) |
state |
控制软件包状态:- present:确保安装(默认,不升级)- absent:卸载软件包- latest:安装并升级到最新版- installed:同 present- removed:同 absent |
state: latest(安装并升级到最新)state: absent(卸载) |
update_cache |
是否更新 yum 缓存(类似 yum makecache):- yes:更新- no:不更新(默认) |
update_cache: yes(先更新缓存再安装) |
enablerepo |
临时启用指定 yum 仓库(多个仓库用逗号分隔)。 | enablerepo: epel,nginx-stable(启用 EPEL 和 Nginx 稳定版仓库) |
disablerepo |
临时禁用指定 yum 仓库(多个仓库用逗号分隔)。 | disablerepo: base(禁用 base 仓库) |
disable_gpg_check |
是否跳过 GPG 签名验证(不推荐,仅临时用于无签名包)。 | disable_gpg_check: yes |
autoremove |
卸载软件包时,是否自动删除其依赖的无用包(类似 yum autoremove)。 |
state: absent``autoremove: yes |
安装软件包
yaml
- name: 安装并升级 Nginx(CentOS)
ansible.builtin.yum:
name: nginx
state: present
update_cache: yes # 先更新缓存
卸载软件包
yaml
- name: 卸载 Nginx 并清理依赖(CentOS)
ansible.builtin.yum:
name: nginx
state: absent
autoremove: yes # 自动删除无用依赖
- 安装软件包
bash
yum install -y tree
ansible -i hosts data -m yum -a 'name=tree state=present'
#安装多个
ansible -i hosts data -m yum -a 'name=tree,lrzsz,make state=present'
- 卸载软件包
bash
yum remove -y tree
ansible -i hosts data -m yum -a 'name=tree state=absent'
分发配置文件(copy)
| 参数 | 说明 | 示例 |
|---|---|---|
src |
源路径 (控制节点上的文件 / 目录路径):- 若为文件:直接复制该文件。- 若为目录:默认递归复制目录内所有内容(不包含目录本身,需注意路径末尾是否带/)。- 支持相对路径(相对于 Playbook 所在目录)或绝对路径。 |
src: ./files/nginx.conf(相对路径,Playbook 同级的 files 目录下)src: /tmp/app.tar.gz(绝对路径) |
dest |
目标路径 (被控节点上的路径,必选):- 若 src 是文件:dest 可以是文件路径(直接复制为该文件)或目录路径(复制到该目录下,文件名不变)。- 若 src 是目录:dest 必须是目录路径(复制内容到该目录下)。 |
dest: /etc/nginx/nginx.conf(复制为目标文件)dest: /etc/nginx/(复制到目标目录,文件名不变) |
backup |
复制前,是否备份目标文件 (若目标存在,备份为 dest.~n~ 格式,如 nginx.conf.~1~)。 |
backup: yes(备份原有文件) |
force |
当目标文件已存在时,是否强制覆盖 (对比源文件和目标文件的内容哈希):- yes:内容不同则覆盖(默认)。- no:若目标存在则不复制(即使内容不同)。 |
force: no(不覆盖已存在的文件) |
validate |
复制文件后,执行验证命令 (如检查配置文件语法),验证失败则不保留文件。命令中用 %s 指代目标文件路径。 |
validate: /usr/sbin/nginx -t -c %s(复制 Nginx 配置后,用 nginx -t 验证语法) |
基础复制
yaml
- name: 复制Nginx配置文件到被控节点
ansible.builtin.copy:
src: ./files/nginx.conf # 控制节点的源文件
dest: /etc/nginx/nginx.conf # 被控节点的目标路径
mode: 0644 # 权限:所有者读写,组和其他只读
owner: root # 所有者为root
group: nginx # 所属组为nginx
backup: yes # 备份原有配置文件
复制目录并控制权限
yaml
- name: 复制web静态文件目录到被控节点
ansible.builtin.copy:
src: ./html/ # 控制节点的html目录(末尾带/,表示复制目录内内容)
dest: /var/www/html/ # 被控节点的目标目录
directory_mode: 0755 # 目录权限755
mode: 0644 # 目录内文件权限644
owner: www-data
group: www-data
复制后验证配置文件
yaml
- name: 复制Apache配置并验证语法
ansible.builtin.copy:
src: ./files/httpd.conf
dest: /etc/httpd/conf/httpd.conf
validate: /usr/sbin/httpd -t -f %s # 用httpd -t验证配置
- 复制文件并备份
bash
ansible -i hosts data -m copy -a 'src=/etc/hosts dest=/etc/hosts backup=yes'
[root@web01 ~]# ll /etc/hosts*
-rw-r--r-- 1 root root 346 11月 10 15:13 /etc/hosts
-rw-r--r-- 1 root root 311 10月 17 09:06 /etc/hosts.2081.2025-11-10@15:13:21~
systemd服务管理模块
| 参数 | 说明 | 示例取值 |
|---|---|---|
name |
必选 ,指定服务名称(对应 /usr/lib/systemd/system/ 下的 .service 文件名,可省略 .service 后缀)。 |
name: nginx(对应 nginx.service)name: sshd.service |
state |
控制服务的运行状态 (当前是否活跃):- started:启动服务(若未运行则启动,已运行则不操作)。- stopped:停止服务(若运行则停止,已停止则不操作)。- restarted:重启服务(无论当前状态,强制重启)。- reloaded:重新加载服务配置(不中断服务,仅刷新配置,适用于支持 reload 的服务)。 |
state: started(启动服务)state: reloaded(重载配置) |
enabled |
控制服务是否开机自启 (系统启动时自动运行):- yes:启用开机自启。- no:禁用开机自启。- masked:屏蔽服务(禁止手动或自动启动,比 no 更严格)。 |
enabled: yes(开机自启)enabled: no(禁止开机自启) |
daemon_reload |
当服务配置文件(.service 文件)被修改后,是否重新加载 systemd 守护进程 (使新配置生效):- yes:执行 systemctl daemon-reload。- no:不执行(默认)。 |
daemon_reload: yes(修改配置后重载) |
- 启动服务
bash
systemctl start nginx
ansible -i hosts web -m systemd -a 'name=nginx state=started'
- 关闭服务
bash
systemctl stop nginx
ansible -i hosts web -m systemd -a 'name=nginx state=stopped'
- 重新服务
bash
ansible -i hosts web -m systemd -a 'name=nginx state=restarted'
- 启动服务并设置开机自启
bash
systemctl enable --now nginx
ansible -i hosts web -m systemd -a 'name=nginx enabled=yes state=started'
- 关闭服务并设置开机不自启
bash
sy
ansible -i hosts web -m systemd -a 'name=nginx enabled=no state=stopped'
压缩模块(archive)
| 参数 | 说明 |
|---|---|
path |
必选,要压缩的文件 / 目录路径(支持通配符,如 /data/*) |
dest |
必选,输出的压缩包完整路径(如 /tmp/data.tar.gz) |
format |
压缩格式,可选:tar/gz/bz2/xz/zip(默认 tar) |
compression |
仅 format=tar 时生效,指定压缩算法:gzip/bzip2/xz/none(默认 gzip) |
remove |
是否删除源文件 / 目录,默认 no(建议保持默认,避免误删) |
mode |
压缩包的权限(如 0644,需字符串格式) |
owner/group |
压缩包的属主 / 属组(如 root/root) |
常用示例
示例 1:打包并压缩为 tar.gz(最常用)
yaml
- name: 打包 /data 目录为 /tmp/data.tar.gz
ansible.builtin.archive:
path: /data # 要压缩的目录
dest: /tmp/data.tar.gz # 输出的压缩包路径
format: tar # 基础格式为tar
compression: gzip # 用gzip压缩(最终为tar.gz)
mode: '0644' # 压缩包权限
owner: root
group: root
示例 2:压缩为 zip 格式
yaml
- name: 打包 /var/log/*.log 为 /tmp/logs.zip
ansible.builtin.archive:
path: /var/log/*.log # 匹配多个日志文件
dest: /tmp/logs.zip
format: zip # 直接指定zip格式
传输压缩包并解压(unarchive)
| 参数 | 是否必选 | 默认值 | 说明 | 示例 |
|---|---|---|---|---|
src |
是 | - | 归档文件的源路径。remote_src=yes 时为远程路径;no 时为控制节点路径 |
远程:/tmp/archive.tar.gz;本地:./local_files.zip |
dest |
是 | - | 远程主机上的解压目标目录 | /opt/deploy (解压到远程主机的 /opt/deploy 目录) |
remote_src |
否 | yes |
控制 src 位置:yes 为远程文件,no 为控制节点文件(需传输) |
no (表示 src 是控制节点本地文件) |
mode |
否 | - | 解压后文件 / 目录的权限(数字或符号格式) | 数字:0755;符号:u=rwx,g=rx,o=r |
owner |
否 | - | 解压后文件 / 目录的所有者(用户名或 UID) | webuser (将文件所有者设为 webuser) |
group |
否 | - | 解压后文件 / 目录的所属组(组名或 GID) | webgroup (将文件所属组设为 webgroup) |
extra_opts |
否 | - | 传递给底层工具(如 tar/unzip)的额外选项 |
tar 去顶层目录:--strip-components=1;unzip 静默解压:-q |
list_files |
否 | no |
若为 yes,仅列出归档内容(不实际解压) |
yes (仅预览归档中的文件列表,不解压) |
creates |
否 | - | 若指定路径存在,则跳过解压(幂等性控制) | /opt/deploy/config.ini (若该文件存在,则不解压) |
validate_checksum |
否 | yes |
是否验证源文件校验和(确保未篡改),no 则跳过 |
no (跳过校验和验证,适用于临时文件) |
keep_newer |
否 | no |
目标文件比归档中更新时,是否保留目标文件(yes 保留,no 覆盖) |
yes (保留目标中已更新的文件,不被归档文件覆盖) |
exclude |
否 | - | 解压时排除的文件 / 目录(支持通配符) | *.tmp (排除所有 .tmp 临时文件);logs/ (排除 logs 目录) |
实例 1:从控制节点传输并解压 tar.gz 包到远程主机
场景 :将控制节点本地的 app.tar.gz 传输到远程主机,解压到 /opt/app 目录,同时指定所有者、所属组和权限,并去掉归档文件的顶层目录。
yaml
- name: 传输本地tar包并解压到远程主机
ansible.builtin.unarchive:
src: ./app.tar.gz # 控制节点本地文件路径
dest: /opt/app # 远程主机目标目录(不存在会自动创建)
remote_src: no # 声明src是本地文件(需先传输到远程)
owner: appuser # 解压后文件的所有者
group: appgroup # 解压后文件的所属组
mode: '0755' # 权限设置(所有者读写执行,组和其他读执行)
extra_opts: '--strip-components=1' # 去掉tar包的顶层目录(如原结构是app-v1.0/*,解压后直接是/*)
creates: /opt/app/main.py # 若main.py已存在,则跳过解压(幂等性控制)
实例 2:解压远程主机上的 zip 文件
场景 :远程主机 /tmp 目录下有 data.zip,将其解压到 /var/data,并排除其中的 .log 临时文件,使用静默模式解压。
yaml
- name: 解压远程主机上的zip文件
ansible.builtin.unarchive:
src: /tmp/data.zip # 远程主机上的源文件路径(默认remote_src=yes)
dest: /var/data # 远程目标目录
exclude: '*.log' # 解压时排除所有.log文件
extra_opts: '-q' # 传递给unzip的选项:静默模式(不输出解压过程)
validate_checksum: no # 跳过校验和验证(适用于临时生成的zip包)
注意:远程主机需安装
unzip工具(可通过package模块提前安装:name: unzip state: present)。
实例 3:保留目标目录中更新的文件
场景 :远程主机 /backup 有 config.tar.bz2,解压到 /etc/config,但如果目标目录中已有比归档文件更新的配置文件,则保留目标文件(不覆盖)。
yaml
- name: 解压tar包并保留更新的目标文件
ansible.builtin.unarchive:
src: /backup/config.tar.bz2
dest: /etc/config
keep_newer: yes # 若目标文件比归档中文件新,则保留目标文件
mode: '0644' # 配置文件权限:所有者读写,组和其他只读
实例 4:仅预览归档文件内容(不解压)
场景 :检查远程主机 /tmp 下的 files.tar.xz 中包含哪些文件,不实际解压。
yaml
- name: 预览tar.xz文件中的内容
ansible.builtin.unarchive:
src: /tmp/files.tar.xz
dest: /tmp # 目标目录仅为占位(实际不解压)
list_files: yes # 仅列出内容,不解压
register: archive_content # 结果保存到变量
- name: 打印归档文件内容
ansible.builtin.debug:
var: archive_content.files # 输出文件列表
执行后,archive_content.files 会返回归档中的所有文件路径(如 ["file1.txt", "dir/file2.sh"])。
实例 5:解压后递归设置权限(覆盖子文件)
场景 :从控制节点传输 web.tar 到远程 /var/www,解压后强制将所有文件权限设为 0644,目录权限设为 0755(通过 mode 递归生效)。
yaml
- name: 解压并递归设置权限
ansible.builtin.unarchive:
src: ./web.tar
dest: /var/www
remote_src: no
mode:
file: '0644' # 文件权限
directory: '0755' # 目录权限
owner: www-data # 所有文件/目录的所有者统一为www-data
替换/添加文件中的内容(lineinfile)单行精准修改
| 参数 | 是否必选 | 默认值 | 说明 | 示例 |
|---|---|---|---|---|
path |
是 | - | 目标文件的路径(远程主机上的路径) | path: /etc/nginx/nginx.conf |
line |
否 | - | 要添加或替换的行内容(state=present 时有效,state=absent 时无需指定) |
line: "worker_processes 4;" |
regexp |
否 | - | 用于匹配行的正则表达式(若匹配到,则用 line 替换;若未匹配且 state=present,则添加 line) |
regexp: "^worker_processes.*"(匹配以 worker_processes 开头的行) |
state |
否 | present |
行的状态:present(确保存在)、absent(删除匹配行) |
state: absent(删除匹配 regexp 的行) |
backrefs |
否 | no |
若为 yes,仅当 regexp 匹配到行时才用 line 替换;若未匹配,不添加 line(默认 no 时未匹配会添加) |
backrefs: yes(仅替换已有行,不新增) |
insertafter |
否 | EOF |
当 regexp 未匹配到行时,在指定行之后插入 line(EOF 表示文件末尾,也可填正则表达式) |
insertafter: "^http {"(在 http { 行之后插入) |
insertbefore |
否 | - | 当 regexp 未匹配到行时,在指定行之前插入 line(用法同 insertafter) |
insertbefore: "^server {"(在 server { 行之前插入) |
backup |
否 | no |
是否备份原文件(备份文件会添加 .bak 后缀) |
backup: yes(修改前备份文件) |
regexp_flags |
否 | None |
正则表达式的匹配模式(如 I 表示忽略大小写,M 表示多行模式) |
regexp_flags: "I"(匹配时忽略大小写) |
mode |
否 | - | 设置目标文件的权限(若文件不存在,创建时生效) | mode: '0644' |
示例 1:修改 Nginx 配置中的工作进程数
需求 :将 /etc/nginx/nginx.conf 中 worker_processes 行的值改为 4(若该行不存在则添加到文件末尾)。
yaml
- name: 修改 Nginx 工作进程数为 4
ansible.builtin.lineinfile:
path: /etc/nginx/nginx.conf
regexp: "^worker_processes.*" # 匹配以 worker_processes 开头的行
line: "worker_processes 4;" # 替换后的内容
backup: yes # 备份原文件
示例 2:确保文件中存在指定的 hosts 解析
需求 :在 /etc/hosts 中添加 192.168.1.100 web01 解析(若已存在则不修改,不存在则添加)。
yaml
- name: 添加 hosts 解析
ansible.builtin.lineinfile:
path: /etc/hosts
line: "192.168.1.100 web01" # 要确保存在的行
regexp: "^192.168.1.100.*web01" # 匹配已有的相同解析(避免重复添加)
示例 3:删除配置文件中的注释行
需求 :删除 /etc/sysctl.conf 中所有以 # 开头的注释行(空注释行也删除)。
yaml
- name: 删除 sysctl.conf 中的注释行
ansible.builtin.lineinfile:
path: /etc/sysctl.conf
regexp: "^#" # 匹配以 # 开头的行
state: absent # 删除匹配到的行
示例 4:在指定行前插入新配置
需求 :在 /etc/ssh/sshd_config 中 Port 22 行之前,插入 # 自定义SSH端口 注释。
yaml
- name: 在 SSH 端口配置前插入注释
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
line: "# 自定义SSH端口" # 要插入的注释行
insertbefore: "^Port 22" # 在 Port 22 行之前插入
regexp: "^# 自定义SSH端口" # 避免重复插入
示例 5:仅替换已有行,不新增(backrefs=yes)
需求 :若 /etc/profile 中有 export PATH=/usr/local/bin,则替换为 export PATH=/usr/local/bin:/usr/bin;若不存在,则不添加(避免新增多余行)。
yaml
- name: 仅替换已有 PATH 配置
ansible.builtin.lineinfile:
path: /etc/profile
regexp: "^export PATH=/usr/local/bin" # 匹配原始行
line: "export PATH=/usr/local/bin:/usr/bin" # 替换后的行
backrefs: yes # 仅当 regexp 匹配时才替换,不匹配则不操作
全局替换 (replace)
在 Ansible 中,replace模块(全称为ansible.builtin.replace)是用于在文件中全局替换文本内容 的核心模块,功能类似sed 's/原内容/新内容/g',但更符合 Ansible 的自动化理念(支持幂等性、可维护性更高)。
| 参数 | 作用说明 |
|---|---|
path |
必选,目标文件的路径(如/etc/apt/sources.list)。 |
regexp |
必选,用于匹配目标内容的正则表达式(注意转义特殊字符,如.需写为\.)。 |
replace |
必选,替换后的新内容(可引用regexp中的捕获组,如\1代表第一个分组)。 |
backup |
可选,是否备份原文件。值为yes或具体后缀(如.bak),默认不备份。 |
before |
可选,仅替换 "在某行内容之前" 的匹配项(需配合正则)。 |
after |
可选,仅替换 "在某行内容之后" 的匹配项(需配合正则)。 |
validate |
可选,替换后执行命令验证文件有效性(如visudo -cf %s验证 sudoers 文件)。 |
- 基础用法:全局替换文本(如替换 Ubuntu 镜像源)
yaml
- name: 替换sources.list中的阿里云镜像
ansible.builtin.replace:
path: /etc/apt/sources.list
regexp: 'cn\.archive\.ubuntu\.com' # 匹配原镜像地址(.转义为\.)
replace: 'mirrors.aliyun.com' # 替换为阿里云镜像
backup: '.bak' # 备份原文件为sources.list.bak
- 带正则捕获组的替换(保留部分原有内容)
例如,将配置文件中所有max_size = 1024改为max_size = 2048,但保留变量名:
yaml
- name: 调整max_size参数值
ansible.builtin.replace:
path: /etc/app/config.ini
regexp: '(max_size\s*=\s*)1024' # 捕获组\1保留"max_size = "部分
replace: '\12048' # 用\1引用捕获组,替换数值为2048
- 限制替换范围(仅替换某段内容中的匹配项)
例如,仅替换[database]配置段后的host = localhost为host = db-server:
yaml
- name: 仅修改database段的host配置
ansible.builtin.replace:
path: /etc/app/config.ini
regexp: 'host\s*=\s*localhost'
replace: 'host = db-server'
after: '\[database\]' # 仅处理在"[database]"行之后的内容([ ]需转义)
blockinfile(插入多行文本)
blockinfile 是 Ansible 中用于在文件中插入、更新或删除多行文本块 的模块,特别适合处理配置文件中的 "块级内容"(如 Nginx/Apache 的 <VirtualHost> 块、JSON 中的对象、代码中的函数块等)。与处理单行的 lineinfile 不同,blockinfile 能保持多行文本的格式(换行、缩进等),并通过 "标记" 实现幂等性(重复执行不会重复添加)。
| 参数 | 作用说明 | |
path/dest |
必选,目标文件的路径(如 /etc/nginx/nginx.conf)。 |
|
block |
必选,要插入的多行文本块(支持 YAML 的 ` | ` 保留换行和缩进)。 |
marker |
可选,用于标记文本块的开始和结束(默认值:# {mark} ANSIBLE MANAGED BLOCK)。{mark} 会被替换为 BEGIN 或 END,用于识别块是否已存在(实现幂等)。 |
|
insertbefore |
可选,指定文本块插入到 "匹配行" 之前(如 ^http { 表示插入到以 http { 开头的行之前)。支持正则表达式。 |
|
insertafter |
可选,指定文本块插入到 "匹配行" 之后(如 ^events { ... })。 |
|
state |
可选,present(默认,确保块存在)或 absent(删除块)。 |
|
backup |
可选,yes 则在修改前备份文件(生成 .bak 后缀的备份)。 |
|
trim_empty_lines |
可选,yes(默认)则自动去除 block 中首尾的空行。 |
- 基础用法:向文件插入多行配置块
向 Nginx 配置文件中插入 stream 块(4 层负载均衡配置):
yaml
- name: 向nginx.conf插入stream块
blockinfile:
path: /etc/nginx/nginx.conf
# 多行内容(用|保留换行和缩进)
block: |
stream {
log_format l4 '$remote_addr [$time_local] "$protocol" $status';
include /etc/nginx/l4/*.conf;
}
# 标记:用于识别该块(避免重复添加)
marker: "# {mark} ANSIBLE STREAM BLOCK"
# 插入到http块之前(Nginx要求stream与http同级)
insertbefore: '^http {'
backup: yes # 修改前备份原文件
执行后,nginx.conf 中会新增:
nginx
# BEGIN ANSIBLE STREAM BLOCK
stream {
log_format l4 '$remote_addr [$time_local] "$protocol" $status';
include /etc/nginx/l4/*.conf;
}
# END ANSIBLE STREAM BLOCK
http {
... # 原有http块内容
}
- 更新已存在的块
若再次执行上述任务,且 block 内容有修改(如调整 log_format),blockinfile 会自动更新 BEGIN 和 END 标记之间的内容(不会重复添加)。
- 删除指定块
删除之前插入的 stream 块:
yaml
- name: 删除nginx.conf中的stream块
blockinfile:
path: /etc/nginx/nginx.conf
marker: "# {mark} ANSIBLE STREAM BLOCK" # 必须与插入时的marker一致
state: absent # 删除块
- 在文件末尾插入块
若不指定 insertbefore/insertafter,默认插入到文件末尾:
yaml
- name: 在/etc/sysctl.conf末尾添加内核参数块
blockinfile:
path: /etc/sysctl.conf
block: |
# 自定义内核参数
net.ipv4.ip_forward = 1
vm.swappiness = 10
marker: "# {mark} ANSIBLE SYSCTL BLOCK"
修改定时任务(cron)
Ansible 的cron模块用于管理远程主机的定时任务(crontab) ,支持添加、修改、删除或禁用系统级或用户级的定时任务,无需手动编辑crontab -e。
| 参数 | 作用 | 示例值 |
|---|---|---|
name |
任务的唯一标识(Ansible 通过此名称识别任务,必须唯一) | "clean_logs" |
job |
定时任务要执行的命令或脚本路径(核心内容) | "/usr/bin/rm -rf /var/log/*.log" |
minute |
分钟字段(0-59,*表示每分钟,*/5表示每 5 分钟) |
"0"(整点)、 "*/10"(每 10 分钟) |
hour |
小时字段(0-23) | "3"(凌晨 3 点)、 "*/6"(每 6 小时) |
day |
日期字段(1-31) | "1"(每月 1 号) |
month |
月份字段(1-12 或 Jan-Dec) | "1,3,5"(1/3/5 月) |
weekday |
星期字段(0-6 或 Sun-Sat,0 = 周日) | "0"(周日)、 "1-5"(周一到周五) |
user |
指定任务所属的用户(默认是root) |
"www"、 "postgres" |
state |
任务状态:present(添加 / 修改,默认)、absent(删除) |
"absent"(删除任务) |
disabled |
是否禁用任务(yes/no,默认no;禁用后任务前会加#注释) |
"yes"(禁用任务) |
special_time |
特殊时间(替代minute/hour/day等字段),如@daily(每天凌晨) |
"@reboot"(重启后执行)、@weekly |
使用示例
以下是常见场景的 playbook 示例:
- 添加定时任务(基础示例)
为root用户添加 "每天凌晨 3 点清理/var/log日志" 的任务:
yaml
- name: 添加日志清理定时任务
ansible.builtin.cron:
name: "clean /var/log daily" # 唯一名称
minute: "0" # 0分
hour: "3" # 3点
job: "/usr/bin/rm -rf /var/log/*.log > /dev/null 2>&1" # 执行的命令(重定向输出避免邮件)
user: root # 所属用户(默认root,可省略)
- 修改已存在的任务
修改上述任务的执行时间为 "每周日凌晨 3 点",并更新命令:
yaml
- name: 修改日志清理任务
ansible.builtin.cron:
name: "clean /var/log daily" # 必须与原任务name一致(通过name匹配)
minute: "0"
hour: "3"
weekday: "0" # 0=周日
job: "/usr/bin/find /var/log -name '*.log' -mtime +7 -delete > /dev/null 2>&1" # 新命令(删除7天前的日志)
- 删除定时任务
删除名称为 "clean /var/log daily" 的任务:
yaml
- name: 删除日志清理任务
ansible.builtin.cron:
name: "clean /var/log daily" # 必须匹配要删除的任务名称
state: absent # 状态设为absent表示删除
- 禁用 / 启用任务
临时禁用任务(不删除,仅注释):
yaml
- name: 禁用日志清理任务
ansible.builtin.cron:
name: "clean /var/log daily"
disabled: yes # yes=禁用,no=启用(默认)
- 使用特殊时间(
special_time)
添加 "每次系统重启后执行脚本" 的任务:
yaml
- name: 重启后执行初始化脚本
ansible.builtin.cron:
name: "run init script on reboot"
special_time: "@reboot" # 替代minute/hour等字段
job: "/opt/init.sh"
user: www # 以www用户执行
special_time支持的取值:
@reboot(重启后)、@daily(每天凌晨)、@weekly(每周)、@monthly(每月)、@yearly(每年)。
mysql_user(管理数据库用户)
| 参数 | 作用说明 |
|---|---|
name |
必需,指定用户名(如root、appuser)。 |
host |
指定用户允许登录的主机(默认localhost),支持通配符:%(所有主机)、192.168.1.%(某网段)。 |
password |
用户密码(明文或加密后的哈希值,推荐用明文,模块会自动加密)。 |
login_user |
连接 MySQL 时使用的用户名(如root,用于执行用户管理操作)。 |
login_password |
连接 MySQL 时的密码(与login_user对应)。 |
login_unix_socket |
通过本地 socket 文件连接(而非网络端口),适用于非默认安装的 MySQL(如/app/data/3306/mysql.sock)。 |
login_host |
MySQL 服务器地址(默认localhost,远程连接时需指定)。 |
login_port |
MySQL 端口(默认 3306)。 |
priv |
授予的权限,格式:数据库.表:权限1,权限2(如appdb.*:SELECT,INSERT、*.*:ALL)。 |
state |
状态:present(创建 / 更新用户,默认)、absent(删除用户)。 |
append_privs |
若为yes,则新增权限而非覆盖原有权限(默认no,会覆盖)。 |
password_expire |
是否强制密码过期(yes/no,默认no)。 |