Ansible详解(一)Ansible简介和基础命令及操作
在当今的IT运维中,面对成百上千台服务器,传统的人工手动操作方式不仅效率低下,而且极易出错。自动化运维工具的出现,正是为了解决这一痛点。在众多自动化工具中,Ansible 因其简单易用、功能强大且无需在被管理端安装代理(Agentless)的特性而备受青睐。本文将带您全面了解 Ansible,从其核心概念、运行机制到基础安装和常用模块操作,为您开启自动化运维的大门。
前言
在当今的IT运维中,面对成百上千台服务器,传统的人工手动操作方式不仅效率低下,而且极易出错。自动化运维工具的出现,正是为了解决这一痛点。在众多自动化工具中,Ansible 因其简单易用、功能强大且无需在被管理端安装代理(Agentless)的特性而备受青睐。本文将带您全面了解 Ansible,从其核心概念、运行机制到基础安装和常用模块操作,为您开启自动化运维的大门。
一、Ansible 概述和运行机制
1.1 Ansible 概述
Ansible 是一款使用 Python 语言编写的开源自动化运维工具,它实现了批量系统配置、批量程序部署、批量运行命令等功能,主要面向类 Unix 系统。
1.1.1 与其他工具的对比
与 Puppet、SaltStack、Chef 等同类工具相比,Ansible 具有显著优势:
- Puppet:Ruby 语言编写,采用 C/S 架构,通过 HTTP 协议通信。
- SaltStack:Python 编写,采用 C/S 架构,通过 SSH 或消息队列(MQ)通信。
- Chef:同样采用 C/S 架构,通过 HTTP 协议通信。
而 Ansible 的优势在于:
- 无代理(Agentless):无需在被管理节点上安装任何客户端,非常轻量。
- 使用 SSH:直接通过 SSH 协议与远程节点进行通信和操作。
- 易于上手:使用 YAML 语言编写剧本(Playbook),语法简洁易懂。
官方网站:https://www.ansible.com/
1.1.2 发展历程与特点
- 行业事件:Ansible 公司成立于 2013 年,并在 2015 年 10 月被红帽(Red Hat)公司以约 1.5 亿美元收购。
- 核心特点:
- 部署简单,只需在管理端安装,被控端无需额外操作。
- 默认使用 SSH 协议管理设备,安全可靠。
- 支持集中化管理,功能强大,扩展性高。
- 通过 Playbook 剧本实现复杂的任务编排和状态管理。
- 对云计算和大数据平台有良好的支持。
1.2 Ansible 运行机制
Ansible 的核心工作模式是“推送”:管理节点将所需的模块或命令通过 SSH 推送到被管理节点上执行,执行完成后自动删除临时文件。
核心组件:
- Ansible:核心引擎。
- Modules(模块):核心执行单元,包括内置模块和自定义模块。
- Plugins(插件):用于增强核心功能,如连接插件、邮件插件等。
- Playbooks(剧本):采用 YAML 格式,定义自动化任务流程。
- Inventory(主机清单):定义被管理的主机及其分组信息。
1.3 Ansible 角色(Role)
为了应对复杂环境并提高 Playbook 的可复用性和可维护性,Ansible 引入了“角色”的概念。角色允许用户将相关的任务、处理程序、文件、模板和变量等组织在一个独立的目录结构中,便于共享和重复使用。
二、实战:安装并配置 Ansible
2.1 环境准备
本示例环境包含三台主机:
角色 | IP 地址 |
---|---|
管理端 | 192.168.10.123 |
被管理端 1 | 192.168.10.124 |
被管理端 2 | 192.168.10.125 |
2.2 管理端安装 Ansible
在管理端服务器上执行以下命令进行安装:
# 安装 EPEL 扩展源
yum install -y epel-release
# 安装 Ansible
yum install -y ansible
安装完成后,主要配置文件目录为 /etc/ansible/
,其结构如下:
/etc/ansible/
├── ansible.cfg # Ansible 主配置文件
├── hosts # 默认的主机清单文件
└── roles/ # 角色目录
2.3 配置主机清单 (Inventory)
编辑 /etc/ansible/hosts
文件,定义需要管理的主机。
[webservers] # 定义名为 webservers 的组
192.168.10.14 # 组内包含的主机 IP
[dbservers] # 定义名为 dbservers 的组
192.168.10.15
2.4 配置 SSH 免密登录
为了让 Ansible 管理节点可以无缝通过 SSH 连接被管理节点,需要配置密钥认证。
在 管理端 生成 SSH 密钥对,并将公钥分发到所有被管理端:
# 生成密钥对,一路回车即可
ssh-keygen -t rsa
# 使用 sshpass 工具免交互拷贝公钥(需要先安装 sshpass: ‘yum install -y sshpass’)
sshpass -p '你的密码' ssh-copy-id root@192.168.10.14
sshpass -p '你的密码' ssh-copy-id root@192.168.10.15
三、Ansible 基础命令及模块操作
3.1 命令格式
Ansible 的基本命令行使用格式如下:
ansible <主机或组名> -m <模块名> -a "<模块参数>"
<主机或组名>
:来自主机清单,可以是 IP、组名或all
(代表所有主机)。-m <模块名>
:指定要使用的模块。-a "<参数>"
:传递给模块的参数。
3.2 常用模块详解
3.2.1 command 模块
功能:用于在远程主机执行简单命令。注意:不支持管道符 |
、重定向 (<
, >
) 等 Shell 特性。
示例:
ansible-doc -s command # 查看模块帮助
ansible host1 -m command -a 'date' # 对 webservers 组执行 date 命令
ansible all -a 'ls /' # 省略 -m 参数时,默认使用 command 模块
chdir
:在远程主机上运行命令前提前进入目录,类似cd
creates
:判断指定文件是否存在,如果存在,不执行后面的操作removes
:判断指定文件是否存在,如果存在,执行后面的操作
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
cmd |
是 | - | 要执行的命令。 | cmd="/usr/bin/wh" |
_raw_params |
是 | - | 与 cmd 相同,通常省略。 |
直接写 "/usr/bin/wh" |
chdir |
否 | - | 执行命令前,先切换到此目录。 | chdir="/tmp" |
creates |
否 | - | 如果此文件/目录存在,则不执行命令。 | creates="/tmp/lockfile" |
removes |
否 | - | 如果此文件/目录存在,则执行命令。 | removes="/tmp/old.log" |
3.2.2 shell 模块
功能:用于执行复杂的 Shell 命令,支持管道、重定向等所有 Shell 特性。
示例:
ansible host1 -m shell -a 'echo 123456 | passwd --stdin test' # 免交互修改用户密码
ansible host1 -m shell -a 'echo $(ifconfig ens33 | awk "NR==2 {print \$2}")' # 获取 IP 地址
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
cmd |
是 | - | 要执行的命令字符串。 | cmd="ps aux | grep java" |
_raw_params |
是 | - | 与 cmd 相同,通常是省略参数名直接写命令。 |
直接写 "ps aux | grep java" |
chdir |
否 | - | 执行命令前,先切换到此目录。 | chdir="/tmp" |
creates |
否 | - | 如果此文件/目录存在,则不执行命令。 | creates="/tmp/lockfile" |
removes |
否 | - | 如果此文件/目录存在,则执行命令。 | removes="/tmp/old.log" |
executable |
否 | /bin/sh |
指定执行命令的 Shell。 | executable="/bin/bash" |
正常在主机输入awk是应该是
echo $(ifconfig ens33 | awk 'NR==2 {print $2}')
,但是使用ansible远程时'echo $(ifconfig ens33 | awk "NR==2 {print \$2}")'
被要求包裹在单引号内,当双引号时使用$()会被识别为从本机给的变量,因此$(ifconfig ens33 | awk "NR==2 {print $2)此时awk只能跟双引号,但双引号内的内容会被转义,$2会被识别成一个参数,所以需要在双引号内进行转义$2
3.2.3 cron 模块
功能:管理远程主机的计划任务(crontab)。
示例:
# 添加一个每 1 分钟执行一次的计划任务
ansible host1 -m cron -a 'minute="*/1" job="/bin/echo helloworld" name="123"'
# 查看计划任务
ansible host1 -a 'crontab -l'
# 移除指定的计划任务
ansible host1 -m cron -a 'name="123" state=absent' #假如任务没有名字,name=None即可
- 在远程主机定义任务计划。其中有两种状态(state):present表示添加(可以省略),absent表示移除。
- minute/hour/day/month/weekday:分/时/日/月/周
- job:任务计划要执行的命令
- name:任务计划的名称
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
name |
是 | - | 计划任务的唯一标识符(注释)。用于查找和删除任务。 | name="Backup Job" |
job |
是 | - | 要执行的命令或脚本。 | job="/path/to/backup.sh" |
state |
否 | present |
任务状态。 present :添加或更新。 absent :移除。 |
state=absent |
minute |
否 | * |
分钟 (0-59)。 | minute="5" minute="*/10" |
hour |
否 | * |
小时 (0-23)。 | hour="1" |
day |
否 | * |
日 (1-31)。 | day="1" |
month |
否 | * |
月 (1-12)。 | month="*/3" |
weekday |
否 | * |
周几 (0-6, 周日=0 或 7)。 | weekday="0" weekday="1-5" |
user |
否 | root |
在哪个用户的 crontab 中修改。 | user="nginx" |
disabled |
否 | - | 是否禁用该任务(在行首添加 # )。 |
disabled=yes |
也可以在远程主机的/var/log/cron中查看是否运行成功
3.2.4 user 模块 与 group 模块
功能:用于管理远程主机的用户和用户组。
示例:
# 创建 mysql 组
ansible host1 -m group -a 'name=mysql gid=306 system=yes'
# 创建用户 test01 并加入 mysql 组
ansible host1 -m user -a 'name=test01 uid=306 system=yes group=mysql'
ansible host1 -m command -a 'tail /etc/passwd'
# 删除用户
ansible host1 -m user -a 'name="test01" state=absent'
常用的参数:
name
:用户名,必选参数state=present|absent
:创建账号或者删除账号,present表示创建,absent表示删除system=yes|no
:是否为系统账号,默认为yesuid
:用户uidgroup
:用户基本组shell
:默认使用的shellmove_home=yse|no
:如果设置的家目录已经存在,是否将已-经存在的家目录进行移动password
:用户的密码,建议使用加密后的字符串comment
:用户的注释信息remove=yes|no
:当state=absent时,是否删除用户的家目录
user
模块具体参数一览表
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
name |
是 | - | 要创建、修改或删除的用户名。 | name='testuser' |
state |
否 | present |
用户状态。present :创建用户(如果不存在)。absent :删除用户(如果存在)。 |
state=present state=absent |
uid |
否 | - | 用户的 UID(数字)。 | uid=1005 |
group |
否 | 与用户名相同的主组 | 用户的主要组(GID 或组名)。 | group='developers' group=1001 |
groups |
否 | - | 用户所属的附加组列表。用逗号分隔。注意:groups 与 group 不同,group 是主组,groups 是附加组。 |
groups='wheel,nginx' |
append |
否 | no |
是否将 groups 中指定的组追加到用户的现有附加组中。如果为 no (默认),则用户将仅属于 groups 列表中的组,其他现有附加组将被移除。 |
append=yes |
home |
否 | /home/username |
用户的家目录路径。 | home='/opt/home/testuser' |
shell |
否 | /bin/bash |
用户的默认登录 shell。 | shell='/bin/zsh' |
comment |
否 | - | 用户的描述信息(通常是 GECOS 或全名字段)。 | comment='Test User' |
password |
否 | - | 设置用户密码。必须使用加密后的哈希值,明文密码无效。 | password='$6$salt$encrypted' |
generate_ssh_key |
否 | no |
是否为用户生成 SSH 密钥对。yes :生成。no :不生成。 |
generate_ssh_key=yes |
ssh_key_bits |
否 | 2048 |
与 generate_ssh_key=yes 一起使用,指定 SSH 密钥的位数。 |
ssh_key_bits=4096 |
create_home |
否 | yes |
是否创建家目录。 | create_home=no |
system |
否 | no |
是否创建为系统用户(通常 UID < 1000)。 | system=yes |
remove |
否 | no |
与 state=absent 一起使用,是否同时删除用户的家目录和邮件池。 |
state=absent remove=yes |
move_home |
否 | no |
如果设置为 yes 并且 home 指向一个新位置,则将家目录移动到新位置。 |
move_home=yes |
group
模块具体参数一览表
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
name |
是 | - | 要创建、修改或删除的组名。 | name='developers' |
state |
否 | present |
组状态。present :创建组(如果不存在)。absent :删除组(如果存在)。 |
state=present state=absent |
gid |
否 | - | 组的 GID(数字)。 | gid=1005 |
system |
否 | no |
是否创建为系统组(通常 GID < 1000)。 | system=yes |
始终优先使用Ansible的专用模块(如 user, copy, yum, service)而不是裸的shell命令。 这是发挥Ansible自动化威力和可靠性的关键。command或 shell模块应作为处理那些没有专用模块的特殊情况的“最后手段”。
3.2.5 copy 模块
功能:将管理节点上的文件或内容复制到远程主机。
示例:
# 复制文件并设置权限
ansible host1 -m copy -a 'src=/etc/fstab dest=/opt/fstab.bak owner=root mode=640'
# 直接将内容写入远程文件
ansible host1 -m copy -a 'content="helloworld" dest=/opt/hello.txt'
常用参数:
dest
:指出复制文件的目标及位置,使用绝对路径,如果是源目录,指目标也要是目录,如果目标文件已经存在会覆盖原有的内容src
:指出源文件的路径,可以使用相对路径或绝对路径,支持直接指定目录,如果源是目录则目标也要是目录mode
:指出复制时,目标文件的权限owner
:指出复制时,目标文件的属主group
:指出复制时,目标文件的属组content
:指出复制到目标主机上的内容,不能与src一起使用
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
src |
条件必选 | - | 本地源文件路径。与 content 二选一。 |
src="/app/config.yml" |
dest |
是 | - | 远程主机上的目标路径。 | dest="/etc/app/config.yml" |
content |
条件必选 | - | 直接用字符串内容创建文件。与 src 二选一。 |
content="Hello World" |
owner |
否 | - | 目标文件属主。 | owner="nginx" |
group |
否 | - | 目标文件属组。 | group="nginx" |
mode |
否 | - | 目标文件权限。 | mode="0644" mode="u+rw" |
backup |
否 | no |
覆盖前是否备份原文件。 | backup=yes |
force |
否 | yes |
如果目标存在且不同,是否覆盖。 | force=no |
validate |
否 | - | 复制前执行验证命令(常用于配置文件)。 | validate="/usr/sbin/nginx -t %s" |
3.2.6 file 模块
功能:设置文件属性,如权限、属主、创建链接文件等。
示例:
# 修改文件属性
ansible host1 -m file -a 'owner=test01 group=mysql mode=644 path=/opt/fstab.bak'
# 创建软链接,path的文件存在时会报错
ansible host1 -m file -a 'path=/opt/fstab.link src=/opt/fstab.bak state=link'
# 创建空文件
ansible host1 -m file -a "path=/opt/abc.txt state=touch"
#删除一个文件
ansible dbservers -m file -a "path=/opt/abc.txt state=absent"
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
path |
是 | - | 文件/目录/链接的路径。 | path="/etc/foo.conf" |
state |
否 | file |
对象类型。 file :文件。 directory :目录。 link :软链接。 hard :硬链接。 absent :删除。 |
state=directory state=absent |
src |
否 | - | 当 state=link 或 hard 时,指定源路径。 |
src="/etc/foo.conf" |
owner |
否 | - | 属主。 | owner="root" |
group |
否 | - | 属组。 | group="root" |
mode |
否 | - | 权限。 | mode="0755" |
recurse |
否 | no |
递归设置目录下的文件属性(需与 owner /group /mode 配合)。 |
recurse=yes |
3.2.7 hostname 模块
功能:管理远程主机的主机名。
示例:
ansible host1 -m hostname -a "name=mysql01"
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
name |
是 | - | 要设置的主机名。 | name="web-server-01" |
use |
否 | 取决于系统 | 使用哪个工具修改主机名(通常自动选择)。 | use="systemd" |
3.2.8 ping 模块
功能:检测与管理节点的 SSH 连通性。
示例:
ansible all -m ping
3.2.9 yum 模块
功能:使用 yum 包管理器来安装或卸载软件包。
示例:
# 安装 httpd 服务
ansible host1 -m yum -a 'name=httpd'
# 卸载 httpd 服务
ansible host1 -m yum -a 'name=httpd state=absent'
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
name |
是 | - | 包名。可以是 name@version 格式,或用列表。 |
name="httpd" name="httpd,php" |
state |
否 | present |
包状态。 present :安装最新版。 installed :同 present。 latest :升级到最新。 absent :卸载。 |
state=latest state=absent |
disable_gpg_check |
否 | no |
是否禁用 GPG 签名检查。 | disable_gpg_check=yes |
enablerepo |
否 | - | 临时启用指定的仓库。 | enablerepo="epel" |
disablerepo |
否 | - | 临时禁用指定的仓库。 | disablerepo="*" |
3.2.10 service/systemd 模块
功能:管理远程主机的服务状态,如启动、停止、设置开机自启等。
示例:
# 启动 httpd 服务并设置为开机自启
ansible host1 -m service -a 'enabled=true name=httpd state=started'
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
name |
是 | - | 服务名称。 | name="nginx" |
state |
否 | - | 服务运行状态。 started :启动。 stopped :停止。 restarted :重启。 reloaded :重载配置。 |
state=started |
enabled |
否 | - | 服务开机自启状态。 yes :启用。 no :禁用。 |
enabled=yes |
daemon_reload |
否 | no |
在执行操作前是否运行 daemon-reload (常用于修改服务文件后)。 |
daemon_reload=yes |
sleep |
否 | - | 在 restarted 或 stopped 后,等待几秒再执行下一个操作。 |
sleep=5 |
3.2.11 script 模块
功能:将管理节点本地的脚本在远程主机上执行。
示例:
# 编写本地脚本 test.sh
ansible webservers -m script -a 'test.sh' # 在远程主机执行本地脚本
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
cmd |
是 | - | 本地脚本的路径。 | cmd="/opt/scripts/deploy.sh" |
_raw_params |
是 | - | 与 cmd 相同,通常省略。 |
直接写 "/opt/scripts/deploy.sh" |
chdir |
否 | - | 在远程主机执行脚本前,先切换到此目录。 | chdir="/tmp" |
creates |
否 | - | 如果此文件/目录存在,则不执行脚本。 | creates="/tmp/lockfile" |
removes |
否 | - | 如果此文件/目录存在,则执行脚本。 | removes="/tmp/old.log" |
3.2.12 setup 模块
功能:收集远程主机的详细信息(Facts),如 IP、内存、磁盘等。
示例:
ansible host1 -m setup # 收集所有信息
ansible dbservers -m setup -a 'filter=*ipv4*' # 使用过滤器只收集 IP 相关信息
facts 组件是用来收集被管理节点信息的,使用 setup 模块可以获取这些信息
# 内存信息
ansible all -m setup -a "filter=ansible_memory_mb*"
# 具体内存信息
ansible all -m setup -a "filter=ansible_memory_mb"
ansible all -m setup -a 'filter=ansible_memtotal_mb'
ansible all -m setup -a "filter=ansible_swaptotal_mb"
# 磁盘信息
ansible all -m setup -a "filter=ansible_devices*"
ansible all -m setup -a "filter=ansible_mounts*"
# 具体磁盘信息
ansible all -m setup -a "filter=ansible_devices"
ansible all -m setup -a "filter=ansible_mounts"
ansible all -m setup -a "filter=ansible_device_links"
# IPv4信息
ansible all -m setup -a 'filter=ansible_all_ipv4_addresses'
# 查看cpu信息
ansible all -m setup -a "filter=ansible_processor*"
具体参数一览:
参数 | 是否必选 | 默认值 | 说明 | 示例 |
---|---|---|---|---|
filter |
否 | - | 过滤条件,只显示匹配特定模式的信息。 | filter="*ipv4*" filter="ansible_distribution*" |
gather_subset |
否 | all |
收集信息的子集,可提高效率。 all :所有。 min :最小集。 network :网络相关。 |
gather_subset="min" gather_subset="!all" (排除所有) |
fact_path |
否 | /etc/ansible/facts.d |
自定义 Facts 脚本 (.fact) 的路径。 | fact_path="/opt/app_facts" |
四、Inventory 主机清单进阶配置
主机清单 (/etc/ansible/hosts
) 支持更灵活的配置。
Inventory支持对主机进行分组,每个组内可以定义多个主机,每个主机都可以定义在任何一个或多个主机组内。
4.1 定义主机范围与端口
如果是名称类似的主机,可以使用列表的方式标识各个主机。
[webservers]
192.168.10.14:2222 # 指定非标准 SSH 端口
192.168.10.1[2:5] # 表示 192.168.10.12 到 192.168.10.15
[dbservers]
db-[a:f].example.org # 支持匹配主机名
4.2 设置变量
常用Inventory变量
变量名 | 含义 |
---|---|
ansible_host | 节点 IP |
ansible_port | SSH 端口,默认 22 |
ansible_user | SSH 用户 |
ansible_password | SSH 密码(未使用密钥时) |
ansible_ssh_private_key_file | 私钥文件 |
ansible_become | 提升权限 |
ansible_become_method | 提升方式(sudo/su/runas) |
ansible_become_user | 提升为指定用户 |
ansible_become_password | 提升密码 |
4.2.1 主机变量
直接在主机后定义变量。
[webservers]
192.168.10.124 ansible_port=22 ansible_user=root ansible_password=root123
4.2.2 组变量
使用 :vars
为整个组设置变量。
[webservers:vars]
ansible_user=root
ansible_password=root123
[all:vars] # 为所有组设置变量
ansible_port=22
4.2.3 组嵌套
使用 :children
将多个组合并为一个新的组。
[nginx]
192.168.10.20
192.168.10.21
[apache]
192.168.10.30
192.168.10.31
[webs:children] # webs 组包含 nginx 和 apache 组的所有主机,只能识别组不能识别IP
nginx
apache
192.168.10.55 # 无效添加
总结
通过本文的学习,我们对 Ansible 有了一个全面的认识。从它的基本概念和优势,到如何一步步安装配置并建立 SSH 信任关系;从最基础的 ansible
命令和核心模块(如 command
, shell
, copy
, yum
等)的使用,到如何灵活配置主机清单(Inventory)来管理复杂的主机分组和变量。
Ansible 的真正强大之处在于其 简单性 和 幂等性(一个操作多次执行的结果与一次执行的结果一致)。作为自动化运维的利器,它极大地提升了运维工作的效率和可靠性。本文介绍的内容是 Ansible 的核心基础,掌握了这些,您就已经具备了使用 Ansible 完成日常批量管理任务的能力。下一步,可以深入学习 Playbook 的编写,从而解锁更复杂、更强大的自动化场景。
最后,希望大家多多实践、多多探究、聚沙成塔、与君共勉之!
更多推荐
所有评论(0)