我们可以使用命令行的形式使用Ansible模块,ansible-doc -l 显示所有的自带模块。
ansible-doc “模块名” ,查看模块的介绍和案例
ansible-doc -l 查看模块
ansible-doc -s 查看参数
1、执行命令
shell模块:
可以执行Linux系统中的任何命令,就像在本机执行一样。
例:cd到/opt目录下,并将时间写入date.txt文件中
[root@master ansible]# ansible all -m shell -a 'chdir=/opt date > date.txt'
node2 | CHANGED | rc=0 >>
node1 | CHANGED | rc=0 >>
master | CHANGED | rc=0 >>
[root@master ansible]# ansible all -m shell -a 'ls -l /opt/date.txt'
node2 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 43 3月 12 17:37 /opt/date.txtnode1 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 43 3月 12 17:37 /opt/date.txtmaster | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 43 3月 12 17:37 /opt/date.txt
[root@master ansible]# ansible all -m shell -a 'cat /opt/date.txt'
node2 | CHANGED | rc=0 >>
2021年 03月 12日 星期五 17:37:45 CSTnode1 | CHANGED | rc=0 >>
2021年 03月 12日 星期五 17:37:46 CSTmaster | CHANGED | rc=0 >>
2021年 03月 12日 星期五 17:37:45 CST
chdir与remove命令的不同:
chdir:如果存在这个目录则跳过,没有则执行
remove:与chdir命令相反,有则执行,没有则跳过
[root@master ansible]# ansible all -m shell -a 'chdir=/tmp creates=/opt/date.txt pwd'
node2 | SUCCESS | rc=0 >>
skipped, since /opt/date.txt existsnode1 | SUCCESS | rc=0 >>
skipped, since /opt/date.txt existsmaster | SUCCESS | rc=0 >>
skipped, since /opt/date.txt exists[root@master ansible]# ansible all -m shell -a 'chdir=/tmp creates=/opt/date1.txt pwd'
node1 | CHANGED | rc=0 >>
/tmpmaster | CHANGED | rc=0 >>
/tmpnode2 | CHANGED | rc=0 >>
/tmp
command模块:
与shell模块基本相同,但是有些特殊字符存在可能执行不成功。
执行command命令时,直接省略-m 之后的选项
[root@master ansible]# ansible all -a 'cat /opt/date.txt'
node2 | CHANGED | rc=0 >>
2021年 03月 12日 星期五 17:37:45 CSTnode1 | CHANGED | rc=0 >>
2021年 03月 12日 星期五 17:37:46 CSTmaster | CHANGED | rc=0 >>
2021年 03月 12日 星期五 17:37:45 CST
raw模块
与前两个命令相似,但所支持的参数比较少
[root@master ansible]# ansible all -m raw -a 'ls -l /opt/date.txt'
master | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 43 3月 12 17:37 /opt/date.txt
Shared connection to master closed.
node1 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 43 3月 12 17:37 /opt/date.txt
Shared connection to node1 closed.
node2 | CHANGED | rc=0 >>
-rw-r--r--. 1 root root 43 3月 12 17:37 /opt/date.txt
Shared connection to node2 closed.
2、包管理
yum_repository模块
例:在本地局域网中搭建一个ansible下载环境,可供被管理的主机下载
我的用户家目录中已经存在所需要的rpm包
[root@master ~]# systemctl stop firewalld.service
[root@master ~]# setenforce 0
[root@master ~]# mkdir /var/www/html/ansible
[root@master ~]# mkdir /var/www/html/ansible/Packages
[root@master ~]# mv *.rpm /var/www/html/ansible/Packages
[root@master ~]# cd /var/www/html/ansible/
[root@master ansible]# yum install createrepo #制作本地yum源所需要的工具
[root@master ansible]# ls
Packages
[root@master ansible]# ls Packages/
ansible-2.8.0-1.el8ae.noarch.rpm sshpass-1.06-3.el8ae.x86_64.rpm
[root@master ansible]# createrepo .
[root@master ansible]# ls repodata/
[root@master ansible]# systemctl start httpdyum制作完毕:
下发到被管理的节点:
[root@master ansible]# ansible all -m yum_repository -a 'name=ansible2.8 description=ansible2.8 baseurl=http://master/ansible gpgcheck=no enabled=yes'
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"repo": "ansible2.8",
"state": "present"
}
node2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"repo": "ansible2.8",
"state": "present"
}
master | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"repo": "ansible2.8",
"state": "present"
}
检测:在被管理节点[root@node1 ~]# yum repolist
或者使用管理节点查看:
[root@master ansible]# ansible all -m shell -a 'yum repolist'
将yum源移除:[root@master ansible]# ansible all -m yum_repository -a 'name=ansible2.8 state=absent'
state=absent
yum模块
例:用yum模块来为被管理节点安装、升级、下载软件
[root@master ansible]# ansible all -m yum -a 'name=nginx state=latest'
查看下载软件:[root@master ansible]# ansible all -m shell -a 'rpm -q nginx'
node2 | CHANGED | rc=0 >>
nginx-1.14.1-9.module+el8.0.0+4108+af250afe.x86_64node1 | CHANGED | rc=0 >>
nginx-1.14.1-9.module+el8.0.0+4108+af250afe.x86_64master | CHANGED | rc=0 >>
nginx-1.14.1-9.module+el8.0.0+4108+af250afe.x86_64卸载:[root@master ansible]# ansible all -m yum -a 'name=nginx state=absent'
升级所有软件包:
[root@master ansible]# ansible test -m yum -a 'name='*' state=latest'
可以从局域网互联网下载软件
[root@master ansible]# ansible test -m yum -a 'name=网址' #可以不加状态
3、用户管理
group模块
为被管理节点创建一个名为nanfang ,gid为666,身份为系统组的组
[root@master ansible]# ansible all -m group -a 'name=nanfang gid=666 system=yes state=present'
user模块
例:为被管理节点创建tom用户,密码为“123456”
添加密码需要用加密,明文不能识别
[root@master ~]# python3
Python 3.6.8 (default, Oct 11 2019, 15:04:54)
[GCC 8.3.1 20190507 (Red Hat 8.3.1-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import crypt
>>> crypt.crypt('123456')
'$6$aZOJn9.rce4BCQgx$RSZPhjU17QJvH42n2jfTbn/aRK5KTszFrcq77V5c9itRYNy6sIsTuF0uTVL8wfkhr1SNMAzVdVTShlUWAJ8yf.'
>>> exit()[root@master ansible]# ansible all -m user -a 'name=tom password='$6$aZOJn9.rce4BCQgx$RSZPhjU17QJvH42n2jfTbn/aRK5KTszFrcq77V5c9itRYNy6sIsTuF0uTVL8wfkhr1SNMAzVdVTShlUWAJ8yf.'
移除用户:
[root@master ansible]# ansible all -m user -a 'name=tom state=absent remove=yes'
4、计划任务
例:每天1点5分执行,任务输出内容为test
[root@master ansible]# ansible all -m cron -a "name='crontab test' minute=5 hour=1 job='echo test'"
验证:
[root@node1 ~]# crontab -l
#Ansible: crontab test
5 1 * * * echo test删除任务:
[root@master ansible]# ansible all -m cron -a "name='crontab test' state=absent"
5、文件操作
file模块
例:在/opt目录下创建file1.txt文件
[root@master ansible]# ansible node1 -m file -a 'path=/opt/file1.txt state=touch'
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"dest": "/opt/file1.txt",
"gid": 0,
"group": "root",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:usr_t:s0",
"size": 0,
"state": "file",
"uid": 0
}创建软连接:
[root@master ansible]# ansible node1 -m file -a 'path=/opt/linkfile1.txt state=link src=/opt/file1.txt'
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"dest": "/opt/linkfile1.txt",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"secontext": "unconfined_u:object_r:usr_t:s0",
"size": 14,
"src": "/opt/file1.txt",
"state": "link",
"uid": 0
}删除软连接:
[root@master ansible]# ansible node1 -m file -a 'path=/opt/linkfile1.txt state=absent'
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"path": "/opt/linkfile1.txt",
"state": "absent"
}
copy模块
将主机/usr/hang文件内容复制到node1节点中/usr/liu
[root@master ansible]# ansible node1 -m copy -a 'src=/usr/hang dest=/usr/liu owner=root group=root mode=644 backup=yes'
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"backup_file": "/usr/liu.4820.2021-03-13@20:42:35~",
"changed": true,
"checksum": "a4778efbf0b3de49eb36d424c2455b256238d8f1",
"dest": "/usr/liu",
"gid": 0,
"group": "root",
"md5sum": "e2a2456ddb1e10e9a27a979199e9b351",
"mode": "0644",
"owner": "root",
"secontext": "unconfined_u:object_r:usr_t:s0",
"size": 12,
"src": "/root/.ansible/tmp/ansible-tmp-1615639353.678311-113608420942169/source",
"state": "file",
"uid": 0
fetch模块
提取被管理节点中的文件,提取目录会保存原有的目录结构,提取到的文件名一般为被管理节点的主机名或者IP地址
dest 目标地址
src 源
[root@master ansible]# ansible node1 -m fetch -a 'src=/etc/hosts dest=/opt'
node1 | CHANGED => {
"changed": true,
"checksum": "e5d48a063eee9e6987ac4820562132b1b1df5eb4",
"dest": "/opt/node1/etc/hosts",
"md5sum": "c9462631653cc2415539b5885c855c3c",
"remote_checksum": "e5d48a063eee9e6987ac4820562132b1b1df5eb4",
"remote_md5sum": null[root@master ansible]# tree /opt/node1/
/opt/node1/
└── etc
└── hosts1 directory, 1 file
lineinfile模块
用于文件内容修改,替换某一行、在某一行加入或者删除某一行
例:将SELINUX变为enforcing
[root@master ansible]# ansible node1 -m lineinfile -a 'path=/etc/selinux/config regexp="^SELINUX=" line=SELINUX=enforcing'
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"backup": "",
"changed": false,
"msg": ""
}
[root@master ansible]# ansible node1 -m shell -a 'cat /etc/selinux/config'
node1 | CHANGED | rc=0 >># This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
# enforcing - SELinux security policy is enforced.
# permissive - SELinux prints warnings instead of enforcing.
# disabled - No SELinux policy is loaded.
SELINUX=enforcing
# SELINUXTYPE= can take one of these three values:
# targeted - Targeted processes are protected,
# minimum - Modification of targeted policy. Only selected processes are protected.
# mls - Multi Level Security protection.
SELINUXTYPE=targeted
向前面添加一行“one”
[root@master ~]# ansible localhost -m lineinfile -a 'dest=test.txt insertbefore="test(.*)" line="one"'
localhost | CHANGED => {
"backup": "",
"changed": true,
"msg": "line added"
}
[root@master ~]# ansible localhost -a 'cat test.txt'
localhost | CHANGED | rc=0 >>
one
test向后面加入一行“end”
[root@master ~]# ansible localhost -m lineinfile -a 'dest=test.txt insertafter="test(.*)" line="end"'
localhost | CHANGED => {
"backup": "",
"changed": true,
"msg": "line added"
}
[root@master ~]# ansible localhost -a 'cat test.txt'
localhost | CHANGED | rc=0 >>
one
test
end
删除所匹配的行:[root@master ansible]# ansible localhost -m lineinfile -a 'path=test.txt regexp="test(.*)" state=absent'
localhost | SUCCESS => {
"changed": false,
"msg": "file not present"
}
[root@master ~]# ansible localhost -a 'cat test.txt'
localhost | CHANGED | rc=0 >>
one
end
synchronize模块
基于rsync命令批量同步文件
[root@master ansible]# ansible all -m yum -a 'name=rsync state=present'
将node1节点的/etc/hosts 目录同步到master的/tmp下
[root@master ansible]# ansible node1 -m synchronize -a 'src=/etc/hosts dest=/tmp mode=pull'
node1 | CHANGED => {
"changed": true,
"cmd": "/usr/bin/rsync --delay-updates -F --compress --archive --rsh=/usr/bin/ssh -S none -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null --out-format=<<CHANGED>>%i %n%L node1:/etc/hosts /tmp",
"msg": ">f+++++++++ hosts\n",
"rc": 0,
"stdout_lines": [
">f+++++++++ hosts"
]
}
6、防火墙管理
开启防火墙:
[root@master ansible]# ansible all -m service -a 'name=firewalld state=started enabled=true '
允许http服务:
[root@master ansible]# ansible all -m firewalld -a 'service=http permanent=true immediate=true state=enabled'
node2 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"msg": "Permanent and Non-Permanent(immediate) operation"
}
node1 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": false,
"msg": "Permanent and Non-Permanent(immediate) operation"
}
master | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed service http to enabled"
}
允许80端口:
[root@master ansible]# ansible all -m firewalld -a 'port=80/tcp permanent=true immediate=true state=enabled'
node2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed port 80/tcp to enabled"
}
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed port 80/tcp to enabled"
}
master | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed port 80/tcp to enabled"
}
富规则:
[root@master ansible]# ansible all -m firewalld -a 'rich_rule="rule family=ipv4 source address=192.168.83.0/24 service name=http accept" permanent=true immediate=true state=enabled'
node2 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed rich_rule rule family=ipv4 source address=192.168.83.0/24 service name=http accept to enabled"
}
master | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed rich_rule rule family=ipv4 source address=192.168.83.0/24 service name=http accept to enabled"
}
node1 | CHANGED => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/libexec/platform-python"
},
"changed": true,
"msg": "Permanent and Non-Permanent(immediate) operation, Changed rich_rule rule family=ipv4 source address=192.168.83.0/24 service name=http accept to enabled"
}
7、磁盘管理
首先添加一个10G的磁盘
[root@master ~]# lsblk | grep nvme0n2
nvme0n2 259:3 0 10G 0 disk
使用parted模块创建一个1GiB主分区
[root@master ~]# ansible localhost -m parted -a 'device=/dev/nvme0n2 number=1
part_end=1GiB state=present'
localhost | CHANGED => {
"changed": true,
"disk": {
"dev": "/dev/nvme0n2",
"logical_block": 512,
"model": "NVMe Device",
"physical_block": 512,
"size": 10485760.0,
"table": "msdos",
"unit": "kib"
},
"partitions": [
{
"begin": 1024.0,
"end": 1048576.0,
"flags": [],
"fstype": "",
"name": "",
"num": 1,
"size": 1047552.0,
"unit": "kib"
}
],
"script": "unit KiB mklabel msdos mkpart primary 0% 1GiB"
}
使用parted模块创建一个类型为lvm的1G分区
[root@master ~]# ansible localhost -m parted -a 'device=/dev/nvme0n2 number=2
flags=lvm part_start=1GiB part_end=2GiB state=present'
localhost | CHANGED => {
"changed": true,
"disk": {
"dev": "/dev/nvme0n2",
"logical_block": 512,
"model": "NVMe Device",
"physical_block": 512,
"size": 10485760.0,
"table": "msdos",
"unit": "kib"
},
"partitions": [
{
"begin": 1024.0,
"end": 1048576.0,
"flags": [],
"fstype": "",
"name": "",
"num": 1,
"size": 1047552.0,
"unit": "kib"
},
{
"begin": 1048576.0,
"end": 2097152.0,
"flags": [
"lvm"
],
"fstype": "",
"name": "",
"num": 2,
"size": 1048576.0,
"unit": "kib"
}
],
"script": "unit KiB mkpart primary 1GiB 2GiB unit KiB set 2 lvm on"
}
查看:
[root@master ~]# fdisk /dev/nvme0n2
欢迎使用 fdisk (util-linux 2.32.1)。
更改将停留在内存中,直到您决定将更改写入磁盘。
使用写入命令前请三思。
命令(输入 m 获取帮助):p
Disk /dev/nvme0n2:10 GiB,10737418240 字节,20971520 个扇区
单元:扇区 / 1 * 512 = 512 字节
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x2229eb8b
设备 启动 起点 末尾 扇区 大小 Id 类型
/dev/nvme0n2p1 2048 2097151 2095104 1023M 83 Linux
/dev/nvme0n2p2 2097152 4194303 2097152 1G 8e Linux LVM
命令(输入 m 获取帮助):q
移除分区为1的分区:
[root@master ~]# ansible localhost -m parted -a 'device=/dev/nvme0n2 number=2
state=absent'
localhost | CHANGED => {
"changed": true,
"disk": {
"dev": "/dev/nvme0n2",
"logical_block": 512,
"model": "NVMe Device",
"physical_block": 512,
"size": 10485760.0,
"table": "msdos",
"unit": "kib"
},
"partitions": [
{
"begin": 1024.0,
"end": 1048576.0,
"flags": [],
"fstype": "",
"name": "",
"num": 1,
"size": 1047552.0,
"unit": "kib"
}
],
"script": "rm 2"
}
使用lvg模块利用上面的lvm类型分区创建一个名为vg1的卷组
[root@master ~]# ansible localhost -m lvg -a 'pvs=/dev/nvme0n2p1 vg=vg1'
[WARNING]: The value 4 (type int) in a string field was converted to '4' (type string). If
this does not look like what you expect, quote the entire value to ensure it does not
change.
localhost | CHANGED => {
"changed": true
}
[root@master ~]# vgs vg1
VG #PV #LV #SN Attr VSize VFree
vg1 1 0 0 wz--n- 1020.00m 1020.00m
使用lvol模块在vg1卷组上创建一个名为lv的逻辑卷,大小为512M
[root@master ~]# ansible localhost -m lvol -a 'vg=vg1 lv=lv1 size=512'
localhost | CHANGED => {
"changed": true,
"msg": ""
}
[root@master ~]#
[root@master ~]# lvs /dev/vg1/lv1
LV VG Attr LSize Pool Origin Data% Meta% Move Log Cpy%Sync Convert
lv1 vg1 -wi-a----- 512.00m