1. 命令模块
1.1. command
command 是ansible的默认模块,用于执行简单的shell命令,由于功能非常有限(不支持管道、重定向等 符号),一般实际场景中很少使用,大部分都是使用shell默认替代command,且shell模块和command模块参数基本一致。
cmd 指定执行的shell命令
argv 使用列表传递参数而不是将参数作为整个字符串
chdir 切换执行命令的工作目录
creates 指定文件名(支持glob表达式),如果文件存在则不执行
removes 指定文件名(支持glob表达式),如果文件存在则执行
stdin 接收一个命令的标准输入
stdin_add_newline 如果为yes,则使用新的一行去接收标准输入
strip_empty_ends 跳过标准输入和输出的空行
warn 是否启用warning 警告
[root@devops-7-3 ansible_learn]# ansible all -a "hostname"
10.4.7.51 | CHANGED | rc=0 >>
centos-7-51.host.com
10.4.7.53 | CHANGED | rc=0 >>
ansible-7-53.host.com
10.4.7.52 | CHANGED | rc=0 >>
ansible-7-52.host.com
[root@devops-7-3 ansible_learn]# ansible all -a "file passwd chdir=/etc"
10.4.7.52 | CHANGED | rc=0 >>
passwd: ASCII text
10.4.7.51 | CHANGED | rc=0 >>
passwd: ASCII text
10.4.7.53 | CHANGED | rc=0 >>
passwd: ASCII text
[root@devops-7-3 ansible_learn]# ansible all -a "file passwd|xargs -n 2"
10.4.7.53 | CHANGED | rc=0 >>
passwd|xargs: cannot open (No such file or directory)
2: cannot open (No such file or directory)
10.4.7.51 | CHANGED | rc=0 >>
passwd|xargs: cannot open (No such file or directory)
2: cannot open (No such file or directory)
10.4.7.52 | CHANGED | rc=0 >>
passwd|xargs: cannot open (No such file or directory)
2: cannot open (No such file or directory)
1.2. shell
cmd 指定执行的shell命令
argv 使用列表传递参数而不是将参数作为整个字符串
executable 指定使用的解释器去执行命令,默认为bash shell,可以指定为 expect,python等
chdir 切换执行命令的工作目录
creates 指定文件名(支持glob表达式),如果文件存在则不执行
removes 指定文件名(支持glob表达式),如果文件存在则执行
stdin 接收一个命令的标准输入
stdin_add_newline 如果为yes,则使用新的一行去接收标准输入
strip_empty_ends 跳过标准输入和输出的空行
warn 是否启用warning 警告
[root@devops-7-3 ansible_learn]# ansible all -m shell -a "cat /etc/passwd|awk -F':' '/root/{print \$1}'"
10.4.7.53 | CHANGED | rc=0 >>
root
operator
10.4.7.52 | CHANGED | rc=0 >>
root
operator
10.4.7.51 | CHANGED | rc=0 >>
root
operator
1.3. script
可以用来执行各类脚本,如shell脚本,python脚本等等,需要在脚本中执行解释器,或者使用 executable 去指定解释器
cmd 脚本执行的参数
executable 指定使用的解释器去执行命令,默认为bash shell,可以指定为 expect,python等
chdir 切换执行命令的工作目录
creates 指定文件名(支持glob表达式),如果文件存在则不执行
removes 指定文件名(支持glob表达式),如果文件存在则执行
decrypt 控制脚本的解密,仅在加密场景中使用
[root@devops-7-3 ansible_learn]# cat test_bash.sh
#!/bin/bash
[ $# -eq 1 ] && ARG=$1 || ARG=$(date +%F)
echo ${HOSTNAME}-${ARG}
[root@devops-7-3 ansible_learn]# ansible all -m script -a "test_bash.sh cmd=xxx"
10.4.7.51 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.4.7.51 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.4.7.51 closed."
],
"stdout": "centos-7-51.host.com-cmd=xxx\r\n",
"stdout_lines": [
"centos-7-51.host.com-cmd=xxx"
]
}
10.4.7.53 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.4.7.53 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.4.7.53 closed."
],
"stdout": "ansible-7-53.host.com-cmd=xxx\r\n",
"stdout_lines": [
"ansible-7-53.host.com-cmd=xxx"
]
}
10.4.7.52 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.4.7.52 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.4.7.52 closed."
],
"stdout": "ansible-7-52.host.com-cmd=xxx\r\n",
"stdout_lines": [
"ansible-7-52.host.com-cmd=xxx"
]
}
[root@devops-7-3 ansible_learn]# cat test_python.py
import time
s=time.strftime("%H:%M:%S")
print s
[root@devops-7-3 ansible_learn]# ansible all -m script -a "test_python.py executable=/usr/bin/python"
10.4.7.51 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.4.7.51 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.4.7.51 closed."
],
"stdout": "11:21:19\r\n",
"stdout_lines": [
"11:21:19"
]
}
10.4.7.52 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.4.7.52 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.4.7.52 closed."
],
"stdout": "11:21:19\r\n",
"stdout_lines": [
"11:21:19"
]
}
10.4.7.53 | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 10.4.7.53 closed.\r\n",
"stderr_lines": [
"Shared connection to 10.4.7.53 closed."
],
"stdout": "11:21:19\r\n",
"stdout_lines": [
"11:21:19"
]
}
2. 文件操作
2.1. file
path 指定要操作的文件,必填项
state 动作,支持 absent(删除/递归删除),directory(创建目录),file(创建文件),link(软连接),hard(硬链接),...
src 在设置硬链接和软连接时,源文件的路径
follow 是否追踪软连接到真实文件,2.5之前的版本为no
force 在设置软连接的场景中,是否强制设置(1.源文件不存在 2.该软连接已存在)
owner 所属用户
group 文件或者目录的所属组
mode 设置文件权限,使用八进制数字时为四位(0644,0755等),也支持字符串u+x格式,preserve表示保留和源文件相同的权限
recurse 在目录情况下,是否使用递归设置权限
access_time 指定文件或者目录的 atime
access_time_format 指定atime的时间格式
modification_time 指定文件的mtime
modification_time_format指定文件mtime的时间格式
attributes 指定chattr属性
unsafe_writes 是否为不安全写入操作,避免文件出现异常,默认为no
[root@devops-7-3 ansible_learn]# ansible all -m file -a "path=/opt/apps/nginx src=/opt/release/nginx_v1.12 state=link"
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/opt/apps/nginx",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 24,
"src": "/opt/release/nginx_v1.12",
"state": "link",
"uid": 0
}
[root@devops-7-3 ansible_learn]# ansible all -m file -a "path=/opt/release/nginx_v1.12 owner=app group=app mode=0755"
10.4.7.52 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"gid": 1000,
"group": "app",
"mode": "0755",
"owner": "app",
"path": "/opt/release/nginx_v1.12",
"size": 66,
"state": "directory",
"uid": 1000
}
2.2. copy
拷贝本地问题到远程主机,比如分发脚本、配置文件、或者安装包的时候使用。多个文件可以先打包再分发,提高速度
src 源目录或者文件,以 / 结尾时仅拷贝目录内部的文件
content 指定目标文件内容,仅支持单个文件。如果涉及变量等复杂场景,使用 template 模块替代
dest 远程主机中文件存放位置,/ 结尾的为目录,不存在的目录会被创建。必填项
owner 所属用户
group 设置远程主机中文件所属组
mode 设置文件权限,使用八进制数字时为四位(0644,0755等),也支持字符串u+x格式,preserve表示保留和源文件相同的权限
backup 如果目标机器存在同名文件,是否备份,备份文件以时间戳结尾
force 如果远程主机存在同名但不同内容的文件,是否强制替换。默认yes
follow 是否使用目标路径中软连接对应的源文件,默认yes
local_follow 是否使用源文件中软连接的真实文件,默认为yes
checksum 指定文件的sha1,如果不提供,则使用src中文件的sha1作为校验
decrypt 使用 vault 解密文件
attributes 指定下方到目标机器后的属性(lsattr属性)
unsafe_writes 是否为不安全写入操作,避免文件出现异常,默认为no
[root@duduniao modules]# ansible -i hosts all -m copy -a "src=pass_wd dest=/tmp/aaa/"
10.4.7.52 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum": "5fb2367ec8882b1c2f9342c5d7f3ddf34ecf05fd",
"dest": "/tmp/aaa/pass_wd",
"gid": 0,
"group": "root",
"md5sum": "04a8037a688f3c953ad042df1222f0d1",
"mode": "0644",
"owner": "root",
"size": 1562,
"src": "/root/.ansible/tmp/ansible-tmp-1595148700.9609635-505-168834404663483/source",
"state": "file",
"uid": 0
}
2.3. fetch
从远程主机拉取文件到本地,在传统运维场景中,会存在批量拉取配置文件、日志等操作,不支持目录。
src 远程主机中的文件,即被拉取的文件,目前不支持目录,后续版本会支持
dest 文件存储位置,必填参数
validate_checksum 拉取文件后,校验摘要信息
fail_on_missing 当远程文件不存在时忽略错误,默认yes
flat 是否覆盖目标位置的文件
[root@devops-7-3 ansible_learn]# ansible all -m fetch -a "src=/etc/passwd dest=backup"
10.4.7.53 | CHANGED => {
"changed": true,
"checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"dest": "/root/ansible_learn/backup/10.4.7.53/etc/passwd",
"md5sum": "06a4d8bbbabe3dd8db11fc3db1302d40",
"remote_checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"remote_md5sum": null
}
10.4.7.52 | CHANGED => {
"changed": true,
"checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"dest": "/root/ansible_learn/backup/10.4.7.52/etc/passwd",
"md5sum": "06a4d8bbbabe3dd8db11fc3db1302d40",
"remote_checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"remote_md5sum": null
}
10.4.7.51 | CHANGED => {
"changed": true,
"checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"dest": "/root/ansible_learn/backup/10.4.7.51/etc/passwd",
"md5sum": "06a4d8bbbabe3dd8db11fc3db1302d40",
"remote_checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"remote_md5sum": null
}
2.4. find
paths 列表,必填项,查找的文件路径列表
patterns 列表,查找对象的文件名(basename),支持glob和正则表达式,如果是正则表达式,需要完全匹配(从文件名开头到结束)
use_regex 表达式类型,yes表示正则表达式,no表示glob表达式,默认 no
recurse 是否递归查看目录,默认false
depth 查找的目录深度,默认不限制。当recurse为no时,该选项无效
file_type 查找的文件类型,any, directory, file, link任选其一。默认file
size 按文件(不是目录)大小查看,正数表示大于等于,负数表示小于等于
age 按照时间查找,正数表示大于等于某个时间,负数表示小于等于某个时间
age_stamp 文件的时间类型,atime, ctime, mtime选择其一。默认是 mtime
excludes 使用shell的glob表达式或者正则表达式来排除指定文件
hidden 是否查看隐藏文件,默认false
follow 使用查找软连接,默认false
get_checksum 是否检查文件的 sha1 ,开启会降低速度,默认false
contains 正则表达式,查找文件内容
[root@duduniao modules]# ansible -i hosts all -m find -a "paths=/etc patterns=docker-ce* recurse=yes"
10.4.7.51 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"examined": 2357,
"files": [
{
"atime": 1595554086.3457134,
"ctime": 1595554085.3077135,
"dev": 2051,
"gid": 0,
"gr_name": "root",
"inode": 8392100,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1595554085.3057134,
"nlink": 1,
"path": "/etc/yum.repos.d/docker-ce.repo",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 2640,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
"matched": 1,
"msg": ""
}
[root@duduniao modules]# ansible -i hosts all -m find -a "paths=/etc patterns=docker-.+\.repo recurse=yes use_regex=yes"
10.4.7.51 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"examined": 2357,
"files": [
{
"atime": 1595554086.3457134,
"ctime": 1595554085.3077135,
"dev": 2051,
"gid": 0,
"gr_name": "root",
"inode": 8392100,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mode": "0644",
"mtime": 1595554085.3057134,
"nlink": 1,
"path": "/etc/yum.repos.d/docker-ce.repo",
"pw_name": "root",
"rgrp": true,
"roth": true,
"rusr": true,
"size": 2640,
"uid": 0,
"wgrp": false,
"woth": false,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
],
"matched": 1,
"msg": ""
}
2.5. get_url
用于文件下载
url 资源的地址,支持 http,https,ftp 三种协议
dest 下载的文件存储路径,必填项
checksum 校验文件的摘要信息,格式: "sha256:D98291AC[...]B6DC7B97" 或者 "sha256:http://example.com/path/sha256sum.txt"。如果目标主机中存在同sha文件,则跳过下载
timeout url 请求的超时时间,单位秒。默认10秒
use_proxy 是否使用代理,默认true
owner 所属用户
group 设置远程主机中文件所属组
mode 设置文件权限,使用八进制数字时为四位(0644,0755等),也支持字符串u+x格式,preserve表示保留和源文件相同的权限
backup 如果目标机器存在同名文件,是否备份,备份文件以时间戳结尾。默认false
force 如果目标路径存在同名文件,是否会强制替换。默认false
headers 添加请求头信息,以字典的方式
http_agent 请求头中的 agent 字段
url_password 用于 http 的basic 认证
url_username 用于 http 的basic 认证
client_cert 客户端SSL证书
client_key 客户端密钥
sha256sum 用于检验文件的完整性,不建议使用该选项,推荐 checksum
tmp_dest 下载文件时的临时存放目录
unsafe_writes 是否为不安全写入操作,避免文件出现异常,默认为no
validate_certs 仅在 remote_src 为 https 时使用,在自签名的网站可以设置为 no
[root@duduniao modules]# ansible -i hosts all -m get_url -a "url=http://tengine.taobao.org/download/tengine-2.3.2.tar.gz dest=/usr/local/src/ checksum=md5:d854a6ecb3f0e140d94d9e0c45044d1e"
10.4.7.52 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"checksum_dest": null,
"checksum_src": "c0981242589c180e37a3f11ca08dcdc53bb12210",
"dest": "/usr/local/src/tengine-2.3.2.tar.gz",
"elapsed": 7,
"gid": 0,
"group": "root",
"md5sum": "d854a6ecb3f0e140d94d9e0c45044d1e",
"mode": "0644",
"msg": "OK (2835884 bytes)",
"owner": "root",
"size": 2835884,
"src": "/root/.ansible/tmp/ansible-tmp-1595153594.0349374-1174-176561175536547/tmpyc3rXZ",
"state": "file",
"status_code": 200,
"uid": 0,
"url": "http://tengine.taobao.org/download/tengine-2.3.2.tar.gz"
}
2.6. unarchive
拷贝压缩包到远程主机并解压,或者直接解压远程主机上已经存在的压缩包。主要用途是传递软件tar包,或者在需要传递目录时,通过先压缩后解压的方式提高传输效率。支持 .zip 和 .tar.?z 。
remote_src 表示文件是否在远程主机上存在(即不需要从主控端拷贝),默认 no。与 copy 互斥。必填项
dest 远程主机上解压的目标目录,必须存在。必填项
extra_opts 使用数组来指定额外的选项
src 如果 remote_src=no,指需要复制到目标机器的源文件;如果 remote_src=yes 标识目标机器上待解压文件路径;如果 remote_src=yes 且src为url则先下载再解压
owner 所属用户
group 设置远程主机中文件所属组
mode 设置文件权限,使用八进制数字时为四位(0644,0755等),也支持字符串u+x格式,preserve表示保留和源文件相同的权限
exclude 加压时需要排除的文件或者目录列表
keep_newer 如果解压后目录的存在同名文件,且修改时比压缩包中文件要新,则不替换。默认false
list_files 是否列出压缩包中的文件
creates 指定文件名或者目录,如果该目录或者文件存在则不执行解压命令
decrypt 使用 vault 解密文件
attributes 指定下方到目标机器后的属性(lsattr属性)
unsafe_writes 是否为不安全写入操作,避免文件出现异常,默认为no
copy 选择拷贝文件到远程主机上,还是直接解压远程主机上的文件,推荐 remote_src 替换该参数
[root@duduniao modules]# ansible -i hosts all -m unarchive -a "src=09-tomcat-9.0.1.tar.gz dest=/opt/release " # 拷贝本地压缩包到目标机器
10.4.7.54 | FAILED! => {
"changed": false,
"msg": "dest '/opt/release' must be an existing dir" # 目标目录必须存在
}
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/opt/release",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/opt/release",
"-z",
"-f",
"/root/.ansible/tmp/ansible-tmp-1595151623.707055-789-83969276689698/source"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TgzArchive",
"mode": "0755",
"owner": "root",
"size": 52,
"src": "/root/.ansible/tmp/ansible-tmp-1595151623.707055-789-83969276689698/source",
"state": "directory",
"uid": 0
}
[root@duduniao modules]# ansible -i hosts all -m unarchive -a "remote_src=yes src=http://tengine.taobao.org/download/tengine-2.3.2.tar.gz dest=/opt/release "
10.4.7.52 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/opt/release",
"extract_results": {
"cmd": [
"/usr/bin/gtar",
"--extract",
"-C",
"/opt/release",
"-z",
"-f",
"/root/.ansible/tmp/ansible-tmp-1595151761.4330106-867-1307791651892/tengine-2.3.2.tar5AFyWy.gz"
],
"err": "",
"out": "",
"rc": 0
},
"gid": 0,
"group": "root",
"handler": "TgzArchive",
"mode": "0755",
"owner": "root",
"size": 73,
"src": "/root/.ansible/tmp/ansible-tmp-1595151761.4330106-867-1307791651892/tengine-2.3.2.tar5AFyWy.gz",
"state": "directory",
"uid": 0
}
2.7. lineinfile
一般用来替换、删除、插入文本文件中指定行。
path 被操纵的文件路径,必填参数
line 与 state=present 一起使用,插入或者替换文本内容,可以引用 backrefs 中正则分组
backrefs 与 state=present 一起使用,启用正则表达式的反向引用。启动该项时,insertbefore和insertafter会被忽略。默认false
regexp 正则表达式。当state=present时,仅最后匹配行被替换;当state=absent时,删除所有匹配行。为了确保幂等性,建议匹配整行
insertafter 正则表达式,默认值EOF。与 state=present 一起使用,将文本插入最后一个匹配行之后。
未匹配到则使用默认值EOF,即插入文件末尾。当指定了 insertbefore,默认值EOF不生效。
与 insertbefore 和 backrefs 互斥。
insertbefore 正则表达式,默认为空。与 state=present 一起使用,将文本插入最后一个匹配行之前。
state present表示替换或者插入行,absent表示删除行
firstmatch 和`insertafter' 或者 `insertbefore'一起使用,仅在第一个匹配到的行前后进行操作。默认false
owner 所属用户
group 设置远程主机中文件所属组
mode 设置文件权限,使用八进制数字时为四位(0644,0755等),也支持字符串u+x格式,preserve表示保留和源文件相同的权限
backup 如果目标机器存在同名文件,是否备份,备份文件以时间戳结尾
[root@duduniao modules]# ansible -i hosts all -m lineinfile -a "path=/tmp/passwd regexp='^root' state=absent" # 删除指定行
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup": "",
"changed": true,
"found": 1,
"msg": "1 line(s) removed"
}
[root@duduniao modules]# ansible -i hosts all -m lineinfile -a "path=/tmp/passwd line='aaaaa'" # 插入行
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup": "",
"changed": true,
"msg": "line added"
}
[root@duduniao modules]# ansible -i hosts all -m lineinfile -a "path=/tmp/passwd backrefs=yes regexp=^(app.+)/bin/bash$ line='\1/sbin/nologin'" # 替换行
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"backup": "",
"changed": true,
"msg": "line replaced"
}
2.8. blockinfile
用来对多行文本组成的块(block)进行操作,如插入、替换、删除。比如修改 /etc/hosts 文件,常常与template集合使用。
path 被操纵的文件路径,必填参数
block 插入或者删除的内容块
insertafter 正则表达式,默认值EOF。将block插入最后一个匹配行之后。未匹配到则使用默认值EOF,即插入文件末尾。当指定了 insertbefore,默认值EOF不生效。。
insertbefore 正则表达式,默认为空。将block插入最后一个匹配行之前。
state present表示替换或者插入block,absent表示删除block
marker 标记,成对出现,默认值:# {mark} ANSIBLE MANAGED BLOCK
marker_begin 指定marker中开始行的 {mark} 变量的值
marker_end 指定marker中结束行的 {mark} 变量的值
owner 所属用户
group 设置远程主机中文件所属组
mode 设置文件权限,使用八进制数字时为四位(0644,0755等),也支持字符串u+x格式,preserve表示保留和源文件相同的权限
backup 如果目标机器存在同名文件,是否备份,备份文件以时间戳结尾
[root@duduniao modules]# ansible -i hosts all -m blockinfile -a "block='abc def' path=/tmp/passwd marker='// {mark} OF TEST'"
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"msg": "Block inserted"
}
2.9. stat
该模块获取的文件信息非常多,一般通过变量进行引用,作为其它步骤中的判断
path 文件路径,必填参数
follow 如果是软连接,是否获取原本文件信息
get_attributes 使用 lsattr 获取文件属性,默认yes
get_checksum 获取文件摘要信息,默认yes
get_mime 获取文件类型,默认yes
checksum_algorithm 获取摘要算法,默认sha1sum
[root@devops-7-3 ansible_learn]# ansible all -m stat -a "path=/etc/passwd"
10.4.7.52 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"stat": {
"atime": 1594518332.820455,
"attr_flags": "",
"attributes": [],
"block_size": 4096,
"blocks": 8,
"charset": "us-ascii",
"checksum": "e6e41730258fe5f1c0647564076034d92e66af3a",
"ctime": 1542858636.697173,
"dev": 2051,
"device_type": 0,
"executable": false,
"exists": true,
"gid": 0,
"gr_name": "root",
"inode": 8392558,
"isblk": false,
"ischr": false,
"isdir": false,
"isfifo": false,
"isgid": false,
"islnk": false,
"isreg": true,
"issock": false,
"isuid": false,
"mimetype": "text/plain",
"mode": "0644",
"mtime": 1542858636.697173,
"nlink": 1,
"path": "/etc/passwd",
"pw_name": "root",
"readable": true,
"rgrp": true,
"roth": true,
"rusr": true,
"size": 834,
"uid": 0,
"version": "1016886215",
"wgrp": false,
"woth": false,
"writeable": true,
"wusr": true,
"xgrp": false,
"xoth": false,
"xusr": false
}
}
3. 软件操作
3.1. yum
CentOS 系列软件包管理工具,下载线上的 yum 源文件使用 get_url
包,
name 列表,要按照的软件包名称,或者名称+版本。* 表示更新所有软件包,等同于 yum update
state present和installed表示安装软件,latest表示安装或者更新软件。absent和removed表示删除软件
disable_gpg_check 是否关闭gpg check。默认false
autoremove 与state=absent配合使用,连带不需要的依赖性。默认false
list 列出指定的包版本信息。等同于yum list --show-duplicates <package>。与name互斥。
update_cache 是否强制更新yum的缓存。默认false
update_only 仅仅更新软件,不安装额外的软件,与 state=latest配合使用。默认false
security 与state=latest配合使用,为yes时仅更新安全相关软件
download_dir 软件包下载路径,与download_only配合使用
download_only 仅下载而不安装软件包,做一些本地yun源使用
exclude 排除要安装的包,与 state=present或者state=latest配合使用
skip_broken 跳过依赖中有问题的包
validate_certs 是否校验https证书,仅在安装的对象为 https URL对应软件包链接时使用。
lock_timeout 等待yum命令锁的超时时间
[root@duduniao modules]# ansible -i hosts all -m yum -a "name=httpd state=present"
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"httpd"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirrors.aliyun.com\n * extras: mirrors.aliyun.com\n * updates: mirrors.aliyun.com\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-93.el7.centos will be installed\n--> Processing Dependency: httpd-tools = 2.4.6-93.el7.centos for package: httpd-2.4.6-93.el7.centos.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-93.el7.centos.x86_64\n--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-93.el7.centos.x86_64\n--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-93.el7.centos.x86_64\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-5.el7 will be installed\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed\n---> Package httpd-tools.x86_64 0:2.4.6-93.el7.centos will be installed\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.4.6-93.el7.centos base 2.7 M\nInstalling for dependencies:\n apr x86_64 1.4.8-5.el7 base 103 k\n apr-util x86_64 1.5.2-6.el7 base 92 k\n httpd-tools x86_64 2.4.6-93.el7.centos base 92 k\n mailcap noarch 2.1.41-2.el7 base 31 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package (+4 Dependent packages)\n\nTotal download size: 3.0 M\nInstalled size: 10 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal 947 kB/s | 3.0 MB 00:03 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : apr-1.4.8-5.el7.x86_64 1/5 \n Installing : apr-util-1.5.2-6.el7.x86_64 2/5 \n Installing : httpd-tools-2.4.6-93.el7.centos.x86_64 3/5 \n Installing : mailcap-2.1.41-2.el7.noarch 4/5 \n Installing : httpd-2.4.6-93.el7.centos.x86_64 5/5 \n Verifying : apr-1.4.8-5.el7.x86_64 1/5 \n Verifying : httpd-tools-2.4.6-93.el7.centos.x86_64 2/5 \n Verifying : mailcap-2.1.41-2.el7.noarch 3/5 \n Verifying : httpd-2.4.6-93.el7.centos.x86_64 4/5 \n Verifying : apr-util-1.5.2-6.el7.x86_64 5/5 \n\nInstalled:\n httpd.x86_64 0:2.4.6-93.el7.centos \n\nDependency Installed:\n apr.x86_64 0:1.4.8-5.el7 apr-util.x86_64 0:1.5.2-6.el7 \n httpd-tools.x86_64 0:2.4.6-93.el7.centos mailcap.noarch 0:2.1.41-2.el7 \n\nComplete!\n"
]
}
[root@duduniao modules]# ansible -i hosts all -m yum -a "name=httpd state=absent autoremove=yes"
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"removed": [
"httpd"
]
},
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: fastestmirror\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-93.el7.centos will be erased\n--> Finished Dependency Resolution\n--> Finding unneeded leftover dependencies\n---> Marking apr to be removed - no longer needed by httpd\n---> Marking mailcap to be removed - no longer needed by httpd\n---> Marking httpd-tools to be removed - no longer needed by httpd\n---> Marking apr-util to be removed - no longer needed by httpd\nFound and removing 4 unneeded dependencies\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-5.el7 will be erased\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be erased\n---> Package httpd-tools.x86_64 0:2.4.6-93.el7.centos will be erased\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be erased\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nRemoving:\n httpd x86_64 2.4.6-93.el7.centos @base 9.4 M\nRemoving for dependencies:\n apr x86_64 1.4.8-5.el7 @base 221 k\n apr-util x86_64 1.5.2-6.el7 @base 194 k\n httpd-tools x86_64 2.4.6-93.el7.centos @base 168 k\n mailcap noarch 2.1.41-2.el7 @base 62 k\n\nTransaction Summary\n================================================================================\nRemove 1 Package (+4 Dependent packages)\n\nInstalled size: 10 M\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Erasing : httpd-2.4.6-93.el7.centos.x86_64 1/5 \n Erasing : httpd-tools-2.4.6-93.el7.centos.x86_64 2/5 \n Erasing : mailcap-2.1.41-2.el7.noarch 3/5 \n Erasing : apr-util-1.5.2-6.el7.x86_64 4/5 \n Erasing : apr-1.4.8-5.el7.x86_64 5/5 \n Verifying : apr-1.4.8-5.el7.x86_64 1/5 \n Verifying : mailcap-2.1.41-2.el7.noarch 2/5 \n Verifying : httpd-tools-2.4.6-93.el7.centos.x86_64 3/5 \n Verifying : httpd-2.4.6-93.el7.centos.x86_64 4/5 \n Verifying : apr-util-1.5.2-6.el7.x86_64 5/5 \n\nRemoved:\n httpd.x86_64 0:2.4.6-93.el7.centos \n\nDependency Removed:\n apr.x86_64 0:1.4.8-5.el7 apr-util.x86_64 0:1.5.2-6.el7 \n httpd-tools.x86_64 0:2.4.6-93.el7.centos mailcap.noarch 0:2.1.41-2.el7 \n\nComplete!\n"
]
}
3.2. apt
Ubuntu和Debian包管理工具。添加 apt-key 使用 apt_key
包,添加apt源使用 apt_repository
包。
name 包名称列表,或者包名称加版本的格式,如 foo=1.0
state 期望状态,支持absent, build-dep, latest, present, fixed。默认 present
latest表示安装或更新到最新版,build-dep确保已安装依赖性。fixed修复损坏的依赖环境
update_cache 更新 apt 缓存,默认 no
autoremove 在卸载软件时,移除不需要的依赖项
purge 与 state=absent配合使用,移除相关配置文件
only_upgrade 仅仅升级已安装的包,默认 no
upgrade 软件升级方式,支持dist, full, no, safe, yes。默认 no
yes 或则 safe 表示 执行安全升级。full表示全面升级。dist表示执行 apt-get dist-upgrade
allow_unauthenticated 忽略 apt-key 校验
autoclean 清除本地存储库中已检索到的无法再下载的软件包文件。默认 no
cache_valid_time 设置apt缓存过期时间
dpkg_options 添加 dpkg 选项到 apt 命令,默认 force-confdef,force-confold
force_apt_get 强制是他 apt-get 而不是 aptitude。默认no
3.3. pip
在使用ansible操作被控端时,部分模块需要特定的python库才能使用,如docker_coompose模块需要 docker-compose库。
name 需要安装的包的列表
state 动作,支持absent, forcereinstall, latest, present。默认 present
executable 指定执行的pip版本或者路径,在pip3和pip2混用的机器上常用
extra_args 额外的参数,比如指定源 '-i https://xxxx '
requirements 指定requirements.txt依赖文件,需要先将文件拷贝到远程主机上
umask 指定文件的umask,四位八进制,如0022
version 指定包的版本
virtualenv 指定虚拟环境的路径
virtualenv_command 创建虚拟环境的命令,或者命令的路径
virtualenv_python 虚拟环境的python版本
virtualenv_site_packages 虚拟环境是否继承全局的包
[root@duduniao modules]# ansible -i hosts all -m pip -a "name=pip executable=pip2 state=latest extra_args='-i https://pypi.tuna.tsinghua.edu.cn/simple'" # pip升级
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"cmd": [
"/usr/bin/pip2",
"install",
"-U",
"-i",
"https://pypi.tuna.tsinghua.edu.cn/simple",
"pip"
],
"name": [
"pip"
],
"requirements": null,
"state": "latest",
"stderr": "Cache entry deserialization failed, entry ignored\n",
"stderr_lines": [
"Cache entry deserialization failed, entry ignored"
],
"stdout": "Collecting pip\n Downloading https://pypi.tuna.tsinghua.edu.cn/packages/43/84/23ed6a1796480a6f1a2d38f2802901d078266bda38388954d01d3f2e821d/pip-20.1.1-py2.py3-none-any.whl (1.5MB)\nInstalling collected packages: pip\n Found existing installation: pip 8.1.2\n Uninstalling pip-8.1.2:\n Successfully uninstalled pip-8.1.2\nSuccessfully installed pip-20.1.1\n",
"stdout_lines": [
"Collecting pip",
" Downloading https://pypi.tuna.tsinghua.edu.cn/packages/43/84/23ed6a1796480a6f1a2d38f2802901d078266bda38388954d01d3f2e821d/pip-20.1.1-py2.py3-none-any.whl (1.5MB)",
"Installing collected packages: pip",
" Found existing installation: pip 8.1.2",
" Uninstalling pip-8.1.2:",
" Successfully uninstalled pip-8.1.2",
"Successfully installed pip-20.1.1"
],
"version": null,
"virtualenv": null
}
[root@duduniao modules]# cat requirements.txt # 批量安装
ansible==2.7.12
jinja2==2.10.1
netaddr==0.7.19
pbr==5.2.0
hvac==0.8.2
jmespath==0.9.4
ruamel.yaml==0.15.96
[root@duduniao modules]# ansible -i hosts all -m copy -a "src=requirements.txt dest=/tmp/"
[root@duduniao modules]# ansible -i hosts all -m pip -a "requirements=/tmp/requirements.txt executable=pip2 extra_args='-i https://pypi.tuna.tsinghua.edu.cn/simple'"
3.4. service
用于管理服务的重启和开机自启动
name 服务名称,必填项
state 期望状态,支持: started,stopped,restarted,reloaded
enabled 是否开机自启动
runlevel 运行级别,仅针对 OpenRC init scripts
sleep 在服务重启过程中,stop后等待多长时间再执行start
arguments 额外的命令行参数
[root@duduniao modules]# ansible -i hosts all -m service -a "name=httpd state=started enabled=yes"
[root@centos-7-51 ~]# systemctl status httpd;systemctl is-enabled httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; disabled; vendor preset: disabled)
Active: inactive (dead)
Docs: man:httpd(8)
man:apachectl(8)
disabled
[root@centos-7-51 ~]# systemctl status httpd;systemctl is-enabled httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Sat 2020-07-25 18:20:53 CST; 9s ago
Docs: man:httpd(8)
man:apachectl(8)
Main PID: 3800 (httpd)
Status: "Total requests: 0; Current requests/sec: 0; Current traffic: 0 B/sec"
CGroup: /system.slice/httpd.service
├─3800 /usr/sbin/httpd -DFOREGROUND
├─3803 /usr/sbin/httpd -DFOREGROUND
├─3804 /usr/sbin/httpd -DFOREGROUND
├─3805 /usr/sbin/httpd -DFOREGROUND
├─3806 /usr/sbin/httpd -DFOREGROUND
└─3807 /usr/sbin/httpd -DFOREGROUND
Jul 25 18:20:40 centos-7-51.host.com systemd[1]: Starting The Apache HTTP Server...
Jul 25 18:20:53 centos-7-51.host.com systemd[1]: Started The Apache HTTP Server.
enabled
[root@duduniao modules]# ansible -i hosts all -m service -a "name=firewalld state=stopped enabled=no"
4. 系统配置
4.1. group
gid 指定GID
name 组名,必填项
state 期望状态,默认 present
system 是否为系统用户,默认false
[root@duduniao modules]# ansible -i hosts all -m group -a "name=application system=yes gid=1024"
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 1024,
"name": "application",
"state": "present",
"system": true
}
4.2. user
name 指定用户名
state 期望状态,present或absent
uid 指定UID
group 指定主组
groups 指定附属组
shell 指定用户的SHELL
create_home 是否创建家目录
home 指定用户家目录
remove 与 state=absent配合使用,删除用户时是否删除家目录和邮件目录
system 是否为系统用户,无法对以创建的用户进行修改
password 设置用户密码(加密后),参考: https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#how-do-i-generate-encrypted-passwords-for-the-user-module
force 与state=absent配合使用时,强制删除用户。 与generate_ssh_key=yes配合使用时,强制覆盖已存在的ssh密钥
move_home 配合home一起使用,移动旧的家目录内容到新的家目录下
append 是否追加到groups,如果为否,则从原来的附属组移除,并加入groups指定的组中
generate_ssh_key 是否生成ssh密钥
ssh_key_bits 指定SSH密钥的bits数量
ssh_key_comment SSH密钥注释
ssh_key_file SSH密钥路径,默认 .ssh/id_rsa
ssh_key_type SSH密钥类型
ssh_key_passphrase SSH密钥的密码
# password测试失败了
[root@duduniao modules]# ansible -i hosts all -m user -a "name=duduniao uid=2020 group=admin shell=/bin/bash home=/home/duduniao generate_ssh_key=yes ssh_key_comment=duduniao-linux"
10.4.7.51 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"append": false,
"changed": false,
"comment": "",
"group": 2020,
"home": "/home/duduniao",
"move_home": false,
"name": "duduniao",
"shell": "/bin/bash",
"ssh_fingerprint": "2048 SHA256:YndsOvW6n5pA5loXfnpkEkjTlOH8/Wj5s2lPwz9nb3M duduniao-linux (RSA)",
"ssh_key_file": "/home/duduniao/.ssh/id_rsa",
"ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIJrXH/gcn/gR4Fk3C11kLMMhWw7iwqcAL+FaNf77IDFkn6I7xXQwNBp5x99NpZp+TFOBvM0+qpasgvtww4okHbBvTXIbEHgHYwasl+2o+i60EbQigzwEZaVEyw2oZsk7kHntozKWPhG5JHkX01A1o/oEjNCGDjwSpuVd0bvQrDd7mnI8ir3UgVV7qQOWF61zZIMpgktbj3RSYf5Yn2xO1p13s6fE1D1keLeFQePM6JrXXnZkqXu9uArk/n0cSYsNa44Xs+AHmySrBYrvhgTSRmpdDgu6m3xmy1qLZDFsSpoUqqZG1xAspqMCPnUgD3f8WuYI9epB/EX4loUzo4znj duduniao-linux",
"state": "present",
"uid": 2020
}
4.3. selinux
通常在初始化的时候,会关闭防火墙和selinux,selinux模块较为简单。
configfile 指定selinux配置文件地址,默认/etc/selinux/config
state 期望状态,支持disabled, enforcing, permissive
[root@duduniao modules]# ansible -i hosts all -m selinux -a "state=disabled"
10.4.7.51 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"configfile": "/etc/selinux/config",
"msg": "",
"policy": "targeted",
"reboot_required": false,
"state": "disabled"
}
4.4. cron
user 指定编辑的是谁的计划任务,默认是root
name 指定计划任务名称,目前 state=absent 时必填,未来该参数为必填项
job 指定计划任务的命令,该命令不应该有输出。当state=present时必填
state 期望状态,present 或 absent
disabled 注释计划任务,与 state=present 配合使用
minute 分钟,0-59。默认 *
hour 小时,0-23。默认 *
day 日期,1-31。默认 *
weekday 星期,0-6。默认 *
month 月份,1-12。默认 *
cron_file 指定 /etc/cron.d 下的计划任务文件,而不是修改用户的计划任务
special_time 指定周期,支持annually, daily, hourly, monthly, reboot, weekly, yearly
backup 备份原有的计划任务文件,默认False
env 是否启用计划任务的环境变量,如果启用则为系统环境变量中的 name 和 value
insertafter 与 state=present 和 env=yes 配合使用,将新的值插入已存在的环境变量之后
insertbefore 与 state=present 和 env=yes 配合使用,将新的值插入已存在的环境变量之前
[root@duduniao modules]# ansible -i hosts all -m cron -a "name='test cron 01' job='echo \$PATH > /tmp/res.txt' user=duduniao" # 创建计划任务
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"test cron 01"
]
}
[root@duduniao modules]# ansible -i hosts all -m shell -a "su - duduniao -c 'crontab -l' "
10.4.7.51 | CHANGED | rc=0 >>
#Ansible: test cron 01
* * * * * echo $PATH > /tmp/res.txt
[root@duduniao modules]# ansible -i hosts all -m shell -a "cat /tmp/res.txt"
10.4.7.51 | CHANGED | rc=0 >>
/usr/bin:/bin
[root@duduniao modules]# ansible -i hosts all -m cron -a "name='test cron 01' job='echo \$PATH > /tmp/res.txt' user=duduniao disabled=yes" # 注释计划任务
10.4.7.51 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"envs": [],
"jobs": [
"test cron 01"
]
}
[root@duduniao modules]# ansible -i hosts all -m shell -a "su - duduniao -c 'crontab -l' "
[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running su
10.4.7.51 | CHANGED | rc=0 >>
#Ansible: test cron 01
#* * * * * echo $PATH > /tmp/res.txt
[root@duduniao modules]# ansible -i hosts all -m cron -a "name='test cron 02' job='fdisk -l &> /tmp/fdisk.txt' "
[root@centos-7-51 ~]# cat /tmp/fdisk.txt # 由于crontab 的环境变量PATH不包含/usr/sbin,所以无法找到 fidks命令
/bin/sh: fdisk: command not found
[root@duduniao modules]# ansible -i hosts all -m cron -a "name=PATH job=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin env=yes" # 添加PATH
[root@centos-7-51 ~]# crontab -l
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin"
#Ansible: test cron 01
* * * * * date &> /tmp/res.txt
#Ansible: test cron 02
* * * * * fdisk -l &> /tmp/fdisk.txt
[root@centos-7-51 ~]# cat /tmp/fdisk.txt
Disk /dev/sda: 21.5 GB, 21474836480 bytes, 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk label type: dos
Disk identifier: 0x000aa0ae
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 1026047 512000 83 Linux
/dev/sda2 1026048 9414655 4194304 82 Linux swap / Solaris
/dev/sda3 9414656 41943039 16264192 83 Linux
5. 其它模块
ansible 涉及到的模块太多,不可能都去学习,除了常用的模块之外,其它在需要用到的过程是查阅 ansible-doc 或者 google 即可。如操作docker,使用 docker_container;发起HTTP请求,采用 uri 等等。
5.1. ping
用于检测远程主机的连通性,确切来说是检测其 ssh 服务的连通性,涉及到 ssh 登陆的过程。
data 如果检测通过,返回data。默认data值为pong
[root@devops-7-3 ansible_learn]# ansible all -m ping -a "data=xxx"
10.4.7.52 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "xxx"
}
10.4.7.51 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "xxx"
}
10.4.7.53 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "xxx"
}
5.2. fail
用于自定义错误和手动抛出错误的场景,一般在playbook中可能会用到。
msg 返回msg信息
[root@duduniao ansible_temps]# ansible test -m fail -a "msg='xxx' "
node1 | FAILED! => {
"changed": false,
"msg": "xxx"
}
node2 | FAILED! => {
"changed": false,
"msg": "xxx"
}
6. 补充说明
上述的案例中,都是使用ansible命令在命令行使用参数的方式去执行命令,这种方式称为 ad-hoc ,这在运维较多服务器的场景下很常见。但是使用ad-hoc方式存在很多问题:
- 运维中涉及的模块较多,如执行shell命令、查询CPU使用率、查询进程、推拉文件等,而且参数还比较多,写起来比较麻烦
- 执行效率很低,尤其是面对几百上千台服务器时,效率远远低于使用 for 循环配合 ssh 方式
- 执行的结果不适合二次处理,且不适合运维人员解读
基于以上的问题,本人编写了一个shell脚本,采用的也是模块化的方式编写,覆盖常用运维场景,且经过生产实践检验,适合替代ad-hoc。由于某些特殊原因,比生产环境中少了一些模块,不过这些模块读者可以自己编写。
6.1. 脚本用法
该脚本是基于ssh通道完成命令的批量执行,批量推文件和拉文件。可以根据自己的业务需求编写模块,提高批处理效率。
当前脚本没有提供输入密码的选项,适合在打通了ssh通道的跳板机操作
Usage:
scan_host.sh module ([-i] ip_list_file|-h ip1 ip2 ...) [-u ssh_user] [-i fork_num] [args]
module: 模块函数名称,默认支持: cmd,ping,push,pull
-i: 指定ip地址列表文件,脚本会自动剔除包含 # 的行
-h: 指定IP地址列表,可指定多个
-u: 指定ssh远程登陆的用户
-i: 指定并发数,默认为5
args: 参数
Example:
scan_host.sh ping ip.list # 从ip.list中取出非注释行的IP地址,执行ping模块
scan_host.sh cmd -h ip1 ip2 ip3 "commands" # 批量执行命令
scan_host.sh cmd ip.txt -f 1 "commands" # 串行执行执行命令
scan_host.sh push ip.list local_dir|local_file [local_dir|local_file] [local_dir|local_file] remote_dir # 推文件
scan_host.sh pull ip.list remote_dir|remote_file [remote_dir|remote_file] [remote_dir|remote_file] local_dir # 拉文件,Local_dir不存在会自动创建
6.2. 案例
[root@elk-7-41 src]# echo 10.4.7.4{0..5} 10.4.7.10{0..5} | xargs -n 1 > ip.txt
6.2.1. ping模块,测试连通性
[root@elk-7-41 src]# scan_host.sh ping ip.txt -f 10 # 以10个并发进程镜像探测
6.2.2. push模块,推文件或者目录
[root@elk-7-41 src]# scan_host.sh push -h 10.4.7.42 10.4.7.101 10.4.7.103 jdk-1.8.tar.gz apollo-* /tmp/ # 推文件
10.4.7.42 jdk-1.8.tar.gz apollo-adminservice-1.5.1-github.zip apollo-configservice-1.5.1-github.zip apollo-portal-1.5.1-github.zip --> /tmp/ Y
10.4.7.101 jdk-1.8.tar.gz apollo-adminservice-1.5.1-github.zip apollo-configservice-1.5.1-github.zip apollo-portal-1.5.1-github.zip --> /tmp/ Y
10.4.7.103 jdk-1.8.tar.gz apollo-adminservice-1.5.1-github.zip apollo-configservice-1.5.1-github.zip apollo-portal-1.5.1-github.zip --> /tmp/ Y
6.2.3. pull模块,拉文件或者目录
[root@elk-7-41 src]# echo '10.4.7.42 10.4.7.101 10.4.7.103 #10.4.7.43' | xargs -n 1 > ip.list
[root@elk-7-41 src]# scan_host.sh pull ip.list /etc/yum.repos.d /etc/passwd xxx # 拖文件
10.4.7.101 yum.repos.d passwd --> xxx SUCCESS
10.4.7.103 yum.repos.d passwd --> xxx SUCCESS
10.4.7.42 yum.repos.d passwd --> xxx SUCCESS
6.2.4. cpu模块,扫描cpu信息
[root@elk-7-41 src]# scan_host.sh cpu ip.list # CPU信息
IP_Address CPU(s) load average(total) R/Total usr sys iowait irq soft idle
10.4.7.101 2 0.00 0.01 0.05 1/97 0.0 0.0 0.0 0.0 0.0 100.0
10.4.7.103 2 0.00 0.01 0.05 1/97 0.0 0.0 0.0 0.0 0.0 100.0
10.4.7.42 1 0.00 0.02 0.05 1/92 0.0 0.0 0.0 0.0 0.0 100.0
6.2.5. cmd模块,执行shell命令
该模块在使用中,有两种比较常用的场景,比如判断一个命令是否执行成功: command >/dev/null 2>&1 && echo yes || echo no
,以及格式化显示 scan_host.sh cmd ip.list "|xargs -n 2
[root@elk-7-41 src]# scan_host.sh cmd ip.list "yum install -q -y httpd && systemctl start httpd && systemctl enable httpd"
10.4.7.103
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.
10.4.7.42
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.
10.4.7.101
Created symlink from /etc/systemd/system/multi-user.target.wants/httpd.service to /usr/lib/systemd/system/httpd.service.
[root@elk-7-41 src]# scan_host.sh cmd ip.list "netstat -lntp|grep 80"
10.4.7.42
tcp6 0 0 :::80 :::* LISTEN 10339/httpd
10.4.7.101
tcp6 0 0 :::80 :::* LISTEN 2050/httpd
10.4.7.103
tcp6 0 0 :::80 :::* LISTEN 1903/httpd
6.3. 脚本内容
#!/bin/bash
# Author: 渡渡鸟
# Version: 1.0
# file_name: scan_host.sh
### 参数处理
OPTIONS(){
# 开始处理module参数
if [[ $1 =~ ^(port|cmd|pull|push|ping|mount|cpu)$ ]];then
MODULE=$(echo $1 | tr 'a-z' 'A-Z') ; shift
else
USAGE ; exit
fi
# 开始处理IP地址参数
if [[ $1 == "-i" && -f $2 ]];then
IP_LIST=$2 ; shift ; shift
elif [[ $1 != "-i" && $1 != "-h" && -f $1 ]];then
IP_LIST=$1 ; shift
elif [[ $1 == "-h" && $2 =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]];then
shift ; IP_LIST=".$$.ip.list"; [ -f $IP_LIST ] && rm -f $IP_LIST
while :
do
echo $1 >> $IP_LIST ; shift
[[ $1 =~ ^([0-9]{1,3}\.){3}[0-9]{1,3}$ ]] || break
done
else
USAGE;exit
fi
# 开始处理Options;为了避免脚本使用过多的选项和降低脚本的复杂性,此处不采用 getopts 和 getopt.
if [[ $1 == "-f" && $2 =~ ^[0-9]+$ ]];then
FORK_NUM=$2 ; shift ; shift
elif [[ $1 == "-u" && ! -z $2 ]];then
SSH_USER=$2 ; shift ; shift
fi
if [[ $1 == "-u" && ! -z $2 ]];then
SSH_USER=$2 ; shift ; shift
elif [[ $1 == "-f" && $2 =~ ^[0-9]+$ ]];then
FORK_NUM=$2 ; shift ; shift
fi
[ -z $FORK_NUM ] && FORK_NUM=5 # 默认并发为5
[ -z $SSH_USER ] && SSH_USER=$USER # 默认为当前用户
# 开始执行脚本,如果需要的话,可以考虑加 trap 捕捉kill命令,用于删除可能存在的临时文件 .$$.ip.list
FORK
$MODULE $@
exec 996>&-
[ -f .$$.ip.list ] && rm -f .$$.ip.list
}
FORK(){
# 控制并发数,默认为5
mkfifo /tmp/$$.fifo
exec 996<>/tmp/$$.fifo
rm -f /tmp/$$.fifo
for i in $(seq $FORK_NUM); do echo >&996 ;done
}
PING(){
# ping模块,使用ping命令实现,如果失败返回 DOWN,否则UPPER
echo "IP status"|tr " " "\t"
for i in $(cat $IP_LIST|grep -v '#')
do
read -u 996
{
ping -c 1 -w 2 $i >/dev/null 2>&1 && echo -e "$i\tUPPER" || echo -e "\e[47;31m$i\tDOWN\e[0m"
echo >&996
} &
done
wait
}
# CPU 信息
CPU(){
echo -e "IP_Address \tCPU(s) load average(total) R/Total usr sys iowait irq soft idle"
for i in $(cat $IP_LIST|grep -v '#')
do
read -u 996
{
ping -c 1 -w 2 $i >/dev/null 2>&1
[ $? -ne 0 ] && echo -e "\e[47;31m$i\tDOWN\e[0m" && echo >&996 && continue
ssh -o "StrictHostKeyChecking no" ${SSH_USER}@$i "echo -ne \"$i\t\";awk '/processor/{sum+=1}END{printf \"%-9s\",sum}' /proc/cpuinfo; top -b -d 1 -n 2|grep -E '^(top|Task|%?Cpu)'|tail -n 3|sed 's/%/ /g;s/%/ /g;s/,/ /g'|awk '{if(NR==1) printf \"%7-s %7-s %12-s\",\$(NF-2),\$(NF-1),\$NF;if(NR==2) printf \"%-15s\",\$4\"/\"\$2;if(NR==3) printf \"%-7s %-7s %-7s %-7s %-7s %-7s\n\",\$2,\$4,\$10,\$12,\$14,\$8}'" 2>&1 | grep -v 'Authorized'
echo >&996
} &
done
wait
}
# 推文件
PUSH(){
## 确认本地文件和远程主机目录
[ $# -lt 2 ] && USAGE && exit || FILES=''
for file in $@
do
[ $# -ge 2 ] && FILES="$FILES $1" && shift || REMOTE_DIR=$1
done
###
for i in $(cat $IP_LIST|grep -v '#')
do
read -u 996
{
ping -c 1 -w 2 $i >/dev/null 2>&1
[ $? -ne 0 ] && echo -e "\e[47;31m$i\tDOWN\e[0m" && echo >&996 && continue
scp -o "StrictHostKeyChecking no" -r $FILES ${SSH_USER}@$i:$REMOTE_DIR >/dev/null 2>&1 && echo -e "$i\t $FILES --> $REMOTE_DIR Y" || echo -e "\e[47;31m$i\t $FILES --> $REMOTE_DIR N\e[0m"|tr " " "\t"
echo >&996
} &
done
wait
}
# 拉文件
PULL(){
[ $# -lt 2 ] && USAGE && exit
for file in $@
do
[[ $# -ge 2 && -z $FILES ]] && FILES="$1" && shift && continue
[[ $# -ge 2 ]] && FILES="$FILES,$1" && shift && continue
LOCAL_DIR=$1
[[ -e $LOCAL_DIR && ! -d $LOCAL_DIR ]] && echo "$LOCAL_DIR isn't a directory!" && USAGE && exit
[[ ! -e $LOCAL_DIR ]] && mkdir -p $LOCAL_DIR
REMOTE_FILES=$(echo $FILES|tr ',' '\n'|awk -F'/' '{print $NF}'|xargs )
REMOTE_FILES_COUNTS=$(echo $FILES|tr ',' '\n'|wc -l)
done
for i in $(cat $IP_LIST|grep -v '#')
do
read -u 996
{
ping -c 1 -w 2 $i >/dev/null 2>&1
[ $? -ne 0 ] && echo -e "\e[47;31m$i\tDOWN\e[0m" && echo >&996 && continue
[ -e $LOCAL_DIR/$i/ ] || mkdir $LOCAL_DIR/$i/
if [ $REMOTE_FILES_COUNTS -eq 1 ];then
scp -r -o "StrictHostKeyChecking no" ${SSH_USER}@$i:$FILES $LOCAL_DIR/$i/ >/dev/null 2>&1 && echo -e "$i\t $REMOTE_FILES --> $LOCAL_DIR SUCCESS" || echo -e "$i\t $REMOTE_FILES --> $LOCAL_DIR \e[47;31mFAILED\e[0m"
else
scp -r -o "StrictHostKeyChecking no" ${SSH_USER}@$i:{$FILES} $LOCAL_DIR/$i/ >/dev/null 2>&1 && echo -e "$i\t $REMOTE_FILES --> $LOCAL_DIR SUCCESS" || echo -e "$i\t $REMOTE_FILES --> $LOCAL_DIR \e[47;31mFAILED\e[0m"
fi
echo >&996
} &
done
wait
}
# 远程执行命令
CMD(){
CMDS=$@
for i in $(cat $IP_LIST|grep -v '#')
do
read -u 996
{
ping -c 1 -w 2 $i >/dev/null 2>&1
[ $? -ne 0 ] && echo -e "\e[47;31m$i\tDOWN\e[0m" && echo >&996 && continue
ssh -o "StrictHostKeyChecking no" ${SSH_USER}@$i "echo $i >/tmp/$$.log;chmod 666 /tmp/$$.log ; ($CMDS) >>/tmp/$$.log 2>&1 ; cat /tmp/$$.log ; rm -f /tmp/$$.log " 2>&1 | grep -v 'Authorized'
echo >&996
} &
done
wait
}
# 扫描端口,可以使用 netstat 和 ss 命令获取,读者自行添加,建议端口号按照从小到大展示
PORT(){
:
}
# 扫描挂载信息,读者自行添加
MOUNT(){
:
}
USAGE(){
cat << EOF
该脚本是基于ssh通道完成命令的批量执行,批量推文件和拉文件。可以根据自己的业务需求编写模块,提高批处理效率。
当前脚本没有提供输入密码的选项,适合在打通了ssh通道的跳板机操作
Usage:
scan_host.sh module ([-i] ip_list_file|-h ip1 ip2 ...) [-u ssh_user] [-i fork_num] [args]
module: 模块函数名称,默认支持: cmd,ping,push,pull
-i: 指定ip地址列表文件,脚本会自动剔除包含 # 的行
-h: 指定IP地址列表,可指定多个
-u: 指定ssh远程登陆的用户
-i: 指定并发数,默认为5
args: 参数
Example:
scan_host.sh ping ip.list # 从ip.list中取出非注释行的IP地址,执行ping模块
scan_host.sh cmd -h ip1 ip2 ip3 "commands" # 批量执行命令
scan_host.sh cmd ip.txt -f 1 "commands" # 串行执行执行命令
scan_host.sh push ip.list local_dir|local_file [local_dir|local_file] [local_dir|local_file] remote_dir # 推文件
scan_host.sh pull ip.list remote_dir|remote_file [remote_dir|remote_file] [remote_dir|remote_file] local_dir # 拉文件,Local_dir不存在会自动创建
EOF
}
OPTIONS $@