别以为学会了 管理Ansible配置文件(文章链接地址)这内功心法,就可以去闯荡江湖各种装逼。有心法没招式也是寸步难行啊。
Ad-Hoc 指的临时意思,就像在命令行写的shell命令就是临时命令,在文件中写的shell命令就是脚本 。
Ad-Hoc 就是在命令行直接执行的内容,主要用于临时命令使用场景。
(说这么多废话,就是在命令行上运行需要的命令嘛,扎马步都解释这么多。)
ansible host-pattern -m module [-a ‘module arguments’] [-i inventory]
指令 匹配规则的主机清单 -m 模块名 选项
--version 显示版本
-a 模块参数(如果有)
-m module 指定模块,默认为command
-v 详细过程 –vv -vvv更详细
--list-hosts 显示主机列表,可简写--list
-C, --check 检查,并不执行
-T, --timeout=TIMEOUT 执行命令的超时时间,默认10s
-u, --user=REMOTE_USER 执行远程执行的用户
-U, SUDO_USER, --sudo-user 指定sodu用户
-b, --become 代替旧版的sudo 切换
--become-method 提权的方法
-k, --ask-pass 提示连接密码,默认Key验证
-K,--ask-become-pass 提示使用sudo密码
这个存放各种招式的地方,难道是传说中的藏经阁?
Ansible模块存放位置:/usr/lib/python2.7/site-packages/ansible/modules # 在系统默认的python目录
(不同python版本位置有所不同。)
https://docs.ansible.com/ansible/latest/user_guide/modules.html
https://docs.ansible.com/ansible/2.9/user_guide/modules_intro.html
https://docs.ansible.com/ansible/latest/modules/modules_by_category.html # 最新版本
https://docs.ansible.com/ansible/2.9/modules/modules_by_category.html#modules-by-category # 2.9版本
ansible-doc -l 查看列表
ansible-doc modulename 查看模块帮助文件
怎么说好呢,还是要善用帮助,多help一下去理解,总有好处。
别说了那么多有的没的,还是最喜欢看演示。
[student@servera ~]$ cat hosts
servera
serverb
[webs]
servera
serverb
ansible -i hosts webs -m ping
servera | SUCCESS => {
"changed": false,
"ping": "pong"
}
serverb | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansible webs -m ping
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not
match 'all'
[WARNING]: Could not match supplied host pattern, ignoring: webs
-i inventory 主机清单文件,不加此选项,默认是在/etc/ansible/hosts,(说白了,会匹配配置文件。)
-m 指定模块
在使用Ansible之前,请在目标主机上保存fingerprint指纹,否则会出现Please add this host’s fingerprint to your known_hosts的错误
使用ssh 用户@目标主机连接一下,输入yes,保存下指纹即可
(别和我说这个都不会?你真不会?马上踢出山,之后让你回去尝试一下,不就是首次ssh过去时那段OOXX的提示嘛。)
[student@servera ~]$ ansible -i hosts webs -m command -a "uptime"
servera | CHANGED | rc=0 >>
00:11:00 up 4:42, 1 user, load average: 0.00, 0.01, 0.05
serverb | CHANGED | rc=0 >>
00:11:00 up 14 min, 1 user, load average: 0.00, 0.01, 0.05
command是执行命令模块
-a 是模块的参数
可以把主机写在选项的最后面,增加可读性
[student@servera ~]$ ansible -i hosts -m command -a "uname -r" webs
serverb | CHANGED | rc=0 >>
4.18.0-80.el8.x86_64
servera | CHANGED | rc=0 >>
4.18.0-80.el8.x86_64
[student@servera ~]$ ansible -i hosts -m command -a "useradd test" webs
servera | FAILED | rc=1 >>
useradd: Permission denied.
useradd: cannot lock /etc/passwd; try again later.non-zero return code
serverb | FAILED | rc=1 >>
useradd: Permission denied.
useradd: cannot lock /etc/passwd; try again later.non-zero return code
[student@servera ~]$ ansible -i hosts -m command -a "whoami" webs
serverb | CHANGED | rc=0 >>
student
servera | CHANGED | rc=0 >>
student
[student@servera ~]$ ansible -i hosts -m command -a "whoami" webs -u root
servera | CHANGED | rc=0 >>
root
serverb | CHANGED | rc=0 >>
root
[student@servera ~]$ ansible -i hosts -m command -a "useradd test" webs -u root
servera | CHANGED | rc=0 >>
serverb | CHANGED | rc=0 >>
主控端若不设置被控端用户(–user REMOTE_USER),则被管控时,默认被控端会使用主控端当前的用户(演示使用的是student用户)来进行相关的任务操作,因此,若被控端没有主控端当前用户的时候(例如,serverb没有student用户),就会报错。
总结,要对使用用户进行合理规划并设置好对应的权限。
2015年底270多个模块,2016年达到540个,2018年01月12日有1378个模块,2018年07月15日1852个模块,2019年05月25日(ansible 2.7.10)时2080个模块,2020年03月02日有3387个模块,虽然模块众多,但最常用的模块也就2,30个而已,针对特定业务只用10几个模块。
[root@servera ~]# cat hosts
servera
serverb
[test]
servera
serverb
功能:尝试连接到主机,验证并返回pong成功。
对于Windows目标,请改用win_ping模块。
不使用icmp协议,使用ssh协议。
例子:
# ansible servera -m ping -i hosts
servera | SUCCESS => {
"changed": false,
"ping": "pong" > 返回pong表明成功通讯
}
功能:在远程节点上执行命令
变量 和操作符号 “<”, “>”, “|”, “;” and “&” 不能正常工作。如果需要使用,请使用shell模块。
Ansible默认不指定模块时,将使用此模块。
功能:在远程节点上执行命令。与command模块使用一致,但是,变量 和操作符号 “<”, “>”, “|”, “;” and “&” 能正常工作。
下面2个例子对比能清晰的表示出不同的地方:
[root@servera ~]# ansible servera -m command -a 'echo $RANDOM' -i hosts
servera | CHANGED | rc=0 >>
$RANDOM
[root@servera ~]# ansible servera -m shell -a 'echo $RANDOM' -i hosts
servera | CHANGED | rc=0 >>
7483
# ansible servera -m shell -a "df -h | awk '{print $5}'" -i hosts # “$”不能正常工作
servera | CHANGED | rc=0 >>
Filesystem Size Used Avail Use% Mounted on
/dev/vda1 40G 1.2G 39G 3% /
devtmpfs 475M 0 475M 0% /dev
tmpfs 496M 0 496M 0% /dev/shm
tmpfs 496M 13M 483M 3% /run
tmpfs 496M 0 496M 0% /sys/fs/cgroup
tmpfs 100M 0 100M 0% /run/user/0
复杂命令,即使使用shell也可能会失败。
解决办法:写到脚本时,copy到远程,执行,再把需要的结果拉回执行命令的机器。
# ansible servera -m shell -a "df -hT|sed '1d'|head -1" -i hosts # "|"能正常工作
servera | CHANGED | rc=0 >>
/dev/vda1 xfs 40G 1.2G 39G 3% /
功能:把脚本复制到远程节点后,在远程节点本地运行脚本。
给定的脚本将通过远程节点上的shell环境进行处理。
这个模块在远程系统上不需要python,就像原始脚本一样。
以上面不能正常工作(df -h | awk ‘{print $5}’)的例子来测试:
# cat test.sh
#!/bin/bash
USE=`df -h | awk '{print $5}'`
echo $USE
# ansible servera -m script -a "/root/test.sh" -i hosts
servera | CHANGED => {
"changed": true,
"rc": 0,
"stderr": "Shared connection to servera closed.\r\n",
"stderr_lines": [
"Shared connection to servera closed."
],
"stdout": "Use% 3% 0% 0% 3% 0% 0%\r\n",
"stdout_lines": [
"Use% 3% 0% 0% 3% 0% 0%"
]
}
功能:复制文件或目录到远程节点。默认会覆盖目标文件
backup: 在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes|no
content: 用于替代"src",可以直接设定指定文件的内容,相当于echo 重定向内容到文件
dest: 必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录
directory_mode: 递归的设定目录的权限,默认为系统默认权限
force: 如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no,则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes
src: 要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。在这种情况下,如果路径使用 “/” 来结尾,则只复制目录里的内容,如果没有使用 “/” 来结尾,则包含目录在内的整个内容全部复制,类似于rsync
# ansible -i hosts servera -m copy -a 'src=/root/test.sh dest=/root backup=yes'
servera | CHANGED => {
"changed": true,
"checksum": "cc0d01995c45d2dbaa45bc4035d45f02ef71b473",
"dest": "/root/test.sh",
"gid": 0,
"group": "root",
"md5sum": "5b63433c46dc57d4d730361c5390fc6d",
"mode": "0644",
"owner": "root",
"secontext": "system_u:object_r:admin_home_t:s0",
"size": 53,
"src": "/root/.ansible/tmp/ansible-tmp-1599190670.37-70286513836843/source",
"state": "file",
"uid": 0
}
# ansible -i hosts servera -m command -a 'ls'
servera | CHANGED | rc=0 >>
anaconda-ks.cfg
original-ks.cfg
test.sh
复制目录时,斜线不要写
# ansible -i hosts servera -m copy -a 'src=/root/abc dest=/root'
servera | CHANGED => {
"changed": true,
"checksum": "4e1243bd22c66e76c2ba9eddc1f91394e57f9f83",
"dest": "/root/abc/test.txt",
"gid": 0,
"group": "root",
"md5sum": "d8e8fca2dc0f896fd7cb4cb0031ba249",
"mode": "0644",
"owner": "root",
"secontext": "system_u:object_r:admin_home_t:s0",
"size": 5,
"src": "/root/.ansible/tmp/ansible-tmp-1599190972.15-137237299762028/source",
"state": "file",
"uid": 0
}
根据内容生成文件,相当于echo abc123 > /root/123.txt
# ansible -i hosts servera -m copy -a 'content="abc123" dest=/root/123.txt'
servera | CHANGED => {
"changed": true,
"checksum": "6367c48dd193d56ea7b0baad25b19455e529f5ee",
"dest": "/root/123.txt",
"gid": 0,
"group": "root",
"md5sum": "e99a18c428cb38d5f260853678922e03",
"mode": "0644",
"owner": "root",
"secontext": "system_u:object_r:admin_home_t:s0",
"size": 6,
"src": "/root/.ansible/tmp/ansible-tmp-1599191087.61-13911557669155/source",
"state": "file",
"uid": 0
}
# ansible -i hosts servera -m command -a 'cat /root/123.txt'
servera | CHANGED | rc=0 >>
abc123
功能: 设置远程节点的文件的文件属性
force: 需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下;另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes|no
group: 定义文件/目录的属组
mode: 定义文件/目录的权限
owner: 定义文件/目录的属主
path: 必选项,定义文件/目录的路径
recurse: 递归的设置文件的属性,只对目录有效
src: 要被链接的源文件的路径,只应用于state=link的情况
dest: 被链接到的路径,只应用于state=link的情况
state: 操作方法
directory:如果目录不存在,创建目录
file:即使文件不存在,也不会被创建
link:创建软链接
hard:创建硬链接
touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间
absent:删除目录、文件或者取消链接文件。相当于rm -rf
创建空文件,类似于touch
ansible -i hosts servera -m file -a 'path=/root/filemodule.txt state=touch mode=0666 owner=ftp'
servera | CHANGED => {
"changed": true,
"dest": "/root/filemodule.txt",
"gid": 0,
"group": "root",
"mode": "0666",
"owner": "ftp",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 0,
"state": "file",
"uid": 14
}
创建空目录, 类似于mkdir -p
ansible -i hosts servera -m file -a 'path=/root/filemodules state=directory mode=0666 owner=ftp'
servera | CHANGED => {
"changed": true,
"gid": 0,
"group": "root",
"mode": "0666",
"owner": "ftp",
"path": "/root/filemodules",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 6,
"state": "directory",
"uid": 14
}
创建软链接
ansible -i hosts servera -m file -a 'path=/root/link.txt state=link src=filemodule.txt'
servera | CHANGED => {
"changed": true,
"dest": "/root/link.txt",
"gid": 0,
"group": "root",
"mode": "0777",
"owner": "root",
"secontext": "unconfined_u:object_r:admin_home_t:s0",
"size": 14,
"src": "filemodule.txt",
"state": "link",
"uid": 0
}
功能:管理计划任务
backup: 对远程主机上的原任务计划内容修改之前做备份
cron_file: 如果指定该选项,则用该文件替换远程主机上的cron.d目录下的用户的任务计划
day: 日(1-31,,/2,……)
hour: 小时(0-23,,/2,……)
minute: 分钟(0-59,,/2,……)
month: 月(1-12,,/2,……)
weekday: 周(0-7,*,……)
job: 要执行的任务,依赖于state=present
name: 该任务的描述
special_time: 指定什么时候执行,参数:reboot,yearly,annually,monthly,weekly,daily,hourly
state: 确认该任务计划是创建还是删除
user: 以哪个用户的身份执行
创建计划任务
# ansible -i hosts servera -m cron -a 'name="test cron job" minute=*/10 job="/usr/bin/wall hello world"'
servera | CHANGED => {
"changed": true,
"envs": [],
"jobs": [
"test cron job"
]
}
# ansible -i hosts servera -a 'crontab -l'
servera | CHANGED | rc=0 >>
#Ansible: test cron job
*/10 * * * * /usr/bin/wall hello world
禁用某个计划任务
正确的写法:必须完整的写完,包括name等属性
# ansible -i hosts servera -m cron -a 'disabled=yes name="test cron job" minute=*/10 job="/usr/bin/wall hello world"'
servera | CHANGED => {
"changed": true,
"envs": [],
"jobs": [
"test cron job"
]
}
# ansible -i hosts servera -m cron -a 'disabled=yes name="test cron job" job="/usr/bin/wall hello world"'
servera | CHANGED => {
"changed": true,
"envs": [],
"jobs": [
"test cron job"
]
}
# ansible -i hosts servera -a 'crontab -l'
servera | CHANGED | rc=0 >>
#Ansible: test cron job
#* * * * * /usr/bin/wall hello world
删除计划任务
# ansible -i hosts servera -m cron -a 'state=absent name="test cron job"'
servera | CHANGED => {
"changed": true,
"envs": [],
"jobs": []
}
# ansible -i hosts servera -a 'crontab -l'
servera | CHANGED | rc=0 >>
功能:使用yum包管理器来管理软件包
config_file: yum的配置文件
disable_gpg_check: 关闭gpg_check
disablerepo: 不启用某个源
enablerepo: 启用某个源
name: 要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径
state: Whether to install (‘present’ or ‘installed’, ‘latest’), or remove (‘absent’ or ‘removed’) a package.
(可选值: present, installed, latest, absent, removed) [Default: present]
# ansible -i hosts servera -m yum -a 'name=tree state=latest'
servera | CHANGED => {
"ansible_facts": {
"pkg_mgr": "yum"
},
"changed": true,
"msg": "",
"rc": 0,
"results": [
"Loaded plugins: langpacks, search-disabled-repos\nResolving Dependencies\n--> Running transaction check\n---> Package tree.x86_64 0:1.6.0-10.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n tree x86_64 1.6.0-10.el7 rhel--server-dvd 46 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package\n\nTotal download size: 46 k\nInstalled size: 87 k\nDownloading packages:\nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : tree-1.6.0-10.el7.x86_64 1/1 \n Verifying : tree-1.6.0-10.el7.x86_64 1/1 \n\nInstalled:\n tree.x86_64 0:1.6.0-10.el7 \n\nComplete!\n"
]
}
# ansible -i hosts servera -a 'rpm -q tree'
servera | CHANGED | rc=0 >>
tree-1.6.0-10.el7.x86_64
功能:配置管理服务
arguments: 给命令行提供一些选项 。可以使用别名 args
enabled: 是否开机启动 yes|no
name:必选项,服务名称
pattern: 定义一个模式,如果通过status指令来查看服务的状态时,没有响应,就会通过ps指令在进程中根据该模式进行查找,如果匹配到,则认为该服务依然在运行
runlevel: 运行级别
sleep:如果执行了restarted,在则stop和start之间沉睡几秒钟
state:对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded)
# ansible -i hosts servera -m yum -a 'name=httpd state=latest'
# ansible -i hosts servera -m service -a 'name=httpd state=started' > 一次只能操作一个服务
servera | CHANGED => {
"changed": true,
"name": "httpd",
"state": "started",
"status": {
"ActiveEnterTimestampMonotonic": "0",
"ActiveExitTimestampMonotonic": "0",
"ActiveState": "inactive",
............
功能:管理用户账号
很多选项,与useradd这类系统命令差不多
name: 用户名,可以使用别名user
范例:
创建用户
# ansible -i hosts servera -m user -a 'name=hunk shell=/sbin/nologin system=yes comment="name is hunk"'
servera | CHANGED => {
"changed": true,
"comment": "name is hunk",
"create_home": true,
"group": 993,
"home": "/home/hunk",
"name": "hunk",
"shell": "/sbin/nologin",
"state": "present",
"system": true,
"uid": 996
}
删除用户
# ansible -i hosts servera -m user -a 'name=hunk state=absent'
servera | CHANGED => {
"changed": true,
"force": false,
"name": "hunk",
"remove": false,
"state": "absent"
}
修改用户指定信息
# ansible -i hosts servera -m user -a 'name=hunk state=present comment=" hunk is my"'
remove:删除用户时一并删除用户家目录,需要与state=absent一起使用
# ansible -i hosts servera -m user -a 'name=hunk state=absent remove=yes'
servera | CHANGED => {
"changed": true,
"force": false,
"name": "hunk",
"remove": true,
"state": "absent",
"stderr": "userdel: hunk mail spool (/var/spool/mail/hunk) not found\n",
"stderr_lines": [
"userdel: hunk mail spool (/var/spool/mail/hunk) not found"
]
}
state: 操作方法。(present , absent)
groups: 添加辅助组
group: 指定用户的主组
以下这个例子注意看,group和groups所代表的含义不同。
- name: add user
user: name={
{
username }} group=ftp groups={
{
groupname }}
功能:添加组或删除组
group模块请求的是groupadd, groupdel, groupmod 三个指令
用法都是差不多的。
gid: 组id
name: 组名称
state: Present创建Absent删除
system: yes|no 是否为系统组
# ansible -i hosts servera -m group -a "name=abc state=present gid=1111"
servera | CHANGED => {
"changed": true,
"gid": 1111,
"name": "abc",
"state": "present",
"system": false
}
# ansible -i hosts servera -m group -a "name=abc state=absent"
servera | CHANGED => {
"changed": true,
"name": "abc",
"state": "absent"
}
遇到不知道如何使用的模块,先 ansible-doc 一下,里面有各种使用选项的说明,同时留意下面的example,这些都是辅助你日后使用的好习惯。
多练习,多记忆,多发现。