ad-hoc
ad-hoc简而言之就是临时命令,执行完就结束,不会保存
通常只有在临时执行一些命令的时候会用,如查看被控端进程是否存活,临时拷贝ansible服务器文件至远端
ad-hoc
命令实例
[root@k81 an]# ansible k8s1 -m command -a 'ls /tmp' k83 | CHANGED | rc=0 >> ansible_command_payload_py2F0e ansible_command_payload_RRZXfs ansible_command_payload_TROafA ansible_command_payload_v5L4yq ansible_command_payload_vrjayM systemd-private-69573346ab1c4111a3ca97f3ac42dd98-chronyd.service-5fhZvy k82 | CHANGED | rc=0 >> ansible_command_payload_7Nj4FP ansible_command_payload_9ONKYk ansible_command_payload_aOeBQL ansible_command_payload_LczCCh ansible_command_payload_mmHXAT systemd-private-bb20e1ef5c6146e98ae0302003eb35d8-chronyd.service-jvbkq1
其中ansible是命令, k8s1是主机或者主机组, -m是指定模块 command是模块名称, -a是模块动作(args), 'ls /tmp'是具体命令
ad-hoc执行过程
1、加载ansible的配置文件,默认是/etc/ansible/ansible.cfg,如需要配置其他可以参考这篇blog
2、查找对应的主机配置文件,找到需要执行的主机或主机组(如果无法匹配就报错退出)
3、加载自己对应的模块文件,如command、shell等
4、通过ansible将模块或命令生成对应的临时py文件,并将文件传输至远端服务器对应执行用户 $HOME/.ansible/tmp/ansible-tmp-number/XXX.PY
5、执行用户家目录的PY文件,先给文件 +x 然后执行,执行完了返回结果
6、删除临时py文件,sleep 0退出
注:如果感兴趣可以用ansible执行sleep命令,然后去对端服务器上查看py文件是否生成
ad-hoc执行状态
使用ad-hoc执行命令会返回颜色
绿色:代表远端服务器没有做修改,同时可以看到changed的值是false
黄色:代表远端服务器做出修改,同时可以看到changed的值是true
红色:代表出现问题,需要看提示
ansible模块
ansible的模块有非常多
[root@k81 an]# ansible-doc -l |wc -l 3387 # 可以打印出非常多模块
ansible查看某个模块的帮助
[root@k81 an]# ansible-doc command # command替换为需要查询的模块即可,其中还有EXAMPLES
常用模块介绍
command
功能:在远程主机执行shell命令,此模块为默认模块,也就是说可以忽略 -m 选型
注:该模块不支持管道命令 |
demo展示:
chdir
[root@k81 an]# ansible k82 -m command -a 'pwd' k82 | CHANGED | rc=0 >> /root [root@k81 an]# ansible k82 -m command -a 'chdir=/opt pwd' k82 | CHANGED | rc=0 >> /opt # 目录切换了
creates
[root@k81 an]# ansible k82 -m command -a 'creates=/tmp/log pwd' k82 | CHANGED | rc=0 >> /root [root@k81 an]# ansible k82 -m command -a 'touch /tmp/log' [WARNING]: Consider using the file module with state=touch rather than running 'touch'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. k82 | CHANGED | rc=0 >> [root@k81 an]# ansible k82 -m command -a 'creates=/tmp/log pwd' k82 | SUCCESS | rc=0 >> skipped, since /tmp/log exists # 可以看到在/tmp/log不存在的时候执行了pwd命令,在/tmp/log存在的时候他直接skipped了
removes
[root@k81 an]# ansible k82 -m command -a 'removes=/tmp/log pwd' k82 | CHANGED | rc=0 >> /root [root@k81 an]# ansible k82 -m command -a 'rm -f /tmp/log pwd' [WARNING]: Consider using the file module with state=absent rather than running 'rm'. If you need to use command because file is insufficient you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message. k82 | CHANGED | rc=0 >> [root@k81 an]# ansible k82 -m command -a 'removes=/tmp/log pwd' k82 | SUCCESS | rc=0 >> skipped, since /tmp/log does not exist # 结果与creates相反,存在的时候执行,不存在的时候skipped
shell
shell模块与command的区别在于shell支持管道 |
[root@k81 an]# ansible k82 -m shell -a 'ss -lntp|grep 80' # 可以成功执行 [root@k81 an]# ansible k82 -m command -a 'ss -lntp|grep 80' # 爆红
yum_repository
常用参数
name: # 仓库的名称 description: # 描述 baseurl: # 仓库地址 gpgcheck: # 是否验证 gpgkey: # 验证的key
demo
[root@k81 an]# ansible k82 -m yum_repository -a 'name=nginx description=ansible_nginx baseurl="http://nginx.org/packages/centos/$releasever/$basearch/" gpgcheck=yes gpgkey="https://nginx.org/keys/nginx_signing.key"' # 验证 [root@k81 an]# ansible k82 -m shell -a 'ls /etc/yum.repos.d/' k82 | CHANGED | rc=0 >> CentOS-Base.repo CentOS-CR.repo nginx.repo
yum
常见的参数如下:
name: # 包名字,支持*通配符 state: # 预期状态 present # 安装,如果已安装就跳过,且如果不写state默认就是present installed # 安装,如果已安装就跳过 absent # 卸载,如果不存在则跳过 latest # 安装最新版本 enablerepo # 通过指定仓库安装 disablerepo # 不从某个仓库安装 exclude # 不按照哪些包
demo
[root@k81 an]# ansible k82 -m yum -a 'name=vsftpd state=present' # 安装vsftpd [root@k81 an]# ansible k82 -m yum -a 'name=vsftpd state=absent' # 卸载vsftpd [root@k81 an]# ansible k82 -m yum -a 'name=nginx enablerepo=epel' # 从epel源安装nginx [root@k81 an]# ansible k82 -m yum -a 'name=vsftpd state=latest exclude="kernel*"' # 更新除内核的所有包
hostname
修改主机名称,直接给demo
[root@k81 an]# ansible ub1 -m hostname -a 'name=ub111' [root@k81 an]# ansible ub1 -m shell -a 'hostname' ub1 | CHANGED | rc=0 >> ub111 # 验证
sysctl
修改内核参数
demo
[root@k81 an]# ansible ub1 -m sysctl -a 'name=net.ipv4.ip_forward value=1' [root@k81 an]# ansible ub1 -m shell -a 'sysctl -a |grep net.ipv4.ip_forward' ub1 | CHANGED | rc=0 >> net.ipv4.ip_forward = 1 net.ipv4.ip_forward_update_priority = 1 net.ipv4.ip_forward_use_pmtu = 0
copy
将ansible的文件拷贝到远端主机,实现替换,类似scp
常见参数如下:
src: # ansible的源文件路径,支持绝对路径和相对路径 dest: # 对端的文件路径 owner: # 属主 group: # 属组 mode: # 权限 backup: # 备份,替换之前先把对端的文件以时间戳的方式做一个拷贝 validate: # 验证 content: # 往文件中写入内容,与src互斥
demo
[root@k81 an]# echo test1 > file1 [root@k81 an]# ansible k82 -m copy -a 'src=./file1 dest=/opt/file1 owner=zs group=zs mode="0600" backup=yes' [root@k81 an]# ansible k82 -a 'removes=/opt/file1 cat /opt/file1' k82 | CHANGED | rc=0 >> test1 # 可以看到文件已经有了,且内容也是对的 [root@k81 an]# echo test2 >> file1 [root@k81 an]# ansible k82 -m copy -a 'src=./file1 dest=/opt/file1 owner=zs group=zs mode="0600" backup=yes' [root@k81 an]# ansible k82 -m shell -a 'ls -l /opt/file*' k82 | CHANGED | rc=0 >> -rw------- 1 zs zs 12 Apr 12 23:24 /opt/file1 -rw------- 1 zs zs 6 Apr 12 23:21 /opt/file1.70493.2023-04-12@23:24:15~ # 可以看到有备份文件 [root@k81 an]# ansible k82 -m shell -a 'cat /opt/file*' k82 | CHANGED | rc=0 >> test1 test2 test1 # 内容也和预期相符 [root@k81 an]# ansible k82 -m copy -a 'src=/etc/sudoers dest=/opt/sudoers validate="/usr/sbin/visudo -csf %s"' # 验证拷贝过去的文件是否正常,如果不正常就报错且不复制到远端 [root@k81 an]# ansible k82 -m copy -a 'content="newtest" dest=/opt/file1 ' [root@k81 an]# ansible k82 -m shell -a 'cat /opt/file1' k82 | CHANGED | rc=0 >> newtest
fetch
这个模块和copy类似,不过他是从被控端拷贝至ansible
常见参数
src: # 远端机器的源路径 dest: # ansible本地的目标路径 flat: # yes - 表示只抓取文件,不创建主机目录及下级目录,默认为no
demo
[root@k81 an]# ansible ubuntus -m fetch -a 'sec=/opt/conf1 dest=/opt flate=yes'
systemd
操纵远端机器的服务状态
常见参数如下:
name: # 服务名 state: # 状态 started # 开启 stopped # 停止 restarted # 重启 reloaded # 重载 enabled: # 开机自启 daemon_reload: daemon-reload
demo
[root@k81 an]# ansible k82 -m systemd -a 'name=vsftpd state=started enabled=yes daemon_reload=yes' # 开启服务并加入开机自启
file
创建文件、目录、软硬链接、授权等
常见参数如下:
path: # 路径 owner: # 属主 group: # 属组 mode: # 权限 state: # 类型 link # 软链接 hard # 硬链接 touch # 文件 directory # 目录 recurse yes # 递归授权 ,仅在目录类型可以使用
demo
[root@k81 an]# ansible k82 -m file -a 'path=/opt/data owner=zs group=zs mode="0770" state=directory recurse=yes' # 创建目录并递归授权
group
创建用户组
group的demo
[root@k81 an]# ansible k82 -m group -a 'name=www gid=777 state=present' # 创建用户组指定gid [root@k81 an]# ansible k82 -m group -a 'name=www gid=777 state=absent' # 删除group [root@k81 an]# ansible k82 -m group -a 'name=www system=yes state=present' # 创建一个系统用户组
user
user的参数
name: # 名称 uid: # 指定uid group: # 指定基本组,需要组已存在 shell: # 登录的shell,默认为/bin/bash create_home: # 是否创建家目录,默认yes password: # 密码,需要是加密后的字符串,否则不生效 system: # 是否为系统用户,默认False groups: # 附加组 append: # 追加 state: # 如果是absent的话 remove: # 移除家目录,与absent的状态搭配
demo
[root@k81 an]# ansible k82 -m user -a 'name=www uid=777 group=www shell=/sbin/nologin create_home=no' # 创建一个指定uid,指定组,设置不允许登录,不创建家目录的用户www [root@k81 an]# ansible k82 -m user -a 'name=ls system=yes group=www groups=root shell=/bin/bash create_home=yes' # 创建一个系统用户,指定基础组与附加组
加密字符串的方法
[root@k81 an]# ansible localhost -m debug -a "msg={{ '666' | password_hash('sha512', 'salt') }}" -o localhost | SUCCESS => { "changed": false, "msg": "$6$salt$Q5zxTLg4vl2J8Al9XHav4CDbM.686fI9cdjPcg.UexLtxDxqAtaj9dlr2CpoNRHVT5DwpxhRdkAtYpLiV/9w2."} # 这里就是将666 以hash的方式加密成了下面那一串字符串
利用加密字符串创建密码
[root@k81 an]# ansible k82 -m user -a 'name=wangwu password=$6$salt$Q5zxTLg4vl2J8Al9XHav4CDbM.686fI9cdjPcg.UexLtxDxqAtaj9dlr2CpoNRHVT5DwpxhRdkAtYpLiV/9w2.' # 新建一个wangwu用户,并且密码是666
新建用户并生成密钥
[root@k81 an]# ansible k82 -m user -a 'name=wl generate_ssh_key=yes ssh_key_bits=2048 ssh_key_file=.ssh/id_rsa' k82 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "comment": "", "create_home": true, "group": 1004, "home": "/home/wl", "name": "wl", "shell": "/bin/bash", "ssh_fingerprint": "2048 SHA256:AVFW+gQ/oBARVAjJIFWGvRVhArB55MPR1imFewif//8 ansible-generated on k82 (RSA)", "ssh_key_file": "/home/wl/.ssh/id_rsa", "ssh_public_key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC1sBHjxncRtF2MW71g1aG/brgMs0QPgPXhIbB1nQJAQRNyg6ajClaimMOqxB0nuimn5ZZoaEGgKCnAyd/hu3q6QtPvBzkOerNWRiHPhRUrQ0qWTsA9KwXx3A3KAKSHuw1m71hblo1B8SiAV+W8VnpBohwbSumU1BFqODFZR2Loa/h0XvrOn/drq1rH3LrjwyyZhO7ferK17VZeP5loCHa4fwZ2FY1aNvPsRnKOnYM1A0WD301124sDNTd4+jXYjZaHImARtk6EhoLU3aiOItgs/yXPfpt12GBHvJklsJZBJ4xCSy8Q6QRoxmLgRWOIncEso1NGHLj4DslRRX+NCjt1 ansible-generated on k82", "state": "present", "system": false, "uid": 1003 }
mount
常见参数
src: # 源设备路径,可以是本地路径或网络地址 path: # 本地将要挂载的路径 fstype: # 挂载类型,如nfs、ext4等 opts: # 挂载的选型 state: # 状态 present # 永久挂载,但是非立即生效(写入 /etc/fstab) absent # 卸载加删除 /etc/fstab mounted # 临时挂载 unmounted # 临时卸载
demo
[root@k81 an]# ansible k82 -m mount -a 'src=10.10.20.100:/zettafs0/nfsdir/cxk path=/mnt fstype=nfs opts=defaults state=mounted' # 永久挂载一个nfs [root@k81 an]# ansible k82 -m mount -a 'src=10.10.20.100:/zettafs0/nfsdir/cxk path=/mnt fstype=nfs opts=defaults state=absent' # 卸载
cron
常见参数
name: # 描述定时任务的功能 minute: # 分钟 hour: # 小时 weekday: # 周 user: # 用户 job: # 任务 state: # 状态 present: # 生成 absent: # 删除 disabled: # 注释掉已有任务
demo
[root@k81 an]# ansible k82 -m cron -a 'name="backup data" hour=02 minute=00 job="/bin/bash /opt/test.sh" user=root' k82 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "envs": [], "jobs": [ "backup data" ] } # [root@k81 an]# ansible k82 -m shell -a 'crontab -l' k82 | CHANGED | rc=0 >> #Ansible: backup data 00 02 * * * /bin/bash /opt/test.sh [root@k81 an]# ansible k82 -m cron -a 'name="backup data" hour=02 minute=00 job="/bin/bash /opt/test.sh" user=root disabled=yes' k82 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "envs": [], "jobs": [ "backup data" ] } # 注释掉该任务 [root@k81 an]# ansible k82 -m shell -a 'crontab -l' k82 | CHANGED | rc=0 >> #Ansible: backup data #00 02 * * * /bin/bash /opt/test.sh
get_url
常见参数
url: # 远端地址 dest: # 下载文件存放地址 mode: # 权限 checksum: # 校验(支持md5、sha256等校验,校验失败会直接报错拒绝下载)
demo
[root@k81 an]# ansible k82 -m get_url -a 'url=https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tar.xz dest=/opt/ mode=0644' # 下载一个文件 [root@k81 an]# ansible k82 -m shell -a ' md5sum /opt/Python-3.7.6.tar.xz ' k82 | CHANGED | rc=0 >> c08fbee72ad5c2c95b0f4e44bf6fd72c /opt/Python-3.7.6.tar.xz [root@k81 an]# ansible k82 -m get_url -a 'url=https://www.python.org/ftp/python/3.7.6/Python-3.7.6.tar.xz dest=/tmp/ checksum=md5:c08fbee72ad5c2c95b0f4e44bf6fd72c' # 下载的时候校验md5
unarchive
解压文件
常用参数
src: # 源文件路径 dest: # 解压后路径 remote_src: # 源文件是否在远端,yes是在,no是不在,默认no
demo
[root@k81 an]# ansible k82 -m unarchive -a 'src=./file.tgz dest=/opt' # 将当前路径的压缩包解压到远端 [root@k81 an]# ansible k82 -m unarchive -a 'src=/tmp/Python-3.7.6.tar.xz remote_src=yes dest=/opt' # 解压远端的压缩包
archive
打包压缩被控端的文件或目录
常用参数
path: # 需要压缩的文件或目录 dest: # 压缩之后转存的路径 format: # 压缩的格式,默认是gz
demo
[root@k81 an]# ansible k82 -m archive -a 'path=/tmp/ dest=/opt/tmp.bgz format=bz2' # 在远端以bz2格式压缩一个包 [root@k81 an]# ansible k82 -m shell -a 'file /opt/tmp.bgz ' k82 | CHANGED | rc=0 >> /opt/tmp.bgz: bzip2 compressed data, block size = 900k
selinx
操作selinux
常用参数很简单,直接给demo了
[root@k81 an]# ansible k82 -m selinux -a 'policy=targeted state=enforcing' # 强制模式 [root@k81 an]# ansible k82 -m selinux -a 'policy=targeted state=permissive' # 宽容模式 [root@k81 an]# ansible k82 -m selinux -a 'policy=targeted state=disabled' # 禁用,这种场景可以省略policy
firewalld
操控远端firewalld
参数
zone: # 操作的zone,默认在public source: # 来源地址 service: # 服务名称 port: # 端口 immediate: 临时生效 permanent: # 永久启用,但不会立即生效 state: #启用和关闭 enabled disabled
demo
[root@k81 an]# ansible k82 -m firewalld -a ' zone=public port=8000-8080/tcp immediate=yes state=enabled ' k82 | CHANGED => { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": true, "msg": "Non-permanent operation, Changed port 8000-8080/tcp to enabled" } [root@k81 an]# ansible k82 -m shell -a 'firewall-cmd --list-all ' k82 | CHANGED | rc=0 >> public (active) target: default icmp-block-inversion: no interfaces: eth0 sources: services: dhcpv6-client ssh ports: 8000/tcp 8000-8080/tcp protocols: masquerade: no forward-ports: source-ports: icmp-blocks: rich rules:
iptables
常用参数
tables: # 指定表,默认是filter chain: # 指定链, source: # 来源IP destination: # 目标IP destination_port: # 目标端口 protocol: # 协议 jump: # 动作 action: # 如何添加 insert: 插入 append: 追加
demo
[root@k81 an]# ansible ub1 -m iptables -a 'table=filter chain=INPUT source=10.10.30.2/24 destination=192.168.23.32 destination_port=80 protocol=tcp jump=DROP action=insert' # 利用ansible写一条规则并检查是否生效 [root@k81 an]# ansible ub1 -m shell -a 'iptables -L -n |head -3' ub1 | CHANGED | rc=0 >> Chain INPUT (policy ACCEPT) target prot opt source destination DROP tcp -- 10.10.30.0/24 192.168.23.32 tcp dpt:80 [root@k81 an]# ansible k82 -m iptables -a 'table=nat chain=PREROUTING protocol=tcp source=10.10.10.2/24 destination=172.21.32.2 destination_port=80 jump=DNAT to_destination="2.2.2.2:8080" action=insert' # 写一条DNA规则并检查 [root@k81 an]# ansible k82 -m shell -a 'iptables -t nat -L -n|head -3' k82 | CHANGED | rc=0 >> Chain PREROUTING (policy ACCEPT) target prot opt source destination DNAT tcp -- 10.10.10.0/24 172.21.32.2 tcp dpt:80 to:2.2.2.2:8080 [root@k81 an]# ansible ub1 -m iptables -a 'table=nat chain=POSTROUTING protocol=tcp source=11.11.11.0/24 jump=SNAT to_source=10.10.10.10 action=append' # 写一条SNAT规则并检查 [root@k81 an]# ansible ub1 -m shell -a 'iptables -t nat -L -n -v|tail -4' ub1 | CHANGED | rc=0 >> Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 SNAT tcp -- * * 11.11.11.0/24 0.0.0.0/0 to:10.10.10.10
lineinfile
功能有点类似sed
常用参数
path: # 远端路径 regexp: # 正则匹配格式 line: # 填充的内容 state: # 状态 ,默认是present,如果设置为absent的话就会删除 insertafter: # 在某行之后新增一行 insertbefore: # 在某行之前新增一行 backrefs: # 默认为no,需要搭配regexp使用 yes # 为yes时,如果没有匹配,则文件保持不变。如果匹配了,把匹配内容替被换为line内容。 no # 为no时,如果没有匹配,则添加一行line。如果匹配了,则把匹配内容替被换为line内容。
demo
## 替换80端口为8080 [root@k81 an]# cat > conf1 <<EOF Listen 80 user=root EOF [root@k81 an]# ansible ub1 -m copy -a 'src=./conf1 dest=/opt/conf1' [root@k81 an]# ansible ub1 -m lineinfile -a 'path=/opt/conf1 regexp="^Listen.*" line="Listen 8080"' # 实际上是行替换,所以这里不加.*其实也能整行替换 [root@k81 an]# ansible ub1 -m shell -a 'cat /opt/conf1' ub1 | CHANGED | rc=0 >> Listen 8080 user=root ## 增加一行配置在文件最后面 [root@k81 an]# ansible ub1 -m lineinfile -a 'path=/opt/conf1 line="it is newline for last"' [root@k81 an]# ansible ub1 -m shell -a 'cat /opt/conf1' ub1 | CHANGED | rc=0 >> Listen 8080 user=root it is newline for last ## 删除文件中一行数据 [root@k81 an]# ansible ub1 -m lineinfile -a 'path=/opt/conf1 regexp=".*newline" state=absent' [root@k81 an]# ansible ub1 -m shell -a 'cat /opt/conf1' ub1 | CHANGED | rc=0 >> Listen 8080 user=root ## 在某一行下面插入一行 [root@k81 an]# ansible ub1 -m lineinfile -a 'path=/opt/conf1 insertafter="user=root" line="new line for after"' [root@k81 an]# ansible ub1 -m shell -a 'cat /opt/conf1' ub1 | CHANGED | rc=0 >> Listen 8080 user=root new line for after ## 在某一行上面插入一行 [root@k81 an]# ansible ub1 -m lineinfile -a 'path=/opt/conf1 insertbefore="user=root" line="new line for before"' [root@k81 an]# ansible ub1 -m shell -a 'cat /opt/conf1' ub1 | CHANGED | rc=0 >> Listen 8080 new line for before user=root new line for after
pam_limits
这个模块是调整内核参数的,通常可以调整文件描述符
domain: # 给哪个用户调整,支持使用 "*" 匹配所有用户 limit_type: # 类型 有 soft 和 hard limit_item: nofile # 通常设置为nofile value: # 文件描述符数量,比如给个 1000000
demo
[root@k81 an]# cat pam_limits1.yaml - hosts: web tasks: - name: change limit pam_limits: domain: "*" limit_type: "{{ item }}" limit_item: nofile value: "100000" loop: - soft - hard ## 也可以用变量写,具体如下: - hosts: web tasks: - name: change limit pam_limits: domain: "*" limit_type: "{{ item.limit_type }}" limit_item: "{{ item.limit_item }}" value: "{{ item.value }}" with_items: - { limit_type: 'soft', limit_item: 'nofile', value: '100000' } - { limit_type: 'hard', limit_item: 'nofile', value: '100000' } ## 两种写法选一种都可以达到效果 ## 执行任务 [root@k81 an]# ansible-playbook pam_limits1.yaml ## 检查是否生效 [root@k81 an]# ansible web -m shell -a 'egrep -v "^$|^#" /etc/security/limits.conf' c3 | CHANGED | rc=0 >> * soft nofile 100000 * hard nofile 100000 c5 | CHANGED | rc=0 >> * soft nofile 100000 * hard nofile 100000 c4 | CHANGED | rc=0 >> * soft nofile 100000 * hard nofile 100000