1. 命令模块

1.1. command

command 是ansible的默认模块,用于执行简单的shell命令,由于功能非常有限(不支持管道、重定向等 符号),一般实际场景中很少使用,大部分都是使用shell默认替代command,且shell模块和command模块参数基本一致。

  1. cmd 指定执行的shell命令
  2. argv 使用列表传递参数而不是将参数作为整个字符串
  3. chdir 切换执行命令的工作目录
  4. creates 指定文件名(支持glob表达式),如果文件存在则不执行
  5. removes 指定文件名(支持glob表达式),如果文件存在则执行
  6. stdin 接收一个命令的标准输入
  7. stdin_add_newline 如果为yes,则使用新的一行去接收标准输入
  8. strip_empty_ends 跳过标准输入和输出的空行
  9. 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 $@

01-2-2-常用模块 - 图1