ansible 常用模块

ansible 常用模块

1)ping模块

主机连通性测试 我们使用ansible web -m ping命令来进行主机连通性测试,效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
ansible@ansible:~$ ansible all -m ping 
192.168.xxxxxx.92 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
192.168.xxxxxx.114 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
192.168.xxxxxx.87 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}

2)command模块

这个模块可以直接在远程主机上执行命令,并将结果返回本主机。

command模块的常用参数如下:

chdir           # 在执行命令之前,先切换到该目录
executable      # 切换shell来执行命令,需要使用命令的绝对路径
free_form       # 要执行的Linux指令,一般使用Ansible的-a参数代替。
creates         # 一个文件名,当这个文件存在,则该命令不执行,可以用来做判断
removes         # 一个文件名,这个文件不存在,则该命令不执行

功能:在远程主机执行 shell 命令;为默认模块,可省略 -m 选项;

注意:不支持管道命令 |;

在被控机器上执行 date 命令

1
2
3
4
5
6
7
ansible@ansible:~$ ansible all -m command -a 'date'
192.168.xxx.92 | CHANGED | rc=0 >>
Tue 07 Dec 2021 02:08:46 PM UTC
192.168.xxx.87 | CHANGED | rc=0 >>
Tue 07 Dec 2021 02:08:43 PM UTC
192.168.xxx.114 | CHANGED | rc=0 >>
Tue 07 Dec 2021 02:08:46 PM UTC

在被控机器上 设置时区

1
2
3
4
5
6
ansible all -m command -a 'sudo timedatectl set-timezone Asia/Shanghai'
192.168.xxx.87 | CHANGED | rc=0 >>

192.168.xxx.92 | CHANGED | rc=0 >>

192.168.xxx.114 | CHANGED | rc=0 >>

在被控机器上 查看设置时区

1
2
3
4
5
6
7
ansible@ansible:~$ ansible all -m command -a 'cat /etc/timezone'
192.168.xxx.114 | CHANGED | rc=0 >>
Asia/Shanghai
192.168.xxx.87 | CHANGED | rc=0 >>
Asia/Shanghai
192.168.xxx.92 | CHANGED | rc=0 >>
Asia/Shanghai

命令模块接受命令名称,后面是空格分隔的列表参数。给定的命令将在所有选定的节点上执行。
它不会通过shell进行处理,比如$HOME和操作如”<”,”>”,”|”,”;”,”&” 工作(需要使用(shell)模块实现这些功能)。注意,该命令不支持| 管道命令。
要想使用 管道 等特殊的用法,可以像下面这样 利用 bash -c 这样执行一段脚本代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
ansible rmsz -m command -a 'bash -c "git config -l|grep push"'
192.168.xxx.173 | CHANGED | rc=0 >>
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sh.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sz.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-nj.ansible.com
192.168.xxx.175 | CHANGED | rc=0 >>
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sh.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sz.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-nj.ansible.com
192.168.xxx.172 | CHANGED | rc=0 >>
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sh.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sz.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-nj.ansible.com
192.168.xxx.171 | CHANGED | rc=0 >>
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sh.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sz.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-nj.ansible.com
192.168.xxx.174 | CHANGED | rc=0 >>
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sh.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sz.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-nj.ansible.com
192.168.xxx.176 | CHANGED | rc=0 >>
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sh.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-sz.ansible.com
url.ssh://gerrit.ansible.com.pushinsteadof=ssh://gerrit-nj.ansible.com
1
2
3
ansible rmsz -m command -a 'git config -l|grep push'
直接这样执行 是不行的!!!

示例一:command模块基础用法,在远端主机执行命令:

1
2
3
4
ansible 192.168.20.22 -a "id"
192.168.20.22 | CHANGED | rc=0 >>
uid=0(root) gid=0(root) groups=0(root)

示例二:在被控端主机切换到指定目录,执行命令:

1
2
3
ansible 192.168.20.22 -a "chdir=/tmp pwd"
192.168.20.22 | CHANGED | rc=0 >>
/tmp

示例三:creates:指定的文件存在时,不执行对应命令:

1
2
3
4
ansible 192.168.20.22 -a "creates=/etc/passwd ls"
192.168.20.22 | SUCCESS | rc=0 >>
skipped, since /etc/passwd exists <==跳过,未执行;

示例四:removes:与creates相反,指定的文件存在,则执行对应命令:

1
2
3
4
5
ansible 192.168.20.22 -a "removes=/etc/passwd ls"
192.168.20.22 | CHANGED | rc=0 >>
anaconda-ks.cfg
apache-tomcat-10.0.7.tar.gz

3)shell模块

shell模块可以在远程主机上调用shell解释器运行命令,支持shell的各种功能,例如管道等。

功能:在远程主机执行 Shell 命令,支持管道等特殊符号的操作,比command模块使用广泛;

shell模块的常用参数如下:

chdir DIR 	执行ansible时,切换到指定的目录
creates FILE 	如果文件FILE存在,则不执行命令
removes FILE 	如果文件FILE存在,则执行命令

shell模块支持管道命令,在被控主机上创建用户和密码:

1
2
3
4
5
6
7
8
ansible 192.168.20.22 -m shell -a 'useradd xxx'
192.168.20.22 | CHANGED | rc=0 >>

ansible 192.168.20.22 -m shell -a 'echo 123456 | passwd --stdin xxx'
192.168.20.22 | CHANGED | rc=0 >>
Changing password for user xxx.
passwd: all authentication tokens updated successfully.

注意:调用bash执行命令 类似cat /tmp/stanley.md | awk -F’|’ ‘{print $1,$2}’ &> /tmp/example.txt这些复杂命令,即使使用shell也可能会失败,解决办法:写到脚本中,copy到远程,执行,再把需要的结果拉回执行命令的机器。

注意:虽然可以使用shell模块完成绝大多数操作,但是shell模块无法很好的保证ansible的幂等性,因此建议使用以下各个专用模块完成特定的功能,可以保证幂等性。

4)copy模块

这个模块用于将文件复制到远程主机,同时支持给定内容生成文件和修改权限等。

1
2
3
4
5
6
7
8
src 	复制的源文件路径,若源文件为目录,默认进行递归复制,如果路劲以“/”结尾,仅会复制目录下的内容,该目录本身不会复制,如果路径不带“/”,目录本身和目录下的内容会一并复制过去。
dest 目标绝对路径,如果源是文件夹,目标也必须是文件夹,不存在将创建
backup 如果目标主机已经有源文件,会事先备份,防止覆盖
mode 文件复制到远程并设定权限,默认file=644,directory=755
owner 文件复制到远程并设定属主,默认为root
group 文件复制到远程并设定属组,默认为root
content 将目标文件的内容,指定为content所带的字符串

示例一:把/data/nginx/html/web01/index.html复制到被控主机/tmp目录下,属主属组为nginx,权限为644:

1
2
3
4
5
# ansible NginxWebs -m copy -a "src=/data/nginx/html/web01/index.html dest=/tmp owner=nginx group=nginx mode=644"


# ll /tmp/index.html
-rw-r--r-- 1 nginx nginx 7 Aug 1 11:16 /tmp/index.html

示例二:再次复制上例文件,并对原文件备份:

1
2
3
4
5
6
7
# ansible NginxWebs -m copy -a "src=/data/nginx/html/web01/index.html dest=/tmp owner=nginx group=nginx mode=644 backup=yes"



# ll /tmp/index.html*
-rw-r--r-- 1 nginx nginx 10 Aug 1 11:20 /tmp/index.html
-rw-r--r-- 1 nginx nginx 7 Aug 1 11:16 /tmp/index.html.6043.2021-08-01@11:20:39~ <==备份的原文件

往远程的主机文件中写入内容,如果文件不存在则创建:

1
2
3
4
5
# ansible NginxWebs -m copy -a "content="Http_Server\n" dest=/var/www/html/index.html"


# cat /var/www/html/index.html
Http_Server

示例四:复制目录到目标主机:

1
2
3
4
5
# ansible NginxWebs -m copy -a "src=/root/test dest=/root"

# ll /root/test/
total 4
-rw-r--r-- 1 root root 3258 Aug 1 11:26 nginx.conf

示例 5:复制目录到目标主机:目标目录不存在,目标目录多一级目录的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ ansible 10.0.12.31 -m copy -a 'src=./telegraf dest=/tmp/telegraf'
10.0.12.31 | CHANGED => {
"changed": true,
"dest": "/tmp/telegraf/",
"src": "/home/buildfarm/./telegraf"
}
$ tree /tmp/telegraf/ # 在目标 机器上查看发现 目录结构 是 /tmp/telegraf/telegraf 这样的,是把源目录telegraf 复制到 目标 /tmp/telegraf 目录里面 了。目标目录不存在是会自动创建的
/tmp/telegraf/
└── telegraf
├── telegraf
├── telegraf.conf
├── telegraf.log
├── telegraf.pid
├── telegraf.service
└── telegraf.sh

1 directory, 6 files

示例 6:复制目录到目标主机:目标目录只有一级目录的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ ansible 10.0.12.31 -m copy -a 'src=./telegraf dest=/tmp/'
10.0.12.31 | CHANGED => {
"changed": true,
"dest": "/tmp/",
"src": "/home/buildfarm/./telegraf"
}
$ tree /tmp/telegraf/ # 在目标 机器上查看发现,这个和上面的例子就很好的对比出来 差异了
/tmp/telegraf/
├── telegraf
├── telegraf.conf
├── telegraf.log
├── telegraf.pid
├── telegraf.service
└── telegraf.sh

示例 6:复制目录到目标主机:目标目录不存在,并且有多级级目录的,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ ansible 10.0.12.31 -m copy -a 'src=./telegraf dest=/tmp/a/b/c/telegraf'
10.0.12.31 | CHANGED => {
"changed": true,
"dest": "/tmp/a/b/c/telegraf/",
"src": "/home/buildfarm/./telegraf"
}
$ tree /tmp/a 这个和 例 5 一样的,会放到目标 目录 里面,等于 /tmp/a/b/c/telegraf/telegraf
/tmp/a
└── b
└── c
└── telegraf
└── telegraf
├── telegraf
├── telegraf.conf
├── telegraf.log
├── telegraf.pid
├── telegraf.service
└── telegraf.sh

4 directories, 6 files





示例 7:复制目录到目标主机:目标目录不存在,并且有多级级目录的, 这个和 上面的 例6 做个 对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
$ ansible 10.0.12.31 -m copy -a 'src=./telegraf/ dest=/tmp/a/b/c/telegraf'
10.0.12.31 | CHANGED => {
"changed": true,
"dest": "/tmp/a/b/c/telegraf/",
"src": "/home/buildfarm/./telegraf/"
}

$ tree /tmp/a 这个和 例 6 做个 对比 , 等于 /tmp/a/b/c/telegraf, 源目录如果 / 结尾的话 情况就不一样了,这个和rsync 很类似
/tmp/a
└── b
└── c
└── telegraf
├── telegraf
├── telegraf.conf
├── telegraf.log
├── telegraf.pid
├── telegraf.service
└── telegraf.sh

3 directories, 6 files
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ ansible 10.0.12.31 -m copy -a 'src=./telegraf dest=/tmp/a/b/c/telegraf/'
10.0.12.31 | CHANGED => {
"changed": true,
"dest": "/tmp/a/b/c/telegraf/",
"src": "/home/buildfarm/./telegraf"
}
$ tree /tmp/a
/tmp/a
└── b
└── c
└── telegraf
└── telegraf
├── telegraf
├── telegraf.conf
├── telegraf.log
├── telegraf.pid
├── telegraf.service
└── telegraf.sh

结果同 示例 6,

$ ansible 10.0.12.31 -m copy -a 'src=./telegraf/ dest=/tmp/a/b/c/telegraf/'
10.0.12.31 | CHANGED => {
"changed": true,
"dest": "/tmp/a/b/c/telegraf/",
"src": "/home/buildfarm/./telegraf/"
}
$ tree /tmp/a
/tmp/a
└── b
└── c
└── telegraf
├── telegraf
├── telegraf.conf
├── telegraf.log
├── telegraf.pid
├── telegraf.service
└── telegraf.sh

结果同 示例 7



最终 放不放到子目录里面,是要看 源路径 上 是否 / 结尾的,类似 rsync 命令


5)fetch模块

作用:从客户端取文件(只能是文件,不支持目录)至服务器端的目录里,与copy相反,如果一定要拉取目录,可以先将目录tar,再拉取。

主要参数如下:

参数 	说明
src 	复制的源文件路径,源文件只能是文件
dest 	目标绝对路径

示例一:把被控主机的/etc/nginx/nginx/conf配置文件拷贝到本机的/root/nginx目录下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

$ ansible 10.0.12.31 -m fetch -a 'src=/etc/hostname dest=/tmp/fetch/aaaaa'
10.0.12.31 | CHANGED => {
"changed": true,
"checksum": "8260afc442f28647c4a78cdcc12c492f7b580f15",
"dest": "/tmp/fetch/aaaaa/10.0.12.31/etc/hostname",
"md5sum": "b9613c443c158f95653754a49b211171",
"remote_checksum": "8260afc442f28647c4a78cdcc12c492f7b580f15",
"remote_md5sum": null
}


#注意:把远程主机文件拷贝到本机时,会为每个远程主机建立一个文件夹,名称就是该远程主机的ip地址,然后把文件分别放到对应主机的目录下;
#目标目录不存在是可以创建出来的,源文件必须是一个存在的文件!!!
$ tree /tmp/fetch/
/tmp/fetch/
└── aaaaa
└── 10.0.12.31
└── etc
└── hostname

3 directories, 1 file

示例二:拷贝远程主机的目录到本机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#1.首先需要把远程主机的目录打包,默认打包到远程主机的家目录下(/root)
# ansible NginxWebs -m shell -a 'tar jcf log.tar.bzip2 /var/log/nginx/access*'
192.168.20.23 | CHANGED | rc=0 >>
tar: Removing leading `/' from member names
192.168.20.22 | CHANGED | rc=0 >>
tar: Removing leading `/' from member names

#2.把打包文件取回本机:
# ansible NginxWebs -m fetch -a 'src=/root/log.tar.bzip2 dest=/root/nginx'
192.168.20.23 | CHANGED => {
"changed": true,
"checksum": "832b6b9863baf60970f0972c749df8a26221ab26",
"dest": "/root/nginx/192.168.20.23/root/log.tar.bzip2",
"md5sum": "86c762c3ab6f3253c6b6be1739a95ac8",
"remote_checksum": "832b6b9863baf60970f0972c749df8a26221ab26",
"remote_md5sum": null
}
192.168.20.22 | CHANGED => {
"changed": true,
"checksum": "c66537be74f74e1c03254be3400ce7af4a1fe4bb",
"dest": "/root/nginx/192.168.20.22/root/log.tar.bzip2",
"md5sum": "74671b6a38285ae2d576451b3b248f3e",
"remote_checksum": "c66537be74f74e1c03254be3400ce7af4a1fe4bb",
"remote_md5sum": null
}

# tree /root/nginx
/root/nginx
├── 192.168.20.22
│ ├── etc
│ │ └── nginx
│ │ └── nginx.conf
│ └── root
│ └── log.tar.bzip2
└── 192.168.20.23
├── etc
│ └── nginx
│ └── nginx.conf
└── root
└── log.tar.bzip2

8 directories, 4 files

6)file模块

功能:为被控端创建文件或目录,设定权限属性;

主要参数如下:

path 	指定远程服务器的路径,也可以写成‘dest’,‘name’
state 	状态,可以将值设定为directory表示创建目录,设定为touch表示创建文件,设定为link表示创建软连接,设定为hard表示创建硬连接,设定为absent表示删除目录文件或链接
mode 	文件复制到远程并设定权限,默认file=644,directory=755
owner 	文件复制到远程并设定属主,默认为root
group 	文件复制到远程并设定属组,默认为root
recurese 	递归修改

示例一:创建文件/root/f1.sh,并设定属主、属组、权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# ansible NginxWebs -m file -a 'path=/root/f1.sh owner=root group=root mode=755 state=touch'
192.168.20.23 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/f1.sh",
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}
192.168.20.22 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/f1.sh",
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"size": 0,
"state": "file",
"uid": 0
}


示例二:修改上例中文件的属主属组为xu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# ansible NginxWebs -m file -a 'path=/root/f1.sh owner=xu group=xu'
192.168.20.22 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 1000,
"group": "xu",
"mode": "0755",
"owner": "xu",
"path": "/root/f1.sh",
"size": 0,
"state": "file",
"uid": 1000
}
192.168.20.23 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 1000,
"group": "xu",
"mode": "0755",
"owner": "xu",
"path": "/root/f1.sh",
"size": 0,
"state": "file",
"uid": 1000
}

# ll /root/f1.sh
-rwxr-xr-x 1 xu xu 0 Aug 1 22:22 /root/f1.sh

示例三:创建目录/root/test/,并设定属主、属组、权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# ansible NginxWebs -m file -a 'path=/root/test owner=root group=root mode=755 state=directory' 
192.168.20.23 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/root/test",
"size": 6,
"state": "directory",
"uid": 0
}
192.168.20.22 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"gid": 0,
"group": "root",
"mode": "0755",
"owner": "root",
"path": "/root/test",
"size": 6,
"state": "directory",
"uid": 0
}

# ll /root/test/ -d
drwxr-xr-x 2 root root 6 Aug 1 22:26 /root/test/

示例四:为/root/f1.sh创建软链接文件/root/f1.sh.link:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# ansible NginxWebs -m file -a 'src=/root/f1.sh dest=/root/f1.sh.link state=link' 
192.168.20.23 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/f1.sh.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 11,
"src": "/root/f1.sh",
"state": "link",
"uid": 0
}
192.168.20.22 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"dest": "/root/f1.sh.link",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"size": 11,
"src": "/root/f1.sh",
"state": "link",
"uid": 0
}

# ll /root/f1.sh*
-rwxr-xr-x 1 xu xu 0 Aug 1 22:22 /root/f1.sh
lrwxrwxrwx 1 root root 11 Aug 1 22:28 /root/f1.sh.link -> /root/f1.sh

示例五:删除以上示例中创建的目录和文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# ansible NginxWebs -m file -a 'path=/root/f1.sh.link state=absent' 
192.168.20.23 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"path": "/root/f1.sh.link",
"state": "absent"
}
192.168.20.22 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"path": "/root/f1.sh.link",
"state": "absent"
}
# ansible NginxWebs -m file -a 'path=/root/f1.sh state=absent'

# ansible NginxWebs -m file -a 'path=/root/test state=absent'

示例六:也可以删除一级目录(挂载点),会报错,但是可以清楚数据:

1
2
3
4
5
6
 #ansible app -m file -a 'dest=/data/ state=absent'
192.168.169.130 | FAILED! => {
"changed": false, <==报错

#ansible app -a 'ls -l /data/'
total 0 <==数据已经清空

示例七:递归授权目录,类似于-R的作用:

1
2
# ansible webservers -m file -a "path=/tmp/foo state=directory owner=root group=root mode=777 recurse=yes"

7)yum模块

功能:管理软件包,需要确认被管理端为红帽系列的,并且需要被管理端配置好yum源。

主要的参数如下:

    name            指定安装软件包名或软件包URL
    state           指定yum对应的方法,present(Defaults)表示安装;absent表示卸载;latest表示安装最新版本软件包,支持多程序一起安装,用逗号隔开
    enablerepo      允许从哪些仓库获取软件
    disablerepo     禁止从哪些仓库获取软件
    exclude         排除某些软件包,例如kernel
    download_only   仅下载软件包,不安装
    disable_gpg_check   不进行gpg检测
    update_cache        可以在安装包的同时更新yum缓存

示例一:在被控端安装vsftpd,apache软件包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# ansible 192.168.20.23 -m yum -a 'name=vsftpd,httpd state=present'
192.168.20.23 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": true,
"changes": {
"installed": [
"vsftpd",
"httpd"
]
},
"msg": "",
"rc": 0,
"results": [
]
}

# rpm -q httpd
httpd-2.4.6-93.el7.centos.x86_64
# rpm -q vsftpd
vsftpd-3.0.2-27.el7.x86_64

示例二:安装当前最新的Apache软件,通过epel仓库安装:

1
# ansible webservers -m yum -a "name=httpd state=present enablerepo=epel"

示例三:通过公网URL安装 rpm 软件:

1
# ansible webservers -m yum -a "name=https://xx.rpm state=present"

示例四:卸载被控主机的vsftpd,apache软件包:

1
# ansible 192.168.20.23 -m yum -a 'name=vsftpd,httpd state=absent'

示例五:安装最新版本的 Apache 软件,如果存在则更新 Apache:

1
# ansible webservers -m yum -a "name=httpd state=latest

示例六:更新所有的软件包,但排除和kernel相关的:

1
# ansible webservers -m yum -a "name=* state=latest exclude=kernel"

8)systemd模块

功能:管理服务启动与停止,与 service 模块用法一致;

主要参数如下:

    name        指定需要控制的服务名称
    state       指定服务状态,其值可以为stopped、started、reloaded、restarted、running
    enabled         指定服务是否为开机启动,yes为启动,no为不启动
    daemon_reload   yes:重启systemd服务,让unit文件生效

示例一:启动nginx服务,并设置为开机自启:

1
# ansible 192.168.20.23 -m service -a 'name=nginx state=started enabled=yes'

示例二:重新启动nginx服务:

1
# ansible 192.168.20.23 -m service -a 'name=nginx state=restarted'

示例三:重载nginx服务:

1
# ansible 192.168.20.23 -m service -a 'name=nginx state=reloaded'

示例四:停止nginx服务:

1
# ansible 192.168.20.23 -m service -a 'name=nginx state=stopped'

9)cron模块

功能:管理被控端计划任务;

主要参数如下:

    参数 	说明
    name 	定时任务基本描述
    job 	定时任务要执行的命令
    minute 	分
    hour 	小时
    day 	日
    month 	月
    weekday 	周,0-6
    disabled 	yes:禁用计划任务,no:启用计划任务
        absent:删除计划任务

示例一:创建计划任务,每10分钟执行一次同步时间,将此计划任务命名为synctime;

1
2
3
4
5
# ansible NginxWebs -m cron -a 'name="synctime" job="ntpdate 192.168.20.1 &> /dev/null" minute=*/10'

# crontab -l
#Ansible: synctime
*/10 * * * * ntpdate 192.168.20.1 &> /dev/null

示例二:添加定时任务, 每天的凌晨2点和凌晨5点执行一次ls:

1
2
3
4
5
6
7
# ansible NginxWebs -m cron -a 'name="ls" job="ls &> /dev/null" minute=0 hour=2,5'

# crontab -l
#Ansible: synctime
*/10 * * * * ntpdate 192.168.20.1 &> /dev/null
#Ansible: ls
0 2,5 * * * ls &> /dev/null

示例三:禁用上面示例的计划任务:

1
2
3
4
5
6
7
8
9
10
# ansible NginxWebs -m cron -a 'name="ls" job="ls &> /dev/null" minute=0 hour=2,5 disabled=yes'

# ansible NginxWebs -m cron -a 'name="synctime" job="ntpdate 192.168.20.1 &> /dev/null" minute=*/10 disabled=yes'

#被控主机被注释掉了
# crontab -l
#Ansible: synctime
#*/10 * * * * ntpdate 192.168.20.1 &> /dev/null
#Ansible: ls
#0 2,5 * * * ls &> /dev/null

示例四:删除上述的计划任务:

1
2
3
# ansible NginxWebs -m cron -a 'name="synctime" state=absent'

# ansible NginxWebs -m cron -a 'name="ls" state=absent'

10)get_url模块

功能:通过互联网下载软件至被控端本地;

    主要参数如下:
    参数 	说明
    url 	资源文件在互联网上的具体url地址
    dest 	文件下载位置的绝对路径
    mode 	文件下载位置的绝对路径
    checksum 	对下载的资源进行校验
    timeout 	URL请求超时时间,默认10s

示例一:下载互联网的软件至本地:

1
# ansible webservers -m get_url -a "url=https://raw.githubusercontent.com/psf/black/main/README.md dest=/tmp"

示例二:下载互联网文件并进行 md5 校验:

1
# ansible webservers -m get_url -a "url=http,https dest=/opt checksum=md5:76eb3af80ffd"

11)mount模块

功能:管理被控端设备挂载;

    主要参数如下:
    参数 	说明
    src 	本地或远程设备的路径
    path 	设备挂载至本地的路径
    fstype 	挂载的文件系统类型,xfs、nfs...
    opts 	挂载的参数,defaults、ro...
    state 	挂载的状态,absent、mounted、unmounted

环境准备:将 ansible 作为 nfs 服务端, 192.168.20.22、192.168.20.23 作为 nfs客户端挂载;

1
2
3
4
5
6
7
8
9
10
# ansible localhost -m yum -a 'name=nfs-utils state=present'

# ansible localhost -m file -a 'path=/data/nfs/ owner=nginx group=nginx state=directory'

# ansible localhost -m copy -a 'dest=/etc/exports content="/data/nfs 192.168.20.0/24(rw,all_squash,anonuid=887,anongid=887)\n"'

# ansible localhost -m service -a 'name=nfs-server state=started'

# exportfs -arv
exporting 192.168.20.0/24:/data/nfs

示例一:挂载 nfs 至本地的 /opt 目录,并实现开机自动挂载:

1
2
3
4
5
6
7
8
# ansible NginxWebs -m mount -a 'src=192.168.20.17:/data/nfs path=/opt fstype=nfs opts=defaults state=mounted'

# df
Filesystem 1K-blocks Used Available Use% Mounted on
192.168.20.17:/data/nfs 154057344 33280 154024064 1% /opt

# cat /etc/fstab
192.168.20.17:/data/nfs /opt nfs defaults 0 0

示例二:临时卸载 nfs 的挂载,但不清理 /etc/fstab :

1
# ansible NginxWebs -m mount -a 'src=192.168.20.17:/data/nfs path=/opt fstype=nfs opts=defaults state=unmounted'

示例三:永久卸载 nfs 挂载,同时清理 /etc/fstab:

1
# ansible NginxWebs -m mount -a 'src=192.168.20.17:/data/nfs path=/opt fstype=nfs opts=defaults state=absent'

12)archive模块

功能:在远端主机打包与压缩;

主要参数如下:
参数 	说明
path 	要压缩的文件或目录
dest 	压缩后的文件
format 	指定打包压缩的类型:bz2、gz、tar、xz、zip

示例一:将 /var/log 目录压缩为 tar.gz 格式,并存储至 /opt 目录下;

1
2
3
4
5
# ansible 192.168.20.23 -m archive -a 'path=/var/log dest=/opt/log.tar.gz format=gz'

# ll /opt
total 692
-rw-r--r-- 1 root root 705807 Aug 2 15:22 log.tar.gz

13)unarchive模块

功能:在远端主机解包与解压缩;

主要参数如下:
参数 	说明
src 	要解压的软件包路径
dest 	解压到目标位置,需要是一个目录
remote_src 	yes:要解压的包在被控端、no:要解压的包在控制端
owner 	文件复制到远程并设定属主,默认为root
group 	文件复制到远程并设定属组,默认为root
mode 	文件复制到远程并设定权限,默认file=644,directory=755

示例一:把压缩包推送到被控端,在被控端主机解压缩:

1
2
3
4
5
#把压缩包拷贝到远端主机:
# ansible 192.168.20.23 -m copy -a 'src=/root/nginx-1.20.1.tar.gz dest=/tmp/'

#在远端主机解压缩:
# ansible 192.168.20.23 -m copy -a 'src=/tmp/nginx-1.20.1.tar.gz dest=/tmp/nginx-1.20.1 remote_src=yes'

示例二:压缩包在ansible主机上,直接解压到被控主机:

1
2
3
4
5
# ansible 192.168.20.23 -m unarchive -a 'src=/root/nginx-1.20.1.tar.gz dest=/tmp/'

# ll /tmp/
total 0
drwxr-xr-x 8 xu1 xu1 158 May 25 20:35 nginx-1.20.1

14)selinux模块

功能:管理远端主机的 SELINUX 防火墙;

主要参数如下:
参数 	说明
state 	Selinux模式:enforcing、permissive、disabled
polocy 	targeted

示例一:设置 selinux 为 enforcing

1
2
3
4
5
# ansible 192.168.20.23 -m selinux -a 'state=enforcing policy=targeted'

# grep "^SELINUX" /etc/selinux/config
SELINUX=enforcing
SELINUXTYPE=targeted

示例二:设置 selinux 为 disabled:

1
2
3
4
5
# ansible 192.168.20.23 -m selinux -a 'state=disabled'

# grep "^SELINUX" /etc/selinux/config
SELINUX=disabled
SELINUXTYPE=targeted

15)service 模块

该模块用于服务程序的管理。
  
其主要选项如下:

    arguments #命令行提供额外的参数
    enabled #设置开机启动。
    name= #服务名称
    runlevel #开机启动的级别,一般不用指定。
    sleep #在重启服务的过程中,是否等待。如在服务关闭以后等待2秒再启动。(定义在剧本中。)
    state #有四种状态,分别为:started--->启动服务, stopped--->停止服务, restarted--->重启服务, reloaded--->重载配置

示例1 开启服务并设置自启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ansible web -m service -a 'name=nginx state=started enabled=true' 
192.168.37.122 | SUCCESS => {
"changed": true,
"enabled": true,
"name": "nginx",
"state": "started",
……
}
192.168.37.133 | SUCCESS => {
"changed": true,
"enabled": true,
"name": "nginx",
"state": "started",
……
}

我们可以去查看一下端口是否打开:

1
2
3
4
5
6
7
8
# ansible web -m shell -a 'ss -ntl'
192.168.37.122 | SUCCESS | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*

192.168.37.133 | SUCCESS | rc=0 >>
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:80 *:*

示例2 关闭服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# ansible web -m service -a 'name=nginx state=stopped'
192.168.37.122 | SUCCESS => {
"changed": true,
"name": "nginx",
"state": "stopped",
……
}
192.168.37.133 | SUCCESS => {
"changed": true,
"name": "nginx",
"state": "stopped",
……
}

# ansible web -m shell -a 'ss -ntl | grep 80'
192.168.37.122 | FAILED | rc=1 >>

192.168.37.133 | FAILED | rc=1 >>

16)user 模块

该模块主要是用来管理用户账号。
  
其主要选项如下:

comment  # 用户的描述信息
createhome  # 是否创建家目录
force  # 在使用state=absent时, 行为与userdel –force一致.
group  # 指定基本组
groups  # 指定附加组,如果指定为(groups=)表示删除所有组
home  # 指定用户家目录
move_home  # 如果设置为home=时, 试图将用户主目录移动到指定的目录
name  # 指定用户名
non_unique  # 该选项允许改变非唯一的用户ID值
password  # 指定用户密码
remove  # 在使用state=absent时, 行为是与userdel –remove一致
shell  # 指定默认shell
state  # 设置帐号状态,不指定为创建,指定值为absent表示删除
system  # 当创建一个用户,设置这个用户是系统用户。这个设置不能更改现有用户
uid  # 指定用户的uid

① 添加一个用户并指定其 uid

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# ansible web -m user -a 'name=keer uid=11111'
192.168.37.122 | SUCCESS => {
"changed": true,
"comment": "",
"createhome": true,
"group": 11111,
"home": "/home/keer",
"name": "keer",
"shell": "/bin/bash",
"state": "present",
"stderr": "useradd: warning: the home directory already exists.\nNot copying any file from skel directory into it.\nCreating mailbox file: File exists\n",
"system": false,
"uid": 11111
}
192.168.37.133 | SUCCESS => {
"changed": true,
"comment": "",
"createhome": true,
"group": 11111,
"home": "/home/keer",
"name": "keer",
"shell": "/bin/bash",
"state": "present",
"stderr": "useradd: warning: the home directory already exists.\nNot copying any file from skel directory into it.\nCreating mailbox file: File exists\n",
"system": false,
"uid": 11111
}

  添加完成,我们可以去查看一下:

1
2
3
4
5
6
# ansible web -m shell -a 'cat /etc/passwd |grep keer'
192.168.37.122 | SUCCESS | rc=0 >>
keer:x:11111:11111::/home/keer:/bin/bash

192.168.37.133 | SUCCESS | rc=0 >>
keer:x:11111:11111::/home/keer:/bin/bash

② 删除用户

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ansible web -m user -a 'name=keer state=absent'
192.168.37.122 | SUCCESS => {
"changed": true,
"force": false,
"name": "keer",
"remove": false,
"state": "absent"
}
192.168.37.133 | SUCCESS => {
"changed": true,
"force": false,
"name": "keer",
"remove": false,
"state": "absent"
}

  一样的,删除之后,我们去看一下:

1
2
3
4
# ansible web -m shell -a 'cat /etc/passwd |grep keer'
192.168.37.122 | FAILED | rc=1 >>

192.168.37.133 | FAILED | rc=1 >>

  发现已经没有这个用户了。

17)group 模块

该模块主要用于添加或删除组。   

常用的选项如下:

gid=  #设置组的GID号
name=  #指定组的名称
state=  #指定组的状态,默认为创建,设置值为absent为删除
system=  #设置值为yes,表示创建为系统组

① 创建组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ansible web -m group -a 'name=sanguo gid=12222'
192.168.37.122 | SUCCESS => {
"changed": true,
"gid": 12222,
"name": "sanguo",
"state": "present",
"system": false
}
192.168.37.133 | SUCCESS => {
"changed": true,
"gid": 12222,
"name": "sanguo",
"state": "present",
"system": false
}

  创建过后,我们来查看一下:

1
2
3
4
5
6
# ansible web -m shell -a 'cat /etc/group | grep 12222' 
192.168.37.122 | SUCCESS | rc=0 >>
sanguo:x:12222:

192.168.37.133 | SUCCESS | rc=0 >>
sanguo:x:12222:

  可以看出,我们的组已经创建成功了。

② 删除组

1
2
3
4
5
6
7
8
9
10
11
# ansible web -m group -a 'name=sanguo state=absent'
192.168.37.122 | SUCCESS => {
"changed": true,
"name": "sanguo",
"state": "absent"
}
192.168.37.133 | SUCCESS => {
"changed": true,
"name": "sanguo",
"state": "absent"
}

  照例查看一下:

1
2
3
4
# ansible web -m shell -a 'cat /etc/group | grep 12222' 
192.168.37.122 | FAILED | rc=1 >>

192.168.37.133 | FAILED | rc=1 >>

  已经没有这个组的相关信息了。

18)script 模块

该模块用于将本机的脚本在被管理端的机器上运行。

  该模块直接指定脚本的路径即可,我们通过例子来看一看到底如何使用的:

首先,我们写一个脚本,并给其加上执行权限:

1
2
3
4
5
6
# vim /tmp/df.sh
#!/bin/bash

date >> /tmp/disk_total.log
df -lh >> /tmp/disk_total.log
# chmod +x /tmp/df.sh

  然后,我们直接运行命令来实现在被管理端执行该脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ansible web -m script -a '/tmp/df.sh'
192.168.37.122 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.37.122 closed.\r\n",
"stdout": "",
"stdout_lines": []
}
192.168.37.133 | SUCCESS => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to 192.168.37.133 closed.\r\n",
"stdout": "",
"stdout_lines": []
}

  照例查看一下文件内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# ansible web -m shell -a 'cat /tmp/disk_total.log'
192.168.37.122 | SUCCESS | rc=0 >>
Tue Dec 5 15:58:21 CST 2017
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 47G 4.4G 43G 10% /
devtmpfs 978M 0 978M 0% /dev
tmpfs 993M 84K 993M 1% /dev/shm
tmpfs 993M 9.1M 984M 1% /run
tmpfs 993M 0 993M 0% /sys/fs/cgroup
/dev/sda3 47G 33M 47G 1% /app
/dev/sda1 950M 153M 798M 17% /boot
tmpfs 199M 16K 199M 1% /run/user/42
tmpfs 199M 0 199M 0% /run/user/0

192.168.37.133 | SUCCESS | rc=0 >>
Tue Dec 5 15:58:21 CST 2017
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 46G 4.1G 40G 10% /
devtmpfs 898M 0 898M 0% /dev
tmpfs 912M 84K 912M 1% /dev/shm
tmpfs 912M 9.0M 903M 1% /run
tmpfs 912M 0 912M 0% /sys/fs/cgroup
/dev/sda3 3.7G 15M 3.4G 1% /app
/dev/sda1 1.9G 141M 1.6G 9% /boot
tmpfs 183M 16K 183M 1% /run/user/42
tmpfs 183M 0 183M 0% /run/user/0

  可以看出已经执行成功了。

19)setup 模块

该模块主要用于收集信息,是通过调用facts组件来实现的。

  facts组件是Ansible用于采集被管机器设备信息的一个功能,我们可以使用setup模块查机器的所有facts信息,可以使用filter来查看指定信息。整个facts信息被包装在一个JSON格式的数据结构中,ansible_facts是最上层的值。

  facts就是变量,内建变量 。每个主机的各种信息,cpu颗数、内存大小等。会存在facts中的某个变量中。调用后返回很多对应主机的信息,在后面的操作中可以根据不同的信息来做不同的操作。如redhat系列用yum安装,而debian系列用apt来安装软件。

① 查看信息
  我们可以直接用命令获取到变量的值,具体我们来看看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# ansible web -m setup -a 'filter="*mem*"'	#查看内存
192.168.37.122 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1116,
"ansible_memory_mb": {
"nocache": {
"free": 1397,
"used": 587
},
"real": {
"free": 1116,
"total": 1984,
"used": 868
},
"swap": {
"cached": 0,
"free": 3813,
"total": 3813,
"used": 0
}
},
"ansible_memtotal_mb": 1984
},
"changed": false
}
192.168.37.133 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1203,
"ansible_memory_mb": {
"nocache": {
"free": 1470,
"used": 353
},
"real": {
"free": 1203,
"total": 1823,
"used": 620
},
"swap": {
"cached": 0,
"free": 3813,
"total": 3813,
"used": 0
}
},
"ansible_memtotal_mb": 1823
},
"changed": false
}

  我们可以通过命令查看一下内存的大小以确认一下是否一致:

1
2
3
4
5
6
7
8
9
10
# ansible web -m shell -a 'free -m'
192.168.37.122 | SUCCESS | rc=0 >>
total used free shared buff/cache available
Mem: 1984 404 1122 9 457 1346
Swap: 3813 0 3813

192.168.37.133 | SUCCESS | rc=0 >>
total used free shared buff/cache available
Mem: 1823 292 1207 9 323 1351
Swap: 3813 0 3813

  可以看出信息是一致的。

② 保存信息

我们的setup模块还有一个很好用的功能就是可以保存我们所筛选的信息至我们的主机上,同时,文件名为我们被管制的主机的IP,这样方便我们知道是哪台机器出的问题。

  
我们可以看一看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# ansible web -m setup -a 'filter="*mem*"' --tree /tmp/facts
192.168.37.122 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1115,
"ansible_memory_mb": {
"nocache": {
"free": 1396,
"used": 588
},
"real": {
"free": 1115,
"total": 1984,
"used": 869
},
"swap": {
"cached": 0,
"free": 3813,
"total": 3813,
"used": 0
}
},
"ansible_memtotal_mb": 1984
},
"changed": false
}
192.168.37.133 | SUCCESS => {
"ansible_facts": {
"ansible_memfree_mb": 1199,
"ansible_memory_mb": {
"nocache": {
"free": 1467,
"used": 356
},
"real": {
"free": 1199,
"total": 1823,
"used": 624
},
"swap": {
"cached": 0,
"free": 3813,
"total": 3813,
"used": 0
}
},
"ansible_memtotal_mb": 1823
},
"changed": false
}

  然后我们可以去查看一下:

1
2
3
4
5
# cd /tmp/facts/
# ls
192.168.37.122 192.168.37.133
# cat 192.168.37.122
{"ansible_facts": {"ansible_memfree_mb": 1115, "ansible_memory_mb": {"nocache": {"free": 1396, "used": 588}, "real": {"free": 1115, "total": 1984, "used": 869}, "swap": {"cached": 0, "free": 3813, "total": 3813, "used": 0}}, "ansible_memtotal_mb": 1984}, "changed": false}

ansible执行原理分析

执行之后 主控节点上会是这样的几个进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
│   │                   └─bash,224417
│ │ └─ansible,228966 /home/conda/envs/ansible/bin/ansible bf -i hosts -m command -a sleep 100
│ │ ├─ansible,228971 /home/conda/envs/ansible/bin/ansible bf -i hosts -m command -a sleep 100
│ │ │ └─ssh,229034 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="ansible" -o ConnectTimeout=10 -o ControlPath=/work/jenkins/.ansible/cp/fd15400aed -tt 192.168.xxx.31 /bin/sh -c '/usr/bin/python3 /home/ansible/.ansible/tmp/ansible-tmp-1638944600.2393298-228971-228771323588639/AnsiballZ_command.py && sleep 0'
│ │ ├─ansible,228972 /home/conda/envs/ansible/bin/ansible bf -i hosts -m command -a sleep 100
│ │ │ └─ssh,229035 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="ansible" -o ConnectTimeout=10 -o ControlPath=/work/jenkins/.ansible/cp/0a0c5feff5 -tt 192.168.xxx.32 /bin/sh -c '/usr/bin/python3 /home/ansible/.ansible/tmp/ansible-tmp-1638944600.239494-228972-9855025113577/AnsiballZ_command.py && sleep 0'
│ │ ├─ansible,228974 /home/conda/envs/ansible/bin/ansible bf -i hosts -m command -a sleep 100
│ │ │ └─ssh,229033 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="ansible" -o ConnectTimeout=10 -o ControlPath=/work/jenkins/.ansible/cp/bc143f4fd4 -tt 192.168.xxx.33 /bin/sh -c '/usr/bin/python3 /home/ansible/.ansible/tmp/ansible-tmp-1638944600.2476149-228974-207118697615073/AnsiballZ_command.py && sleep 0'
│ │ ├─ansible,228976 /home/conda/envs/ansible/bin/ansible bf -i hosts -m command -a sleep 100
│ │ │ └─ssh,229036 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="ansible" -o ConnectTimeout=10 -o ControlPath=/work/jenkins/.ansible/cp/bfd44f17d4 -tt 192.168.xxx.34 /bin/sh -c '/usr/bin/python3 /home/ansible/.ansible/tmp/ansible-tmp-1638944600.255245-228976-274177687105611/AnsiballZ_command.py && sleep 0'
│ │ ├─ansible,228979 /home/conda/envs/ansible/bin/ansible bf -i hosts -m command -a sleep 100
│ │ │ └─ssh,229032 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="ansible" -o ConnectTimeout=10 -o ControlPath=/work/jenkins/.ansible/cp/278053c7e1 -tt 192.168.xxx.35 /bin/sh -c '/usr/bin/python3 /home/ansible/.ansible/tmp/ansible-tmp-1638944600.2513506-228979-200134538240917/AnsiballZ_command.py && sleep 0'
│ │ └─{ansible},228970

1. 当我们执行ansible命令 之后发生了什么?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
ansible 192.168.xxx.31 -f 1 -m command -a 'sleep 100' -o

主控节点上执行如下:
ansible,832930 /home/conda/envs/ansible/bin/ansible 192.168.xxx.31 -f 1 -m command -a sleep 100 -o
├─ansible,833070 /home/conda/envs/ansible/bin/ansible 192.168.xxx.31 -f 1 -m command -a sleep 100 -o
└─ssh,833089 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="ansible" -o ConnectTimeout=10 -o ControlPath=/tmp/ansibletmpl/cp/ansible-ssh-%h-%p-%r -tt 192.168.xxx.31 /bin/bash -c '/usr/bin/python3 /tmp/ansibletmpr/ansible-tmp-1638962875.8801572-833070-192363216003291/AnsiballZ_command.py && sleep 0'
│ └─{ansible},833069
可以看到主控节点上是直接执行了 ssh 命令,简写为 ssh 192.168.xxx.31 /bin/bash xxxx
我们还可以看到 是执行了远端服务器上的一个py脚本。

被控节点上执行
└─bash -c /usr/bin/python3 /tmp/ansibletmpr/ansible-tmp-1638962875.8801572-833070-192363216003291/AnsiballZ_command.py && sleep 0
└─python3 /tmp/ansibletmpr/ansible-tmp-1638962875.8801572-833070-192363216003291/AnsiballZ_command.py
└─sleep 100
我们可以看到远端服务器上是执行了一个py脚本,py脚本里面调用了我们的命令 sleep 100 这个。

2. 如何使用sudo、root 等特权命令??

使用 –become-method sudo -b 提升权限去执行命令

1
ansible -i tools/ansible/inventory.conf -m command -a 'sleep 60' --forks 1  192.168.12.31 -v --become-method sudo -b

下面是主控服务器

1
2
3
4
─ansible,457479 /home/conda/envs/ansible/bin/ansible -i tools/ansible/inventory.conf -m command -a sleep 60 --forks 1 192.168.12.31 -v --become-method sudo -b
├─ansible,457587 /home/conda/envs/ansible/bin/ansible -i tools/ansible/inventory.conf -m command -a sleep 60 --forks 1 192.168.12.31 -v --become-method sudo -b
│ └─ssh,457596 -C -o ControlMaster=auto -o ControlPersist=60s -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="buildfarm" -o ConnectTimeout=10 -o ControlPath=/tmp/buildfarm/ansibletmpcp/ansible-ssh-%h-%p-%r -tt 192.168.12.31 /bin/bash -c 'sudo -H -S -n -u root /bin/bash -c '"'"'echo BECOME-SUCCESS-irtokqitnflolaawnheahtwcoduedpsx ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648609937.0120566-457587-22932890217715/AnsiballZ_command.py'"'"' && sleep 0'
└─{ansible},457586

下面是被执行服务器

1
2
3
4
5
6
7
8
│   ├─sshd,2313068
│ │ └─sshd,2313079
│ │ └─bash,2313233 -c sudo -H -S -n -u root /bin/bash -c 'echo BECOME-SUCCESS-irtokqitnflolaawnheahtwcoduedpsx ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648609937.0120566-457587-22932890217715/AnsiballZ_command.py' && sleep 0
│ │ └─sudo,2313234 -H -S -n -u root /bin/bash -c echo BECOME-SUCCESS-irtokqitnflolaawnheahtwcoduedpsx ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648609937.0120566-457587-22932890217715/AnsiballZ_command.py
│ │ └─bash,2313235 -c echo BECOME-SUCCESS-irtokqitnflolaawnheahtwcoduedpsx ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648609937.0120566-457587-22932890217715/AnsiballZ_command.py
│ │ └─python3,2313236 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648609937.0120566-457587-22932890217715/AnsiballZ_command.py
│ │ └─sleep,2313238 60

使用 –become-user ‘’ 指定个空的用户

1
(ansible) buildfarm@jenkins-master:~$ ansible -i tools/ansible/inventory.conf -m command -a 'sleep 60' --forks 1  192.168.12.31 -v --become-method sudo -b --become-user ''

可以发现远程被控服务器就会执行sudo -H -S -n /bin/bash -c ‘’ 这样的命令了,少了一个 -u root 这个参数

1
2
3
4
5
6
7
│   └─sshd,2313389
│ └─sshd,2313400
│ └─bash,2313442 -c sudo -H -S -n /bin/bash -c 'echo BECOME-SUCCESS-rqpombkywyxtrdmhmlrjbsfstljrwscc ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648613811.7588933-542772-245836208212105/AnsiballZ_command.py' && sleep 0
│ └─sudo,2313443 -H -S -n /bin/bash -c echo BECOME-SUCCESS-rqpombkywyxtrdmhmlrjbsfstljrwscc ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648613811.7588933-542772-245836208212105/AnsiballZ_command.py
│ └─bash,2313445 -c echo BECOME-SUCCESS-rqpombkywyxtrdmhmlrjbsfstljrwscc ; /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648613811.7588933-542772-245836208212105/AnsiballZ_command.py
│ └─python3,2313446 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648613811.7588933-542772-245836208212105/AnsiballZ_command.py
│ └─sleep,2313448 60

copy模块执行分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
目标机器上执行 AnsiballZ_copy.py

─ansible,1415889 /home/conda/envs/ansible/bin/ansible 10.0.12.31 -m copy -a src=/work/backup/ dest=/tmp/a/b/c/telegraf/
│ │ ├─ansible,1415895 /home/conda/envs/ansible/bin/ansible 10.0.12.31 -m copy -a src=/work/backup/ dest=/tmp/a/b/c/telegraf/
│ │ │ └─sftp,1417138 -b - -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="buildfarm" -o ConnectTimeout=10 [10.0.12.31]
│ │ │ └─ssh,1417139 -oForwardX11 no -oForwardAgent no -oPermitLocalCommand no -oClearAllForwardings yes -obatchmode yes -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o User="buildfarm" -o ConnectTimeout=10 -oProtocol 2 -s -- 10.0.12.31 sftp
主控服务器会通过ftp 把 src 指定的 源目录下面的文件一个一个上传到 /tmp/buildfarm/ansibletmpr/xxxxx/source 这个文件。tmp路径是 我们在 ansible.cfg 文件中配置的remote_tmp = /tmp/$USER/ansibletmpr

通过ftp上传到目标服务器之后,在目标服务器上会执行 下面这个 AnsiballZ_copy.py 脚本的
└─bash,1838989 -c /usr/bin/python3 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306/AnsiballZ_copy.py && sleep 0
└─python3,1838990 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306/AnsiballZ_copy.py

├── [ 60] /tmp/buildfarm
│   └── [ 60] /tmp/buildfarm/ansibletmpr
│   └── [ 100] /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306
│   ├── [133K] /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306/AnsiballZ_copy.py
│   ├── [128K] /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306/AnsiballZ_stat.py
│   └── [402M] /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306/source
在目标机器上 会把 文件 /tmp/buildfarm/ansibletmpr/ansible-tmp-1648990563.6564553-1431017-227311237310306/source 再次复制到 dest指定的目录下面