ansible通过模块的方式来完成一些远程的管理工作
#查看所有模块
ansible-doc -l
#查看某个模块的参数
ansible-doc -s module
#查看某个模块更详细的信息
ansible-doc help module
setup:可以用来查看远程主机的一些基本信息
功能: setup 模块来收集主机的系统信息,这些 facts 信息可以直接以变量的形式使用,但是如果主机较多,会影响执行速度
可以使用 gather_facts: no
来禁止 Ansible 收集 facts 信息
# setup模块无任何参数
ansible all -m setupansible all -m setup -a "filter=ansible_nodename"ansible all -m setup -a "filter=ansible_hostname"ansible all -m setup -a "filter=ansible_domain"ansible all -m setup -a "filter=ansible_memtotal_mb"ansible all -m setup -a "filter=ansible_memory_mb"ansible all -m setup -a "filter=ansible_memfree_mb"ansible all -m setup -a "filter=ansible_os_family"ansible all -m setup -a "filter=ansible_distribution_major_version"ansible all -m setup -a "filter=ansible_distribution_version"ansible all -m setup -a "filter=ansible_processor_vcpus"ansible all -m setup -a "filter=ansible_all_ipv4_addresses"ansible all -m setup -a "filter=ansible_architecture"ansible all -m setup -a "filter=ansible_uptime_seconds"ansible all -m setup -a "filter=ansible_processor*"ansible all -m setup -a 'filter=ansible_env'
示例:获取 IPv4 地址
root@ubuntu20:~# ansible db -m setup -a "filter=ansible_all_ipv4_addresses"
10.0.0.16 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["172.18.1.4","10.0.0.16","172.17.0.1","172.60.0.1"],"discovered_interpreter_python": "/usr/bin/python"},"changed": false
}
10.0.0.15 | SUCCESS => {"ansible_facts": {"ansible_all_ipv4_addresses": ["10.0.0.15","172.18.1.125"],"discovered_interpreter_python": "/usr/bin/python3"},"changed": false
}
root@ubuntu20:~#
示例
root@ubuntu20:~# ansible db -m setup -a 'filter=ansible_python_version'
10.0.0.15 | SUCCESS => {"ansible_facts": {"ansible_python_version": "3.8.6","discovered_interpreter_python": "/usr/bin/python3"},"changed": false
}
10.0.0.16 | SUCCESS => {"ansible_facts": {"ansible_python_version": "3.8.6","discovered_interpreter_python": "/usr/bin/python"},"changed": false
}
root@ubuntu20:~#
ping:可以用来测试远程主机的运行状态
# ping模块无任何参数
ansible all -m ping
示例
root@ubuntu20:~# ansible db -m ping
10.0.0.16 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"},"changed": false,"ping": "pong"
}
10.0.0.15 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": false,"ping": "pong"
}
root@ubuntu20:~#
authoried_keys
配置ansible到远程主机的ssh无密码登录的信任关系
参考:https://my.oschina.net/u/4306156/blog/3597849
首先采用Ansible批量建立ssh无密码登录的信任关系!![root@ansible-server ~]# ssh-keygen -t rsa #一路回车
[root@ansible-server ~]# ls /root/.ssh/
id_rsa id_rsa.pub####################################################################################################
需要注意ssh建立互信的命令格式:
# ssh-copy-id -i ~/.ssh/id_rsa.pub username@ip或hostname
####################################################################################################在客户机比较多的情况下,使用 ssh-copy-id命令的方法显然是有些费时,使用ansible-playbook 推送 ymal进行批量创建ssh互信关系就显得省事多了,
这里就使用到了ansible的authoried_keys 模块:首先要配置ansible清单 (远程主机的密码这里为"123456")
[root@ansible-server ~]# vim /etc/ansible/hosts
................
................
[ssh-host]
172.16.60.204
172.16.60.205
172.16.60.206
172.16.60.207[ssh-host:vars]
ansible_ssh_pass="123456"####################################################################################################
发送公钥到目标机器命令格式如下:
# ansible ssh-host -m copy -a "src=/root/.ssh/id_rsa.pub dest=/root/.ssh/authorized_keys mode=600"
####################################################################################################
在上面分发密钥中,如果清单文件/etc/ansible/hosts里没有使用ansible_ssh_pass变量指明密码,则可以使用下面命令:
这里默认ssh-host组下的机器root密码都一样,使用-k 参数,回车输入root密码即可:
# ansible ssh-host -m authorized_key -a "user=root state=present key=\"{{ lookup('file', '/root/.ssh/id_rsa.pub') }} \"" -k
##################################################################################################### 编写playbook文件
[root@ansible-server ~]# vim /opt/ssh_key.yaml
---- hosts: ssh-hostuser: roottasks:- name: ssh-copyauthorized_key: user=root key="{{ lookup('file', '/root/.ssh/id_rsa.pub') }}"# 注意上面yaml脚本中的"ssh-key-host"是在/etc/ansible/hosts清单文件里配置的远程客户机列表
这里做的是基于远程主机root用户的ssh互信# 执行批量互信
[root@ansible-server ~]# ansible-playbook /opt/ssh_key.yaml# 最后验证下ssh互信
[root@ansible-server ~]# ansible -i /etc/ansible/hosts ssh-host -m shell -a "whoami"
如果ansible服务端没有和远程主机做ssh信任关系, 则可以在hosts清单配置里直接指明用户名和密码.
如果使用普通用户, 并且允许sudo, 则需要提前在客户机里的/etc/sudoers文件里配置好该普通用户的sudo配置, 即允许该普通用户有sudo权限.[root@ansible-server ~]# vim /etc/ansible/hosts
................
[test-host]
172.16.60.220 ansible_ssh_user=root ansible_ssh_pass=123456 ansible_ssh_port=22
172.16.60.221 ansible_ssh_user=root ansible_ssh_pass=bo@123 ansible_ssh_port=22
172.16.60.222 ansible_ssh_user=app ansible_ssh_pass=bj@123 ansible_ssh_port=22 ansible_sudo_pass=bj@123即172.16.60.222客户机上要提前配置, 允许app用户具有sudo权限.执行:
[root@ansible-server ~]# ansible test-host -m shell -a "hostname"
172.16.60.222 | SUCCESS | rc=0 >>
k8s-node02172.16.60.220 | SUCCESS | rc=0 >>
k8s-master01172.16.60.221 | SUCCESS | rc=0 >>
k8s-node01[root@ansible-server ~]# ansible -i /etc/ansible/hosts test-host -m shell -a "hostname"
172.16.60.222 | SUCCESS | rc=0 >>
k8s-node02172.16.60.220 | SUCCESS | rc=0 >>
k8s-master01172.16.60.221 | SUCCESS | rc=0 >>
k8s-node01
Command 模块
功能:在远程主机执行命令,此为默认模块,可忽略 -m 选项
注意:
-
此命令不支持 $VARNAME < > | ; & 等,可能用shell模块实现
-
此模块不具有幂等性
语法
ansible [主机IP或组名] -m
command模块包含如下选项
header 1 | header 2 |
---|---|
creates | 一个文件名,当该文件存在,则该命令不执行 |
free_from | 要执行的linux指令 |
chdir | 在执行指令之前,先切换到该指定的目录 |
removes | 一个文件名,当该文件不存在,则该选项不执行,和creates相反 |
executable | 切换shell来执行指令,该执行路径必须是一个绝对路径 |
示例
ansible db -m command -a 'chdir=/etc cat os-release'
# 简写
root@ubuntu20:~# ansible db -a 'chdir=/etc cat os-release'
10.0.0.16 | CHANGED | rc=0 >>
NAME="Ubuntu"
VERSION="20.10 (Groovy Gorilla)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.10"
VERSION_ID="20.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=groovy
UBUNTU_CODENAME=groovy
10.0.0.15 | CHANGED | rc=0 >>
NAME="Ubuntu"
VERSION="20.10 (Groovy Gorilla)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.10"
VERSION_ID="20.10"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=groovy
UBUNTU_CODENAME=groovy
root@ubuntu20:~## file2存在,所以ls /home不执行
ansible db -a 'creates=/tmp/file2 ls /home'# /etc/fs不存在,所以cat /etc/fstab不执行
root@ubuntu20:~# ansible db -a 'removes=/etc/fs cat /etc/fstab'
10.0.0.16 | SUCCESS | rc=0 >>
skipped, since /etc/fs does not exist
10.0.0.15 | SUCCESS | rc=0 >>
skipped, since /etc/fs does not exist
root@ubuntu20:~## 进入/usr/local/src/目录,将jdk-6u45-linux-amd64.rpm打包
ansible mfs_node -a 'chdir=/usr/local/src/ tar zcf=bbb.tar.gz jdk-6u45-linux-amd64.rpm'# 不成功,此命令不支持$VARNAME < > | ; & 等,要用shell模块实现
ansible db -m command -a 'echo adwl2020 |passwd --stdin adwl' ansible db -m command -a 'echo "adwl:adwl2021"|chpasswd'
Shell:和Command相似,用shell执行命令
功能:和command相似,用shell执行命令,支持各种符号,比如:*,$, >
注意:此模块不具有幂等性
语法
ansible [主机IP或组名] -m shell -a '要执行的命令'
示例
root@ubuntu20:~# ansible db -m command -a "chdir=/etc cat os-release|grep ID"
10.0.0.16 | FAILED | rc=1 >>
cat: 'os-release|grep': No such file or directory
cat: ID: No such file or directorynon-zero return code
10.0.0.15 | FAILED | rc=1 >>
cat: 'os-release|grep': No such file or directory
cat: ID: No such file or directorynon-zero return code
root@ubuntu20:~# ansible db -m shell -a "chdir=/etc cat os-release|grep ID"
10.0.0.16 | CHANGED | rc=0 >>
ID=ubuntu
ID_LIKE=debian
VERSION_ID="20.10"
10.0.0.15 | CHANGED | rc=0 >>
ID=ubuntu
ID_LIKE=debian
VERSION_ID="20.10"
root@ubuntu20:~#
示例
ansible srv -m shell -a 'echo adwl2020 |passwd --stdin adwl'
ansible 192.168.30.* -m shell -a 'echo $HOSTNAME'
ansible 192.168.30.* -m shell -a 'cat /dev/null > /tmp/testfie'# 调用bash执行命令,类似cat /tmp/stanley.md | awk -F '|' '{print $1,$2}' &> /tmp/example.txt这些复杂的命令,即使用shell也可以会失败,
# 解决办法:写到脚本时,copy到远程,执行,再把需要的结果拉回执行命令的机器
最近在使用ansible shell模块启动一个shell编写的脚本,该脚本主要功能式加载java的classpath并在后台运行这个java程序。
该脚本在linux shell中可以正常启动和停止,但是使用ansible shell模块却每次都启动后进程都消失了,日志没有任何异常,pid文件也生成了。
后来经过一个同事的猜想,是否有程序将该进程kill掉了。
于是产生了以下几种猜想:
1.ansible shell模块执行完shell脚本,就立即关闭当前的shell,进程也就被关闭了。
2.ansible fork出来子线程来运行脚本,ansible正常退出时会结束所有fork的子线程因为程序启动后被关闭.
尝试解决: 给shell命令开头加个nohup, 结尾加个&, 如果环境变量找不到,加入source ~/.bash_profile
例如:source ~/.bash_profile;nohup /apps/xxx/ss/start.sh &
注意:调用bash执行命令 类似 cat /tmp/test.md | awk -F'|' '{print $1,$2}' &> /tmp/example.txt
这些复杂命令,即使使用shell也可能会失败,解决办法:写到脚本时,copy到远程,执行,再把需要的结果 拉回执行命令的机器
[root@ansible ~]#vim /etc/ansible/ansible.cfg
# 修改下面一行
module_name = shell
范例:将shell模块代替command,设为模块
疑问:既然 shell 模板这么强大,可以直接取代 command、file、yum等模块,那为什么还需要使用其他模块呢?
答案:shell 模块虽然可以代替yum模块执行软件包管理、代替file 模块执行文件管理的功能,但并不具备幂等性和安全性
Script:运行脚本
功能:在远程主机上运行ansible服务器上的脚本(不需要将脚本复制到被控端,无需执行权限)
注意:此模块不具有幂等性
语法
ansible [主机IP或组名] -m script -a [脚本文件]
示例
# 在ansible管理机上编写脚本即可
cat f1.sh
#!/bin/bash
hostname
chmod +x f1.sh
# 在所有被监控机执行shell脚本,不用将脚本放在被监控机上
ansible all -m script -a '/search/odin/f1.sh'#线上示例
[@bjyf_50_20 ansible]$ cat extserver_hosts
[all]
10.162.33.57
10.162.33.59
10.162.33.65
10.162.33.66
10.162.33.80
10.162.33.85
10.162.33.61
[all:vars]
ansible_ssh_pass="noSafeNoWork@2020"
anisble_ssh_user="root"
[@bjyf_50_20 ansible]$ cat f1.sh
#!/bin/bash
hostname# 测试执行
[@bjyf_50_20 ansible]$ ansible -i extserver_hosts all -u root -m script -a 'f1.sh'# 安装supervisor
[@bjyf_50_20 ansible]$ ansible -i extserver_hosts all -u root -m script -a 'install_supervisor.sh'
copy模块-------复制ansible主机的文件到远程主机
功能:从ansible服务器主控端复制文件到远程主机
注意: src=file 如果是没指明路径,则为当前目录或当前目录下的files目录下的file文件
官网:https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html
copy模块包含如下选项
header 1 | header 2 |
---|---|
backup | 在覆盖之前将原文件备份,备份文件包含时间信息。有两个选项:yes |
content | 用于替代"src",可以直接设定指定文件的值 |
dest | 必选项。要将源文件复制到的远程主机的绝对路径,如果源文件是一个目录,那么该路径也必须是个目录 |
directory_mode | 递归的设定目录的权限,默认为系统默认权限 |
force | 如果目标主机包含该文件,但内容不同,如果设置为yes,则强制覆盖,如果为no, 则只有当目标主机的目标位置不存在该文件时,才复制。默认为yes |
others | 所有的file模块里的选项都可以在这里使用 |
remote_src | 如果在远程机器上执行copy,相当于在远端机器本机执行cp命令,remote_src: true。 对于asible 2.6,只支持copy单个文件,不允许递归copy。 对于ansible 2.8 已经支持递归复制。 |
src | 要复制到远程主机的文件在本地的地址,可以是绝对路径,也可以是相对路径。如果路径是一个目录,它将递归复制。 在这种情况下,如果路径使用"/“来结尾,则只复制目录里的内容,如果没有使用”/"来结尾,则包含目录在内的 整个内容全部复制,类似于rsync。 |
示例
# /search/odin/bin bin目录自身和目录里面的文件都备份到dest指定的文件夹
copy: src=/search/odin/bin dest=/search/odin/backup/{{ bak_var.stdout }}/ remote_src=yes# /search/odin/bin/ 只备份bin目录里面的文件到dest指定的文件夹
copy: src=/search/odin/bin/ dest=/search/odin/backup/{{ bak_var.stdout }}/ remote_src=yes
示例
# 关闭所有机器的Selinux
# 可以修改管理机的/etc/sysconfig/selinux文件
cat /etc/sysconfig/selinux
SELINUX=disabled# 将文件拷贝到被管理机器,如目标存在,默认覆盖,此处指定先备份
ansible db -m copy -a 'src=/etc/sysconfig/selinux dest=/etc/sysconfig/selinux backup=yes'# 复制文件bbb到远程目录:
ansible db -m copy -a 'src=bbb dest=/tmp/file2 mode=755 owner=root group=root'
ansible db -a 'cat /tmp/file2'# 如果目标存在,默认覆盖,此处指定先备份
ansible db -m copy -a 'src=bbb dest=/tmp/file2 mode=755 owner=root group=root backup=yes'
ansible db -a 'cat /tmp/file2'# 利用指定内容,直接生成目标文件
ansible db -m copy -a "content='test content\n' dest=/tmp/f1.txt"
Get_url 模块
功能: 用于将文件从http、https或ftp下载到被管理机节点上
常用参数
header 1 | header 2 |
---|---|
url | 下载文件的URL,支持HTTP,HTTPS或FTP协议 |
dest | 下载到目标路径(绝对路径),如果目标是一个目录,就用服务器上面文件的名称, 如果目标设置了名称就用目标设置的名称 |
owner | 指定属主 |
group | 指定属组 |
mode | 指定权限 |
force | 如果yes,dest不是目录,将每次下载文件,如果内容改变,替换文件。 如果否,则只有在目标不存在时才会下载该文件 |
checksum | 对目标文件在下载后计算摘要,以确保其完整性 示例: checksum="sha256:D98291AC[...]B6DC7B97" ,checksum="sha256:http://example.com/path/sha256sum.txt " |
url_username | 用于HTTP基本认证的用户名。对于允许空密码的站点,此参数可以不使用url_password |
url_password | 用于HTTP基本认证的密码。如果未指定url_username 参数,则不会使用url_password 参数 |
validate_certs | 如果“no”,SSL证书将不会被验证。适用于自签名证书在私有网站上使用 |
timeout | URL请求的超时时间,秒为单位 |
示例
root@ubuntu20:~# ansible db -m get_url -a'url=http://nginx.org/download/nginx-1.18.0.tar.gz dest=/usr/local/src/nginx.tar.gz checksum="md5:b2d33d24d89b8b1f87ff5d251aa27eb8"'
10.0.0.16 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"},"changed": true,"checksum_dest": null,"checksum_src": "47b2c5ccd12e2a7088b03d629ff6b9ab18215180","dest": "/usr/local/src/nginx.tar.gz","elapsed": 6,"gid": 0,"group": "root","md5sum": "b2d33d24d89b8b1f87ff5d251aa27eb8","mode": "0644","msg": "OK (1039530 bytes)","owner": "root","size": 1039530,"src": "/root/.ansible/tmp/ansible-tmp-1621674758.5972314-6460-48209020573716/tmp89g8bing","state": "file","status_code": 200,"uid": 0,"url": "http://nginx.org/download/nginx-1.18.0.tar.gz"
}
10.0.0.15 | CHANGED => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python3"},"changed": true,"checksum_dest": null,"checksum_src": "47b2c5ccd12e2a7088b03d629ff6b9ab18215180","dest": "/usr/local/src/nginx.tar.gz","elapsed": 19,"gid": 0,"group": "root","md5sum": "b2d33d24d89b8b1f87ff5d251aa27eb8","mode": "0644","msg": "OK (1039530 bytes)","owner": "root","size": 1039530,"src": "/root/.ansible/tmp/ansible-tmp-1621674759.1839962-6459-130540770817695/tmpdp0h0nc7","state": "file","status_code": 200,"uid": 0,"url": "http://nginx.org/download/nginx-1.18.0.tar.gz"
}
root@ubuntu20:~#
Fetch:从客户端取文件至服务器端,copy相反,目录可先tar
功能:从远程主机提取文件至ansible的主控端,copy相反,目前不支持目录
ansible-doc -s fetch
# 抓取所有被监控机的日志(只能抓取单个文件)
mkdir /log
ansible all -m ftech -a 'src=/var/log/message dest=/log/'#抓取所有日志文件
ansible all -m shell -a 'tar jcf log.tar.xz /var/log/*.log'
ansible all -m ftech -a 'src=/root/log.tar.xz dest=/log/'
tar tvf log.tar.xz
示例
root@ubuntu20:~# ansible 10.0.0.11 -m fetch -a 'src=/root/script/for_user.sh dest=/tmp'
10.0.0.11 | SUCCESS => {"changed": false,"checksum": "a3d4cefd470383ea4c80f12464a0cf953b26597c","dest": "/tmp/10.0.0.11/root/script/for_user.sh","file": "/root/script/for_user.sh","md5sum": "3cb5c8efcecbee10583b33c40a611f15"
}
root@ubuntu20:~# ll /tmp/10.0.0.11/root/script/for_user.sh
-rw-r--r-- 1 root root 353 5月 22 17:18 /tmp/10.0.0.11/root/script/for_user.sh
root@ubuntu20:~
示例
root@ubuntu20:~# ansible web -m fetch -a 'src=/etc/os-release dest=/data/os'
10.0.0.15 | SUCCESS => {"changed": false,"checksum": "ccb4459029c37b82e2e29bd2bc138ec241490521","dest": "/data/os/10.0.0.15/etc/os-release","file": "/etc/os-release","md5sum": "22ab75a1abcb3fc44748307848e32ae6"
}
10.0.0.11 | SUCCESS => {"changed": false,"checksum": "6e35f19e5774acd00f10342edef82a8247674028","dest": "/data/os/10.0.0.11/etc/os-release","file": "/etc/os-release","md5sum": "0868a2ea7fc0d17dec85d63f452563d4"
}
root@ubuntu20:~# tree /data/os
/data/os
├── 10.0.0.11
│ └── etc
│ └── os-release
└── 10.0.0.15└── etc└── os-release4 directories, 2 files
root@ubuntu20:~#
File:设置文件属性
功能:设置文件属性,创建软链接等
# 查看帮助
ansible-doc -s file
选项 | 说明 |
---|---|
force | 需要在两种情况下强制创建软链接,一种是源文件不存在但之后会建立的情况下; 另一种是目标软链接已存在,需要先取消之前的软链,然后创建新的软链,有两个选项:yes |
group | 定义文件/目录的属组 |
mode | 定义文件/目录的权限 |
owner | 定义文件/目录的属主 |
path | 必选项,定义文件/目录的路径 |
recurse | 递归的设置文件的属性,只对目录有效 |
src | 要被链接的源文件的路径,只应用于state=link的情况 |
dest | 被链接到的路径,只应用于state=link的情况 |
state | directory:如果目录不存在,创建目录 file:即使文件不存在,也不会被创建 link:创建软链接 hard:创建硬链接 touch:如果文件不存在,则会创建一个新的文件,如果文件或目录已存在,则更新其最后修改时间 absent:删除目录、文件或者取消链接文件 |
示例
# 创建软连接,将/etc/fstab软连到/tmp/fstab
ansible web -m file -a "src=/etc/fstab dest=/tmp/fstab state=link"
# 在master上或者test上查看结果:
ansible web -a "ls -lh /tmp"
#删除软连接
ansible web -m file -a "dest=/tmp/fstab state=absent"# 在master上删除;-m 指定模块 ;-a 指定模块参数
ansible web -m file -a 'path=/tmp/fstab state=absent'
ansible web -m file -a 'path=/etc/yum.repos.d/xxx.repo state=absent' # 在 web创建file1文件
ansible web -m file -a 'path=/tmp/file1 state=touch'
ansible web -m file -a 'path=/tmp/file2 owner=song mode=755'
# 删除file1文件
ansible web -m file -a 'path=/tmp/file1 state=absent'
# 查看文件
ansible web -m shell -a 'ls /tmp -lh'# 在we上创建文件夹
ansible we -m file -a 'path=/tmp/d1 state=directory owner=root group=root mode=755'
# 删除文件夹
ansible web -m file -a 'path=/tmp/d1 state=absent'# 递归修改目录属性,但不递归至子目录
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql"# 递归修改目录及子目录的属性
ansible all -m file -a "path=/data/mysql state=directory owner=mysql group=mysql recurse=yes"
service模块
功能:管理服务
选项 | 说明 |
---|---|
arguments | 给命令行提供一些选项 |
enabled | 是否开机启动 yes |
name | 必选项,服务名称 |
pattern | 定义一个模式,如果通过status指令来查看服务的状态时, 没有响应,就会通过ps指令在进程中根据该模式进行查找, 如果匹配到,则认为该服务依然在运行 |
runlevel | 运行级别 |
sleep | 如果执行了restarted,在则stop和start之间沉睡几秒钟 |
state | 对当前服务执行启动,停止、重启、重新加载等操作(started,stopped,restarted,reloaded) |
示例
# 启动服务(并设置开启自启动)
ansible web -m service -a 'name=nginx state=started enabled=yes'
ansible web -m raw -a 'ps -ef|grep nginx'
ansible web -m service -a 'name=nginx state=stopped enabled=yes'# 重新加载
ansible web -m service -a 'name=nginx state=reloaded'
ansible web -m raw -a 'ps -ef|grep nginx'
ansible web -m service -a 'name=nginx state=restarted sleep=3'
ansible web -m service -a 'name=network state=restarted args=eth0'
ansible web -m service -a 'name=foo pattern=/usr/bin/foo state=started'
user模板
功能:管理用户
选项 | 解释 |
---|---|
home | 指定用户的家目录,需要与createhome配合使用 |
groups | 指定用户的属组 |
uid | 指定用的uid |
password | 指定用户的密码,注意:passwd的值不能是明文, passwd关键字后面应该是密文,且密文将被保存在/etc/shadow文件中 |
name | 指定用户名 |
createhome | 是否创建家目录 yes |
system | 是否为系统用户 |
remove | 当state=absent时,remove=yes则表示连同家目录一起删除,等价于userdel -r |
state | 是创建还是删除(present,absent) |
shell | 指定用户的shell环境 |
generate_ssh_key | 是否为相关用户生成SSH密钥。 这不会覆盖现有的SSH密钥。 |
ssh_key_bits | 可选择指定要创建的SSH密钥中的位数。 |
ssh_key_passphrase | 设置SSH密钥的密码, 如果没有提供密码,SSH密钥将默认没有密码。 |
ssh_key_file | 指定SSH密钥文件名(可选) 如果这是一个相对的文件名,那么它将是相对于用户的主目录。 |
ssh_key_type | 指定要生成的SSH密钥的类型(可选) 可用的SSH密钥类型将取决于目标主机上的实现。 |
示例
# 使用user模块创建用户
ansible w1 -m user -a 'name=nginx shell=/sbin/nologin system=yes home=/var/nginx group=nginx groups=root,bin uid=80 comment="nginx service" create_home=no non_unique=yes'
ansible w1 -a 'getent passwd nginx'ansible web -m user -a 'name=user1 comment="test user" uid=2048 home=/app/user1 group=root'ansible web -m user -a 'name=sysuser1 system=yes home=/app/sysuser1'# 生成song123加密的密码
root@ubuntu20:~# ansible localhost -m debug -a "msg={{ 'song123'| password_hash('sha512','salt')}}"
localhost | SUCCESS => {"msg": "$6$salt$YjkHZzCRK8Kl2B6mGzlYbO7MlpZIa0AbpM36P/NaQPOgmLCK2H0obwdY6V47h/UFsB/cL.VYdt6P6Uk0FWBar0"
}
root@ubuntu20:~## 用上面创建的密码创建用户
ansible web -m user -a 'createhome=yes home=/home/user1 password="$6$salt$YjkHZzCRK8Kl2B6mGzlYbO7MlpZIa0AbpM36P/NaQPOgmLCK2H0obwdY6V47h/UFsB/cL.VYdt6P6Uk0FWBar0" name=user1 state=present shell=/bin/bash'# 创建用户adwl,并生成4096bit的私钥
ansible web -m user -a 'name=adwl generate_ssh_key=yes ssh_key_bits=4096 ssh_key_file=.ssh/id_rsa'# 使用user模块删除用户(删除家目录remove=yes,默认remove=no)
ansible web -m user -a 'remove=yes state=absent name=user1'
Ansible批量更新远程主机用户密码方法
方法一: 使用Ansible的user模块批量修改远程客户机的用户密码
#由于在使用ansible修改用户密码的时候不能使用明文的方式,需要先加密,所以就需要使用一个方法对输入的明文的密码进行加密.
cat /opt/root_passwd.yaml
---- hosts: ssh-hostgather_facts: falsetasks:- name: change user passwduser: name={{ item.name }} password={{ item.chpass | password_hash('sha512') }} update_password=alwayswith_items:- { name: 'root', chpass: 'kevin@123' }- { name: 'app', chpass: 'bjop123' }#注意上面在yaml文件中修改了远程客户机的root用户密码, app用户密码.
#如果还想要修改其他用户密码, 则继续按照上面规则添加即可!#执行ansible-play
ansible-playbook /opt/root_passwd.yaml
方法二: 修改远程主机的单个用户密码使用此方法比较方便
# 编写playbook文件
cat /opt/root_passwd2.yaml
---- hosts: ssh-hostgather_facts: falsetasks:- name: Change passworduser: name={{ name1 }} password={{ chpass | password_hash('sha512') }} update_password=always# 执行ansible-playbook, 使用-e参数传递用户名和密码给剧本,其中root为用户名,admin#123就是修改后的root密码
ansible-playbook /opt/root_passwd2.yaml -e "name1=root chpass=admin#123"
方法三: 使用如下Ansible脚本, 适用于修改清单中部分远程主机的用户密码
#编写ansible-playbook脚本 (需要注意下面脚本中"ens192"是客户机ip所在的网卡设备名称, 这个要根据自己实际环境去配置, 比如eth0, eth1等)
cat /opt/root_passwd4.yaml
- hosts: test-hostremote_user: roottasks:- name: change password for rootshell: echo '{{ item.password }}' |passwd --stdin rootwhen: ansible_ens192.ipv4.address == '{{ item.ip }}'with_items:- { ip: "172.16.60.220", password: 'haha@123' }- { ip: "172.16.60.221", password: 'kevin@123' }- { ip: "172.16.60.222", password: 'bobo@123' }# 执行ansible-playbook:
ansible-playbook /opt/root_passwd3.yaml
group:管理组
# 查看帮助
ansible-doc -s group
# 创建组
ansible web -m group -a "name=nginx system=yes gid=80"
# 验证
ansible web -a 'getent group nginx'
# 删除组
ansible web -m group -a "name=nginx state=absent"
Hostname 模块
功能:管理主机名
示例
ansible node1 -m hostname -a "name=web001"
ansible 10.162.0.11 -m hostname -a 'name=node002.update.south'
yum 和 apt 模块
功能:yum 管理软件包,只支持RHEL,CentOS,fedora,不支持Ubuntu其它版本
apt 模块管理 Debian 相关版本的软件包
yum 包含如下选项
header 1 | header 2 |
---|---|
config_file | yum的配置文件 |
disable_gpg_check | 关闭gpg_check |
disablerepo | 不启用某个源 |
enablerepo | 启用某个源 |
name | 要进行操作的软件包的名字,也可以传递一个url或者一个本地的rpm包的路径 |
state | 状态(present,absent,latest) |
示例:
# 安装
ansible web -m yum -a 'name=httpd state=latest'
ansible web -m yum -a 'name=httpd state=present'
# 启用 epel 源进行安装
ansible websrvs -m yum -a 'name=nginx state=present enablerepo=epel' # 升级除 kernel 和 foo 开头以外的所有包
ansible websrvs -m yum -a 'name=* state=lastest exclude=kernel*,foo*' # 删除
ansible web -m yum -a 'name=httpd state=absent'# 安装多个包
ansible web -m yum -a 'name=httpd,nginx,redis state=latest'# 卸载多个包
ansible web -m yum -a 'name=httpd,nginx,redis state=absent'# 查看yum.repos.d文件夹
ansible web -m command -a 'ls /etc/yum.repos.d/'# 删除xxx.repo文件
ansible web -m file -a 'path=/etc/yum.repos.d/xxx.repo state=absent' # 更改yum源
ansible all -m copy -a 'src=/etc/yum.repos.d/163.repo dest=/etc/yum.repos.d/163.repo'
ansible web -m yum -a 'name=httpd state=installed'
ansible web -m service -a 'name=httpd state=started'
ansible web -m shell -a 'ps -ef|grep httpd'# 清除更新缓存
ansible 10.162.35.10[1-2] -m yum -a 'name=httpd update_cache=yes'
示例
[root@ansible ~]#ansible websrvs -m yum -a
"name=https://mirror.tuna.tsinghua.edu.cn/zabbix/zabbix/5.2/rhel/7/x86_64/zabbix-agent-5.2.5-1.el7.x86_64.rpm"
示例:查看包
ansible localhost -m yum -a "list=tree"
yum_repository 模块
- name: Add multiple repositories into the same file (1/2)yum_repository:name: epeldescription: EPEL YUM repofile: external_reposbaseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/gpgcheck: no- name: Add multiple repositories into the same file (2/2)yum_repository:name: rpmforgedescription: RPMforge YUM repofile: external_reposbaseurl: http://apt.sw.be/redhat/el7/en/$basearch/rpmforgemirrorlist: http://mirrorlist.repoforge.org/el7/mirrors-rpmforgeenabled: no- name: Remove repository from a specific repo fileyum_repository:name: epelfile: external_reposstate: absent
示例:创建和删除仓库
cat yum_repo.yml
---
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: Add multiple repositories into the same fileyum_repository:name: testdescription: EPEL YUM repofile: external_reposbaseurl: https://download.fedoraproject.org/pub/epel/$releasever/$basearch/gpgcheck: no
ansible-playbook yum_repo.yml
cat /etc/yum.repos.d/external_repos.repocat remove_yum_repo.yml
---
- hosts: websrvsremote_user: rootgather_facts: notasks:- name: remove repoyum_repository:name: testfile: external_reposstate: absentansible-playbook remove_yum_repo.yml
cron模块:用于管理计划任务
功能:计划任务
支持时间:minute,hour,day,month,weekday
包含如下选项
header 1 | header 2 |
---|---|
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 | 以哪个用户的身份执行 |
示例
#创建计划任务:每周二的5点重启机器
ansible t1 -m cron -a 'name="rebootSystem" minute=0 hour="5" day=0 month=0 weekday=2 user=root job="/sbin/reboot"'# 查看计划任务
ansible t1 -m shell -a 'crontab -l'# 禁用计划任务(必须加 name 选项)
ansible all -m cron -a 'disabled=true name="rebootSystem" job="/sbin/reboot"'#启用计划任务
ansible all -m cron -a 'disabled=false name="rebootSystem" job="/sbin/reboot"'# 删除计划任务,直接写上name删除
ansible t1 -m cron -a 'name="rebootSystem" minute=0 hour="5" day=0 month=0 weekday=2 user=root job="/sbin/reboot" state=absent'
ansible test -m cron -a 'name="rebootSystem" state=absent'# 创建计划任务,每3分钟显示一次home目录
ansible test -m cron -a 'name="check home directory" minute=*/3 job="ls -lh /home"'
# 查看计划任务
ansible test -m command -a 'crontab -l'#创建计划任务,指定时间执行
ansible test -m cron -a 'name="check home directory" special_time=reboot job="echo reboot"'
示例
# 备份数据库脚本
[root@centos8 ~]#cat /root/mysql_backup.sh
#!/bin/bash
mysqldump -A -F --single-transaction --master-data=2 -q -uroot |gzip > /data/mysql_`date +%F_%T`.sql.gz# 创建任务
ansible 10.0.0.11 -m cron -a 'hour=2 minute=30 weekday=1-5 name="backup mysql" job=/root/mysql_backup.sh'ansible db -m cron -a "minute=*/5 job='/usr/sbin/ntpdate ntp.aliyun.com &>/dev/null' name=Synctime"# 禁用计划任务
ansible db -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=yes"# 启用计划任务
ansible db -m cron -a "minute=*/5 job='/usr/sbin/ntpdate 172.20.0.1 &>/dev/null' name=Synctime disabled=no"# 删除任务
ansible db -m cron -a "name='backup mysql' state=absent"
ansible db -m cron -a 'state=absent name=Synctime'
synchronize-----使用rsync同步文件
Ansible synchronize模块主要用于目录、文件的同步,主要基于rsync命令工具同步目录和文件
Ansible synchronize模块详解
header 1 | header 2 |
---|---|
compress | 开启压缩,默认为开启 |
archive | 是否采用归档模式同步,保证源文件和目标文件属性一致 |
checksum | 是否效验 |
dirs | 以非递归的方式传送目录 |
links | 同步链接文件 |
recursive | 是否递归yes/no |
rsync_opts | 使用rsync的参数 |
copy_links | 同步的时候是否复制链接 |
delete | 删除源中没有但目标存在的文件,使两边内容一样,以推送方为主 |
src | 源目录及文件 |
dest | 目标文件及目录 |
dest_port | 目标接收的端口 |
rsync_path | 服务的路径,指定rsync在远程服务器上执行 |
rsync_remote_user | 设置远程用户名 |
–exclude=.log | 忽略同步以.log结尾的文件,这个可以自定义忽略什么格式的文件, 或者.txt等等都可以,但是由于这个是rsync命令的参数, 所以必须和rsync_opts一起使用,比如rsync_opts=–exclude=.txt这种模式 |
mode | 同步的模式,rsync同步的方式push、pull,默认是推送push, 从本机推送给远程主机,pull表示从远程主机上拿文件 |
示例:
ansible-doc -s synchronize# 查看目录是否存在
ansible test -m file -a 'path=/var/www/ state=directory'# 使用synchronize模块同步文件
ansible test -m synchronize -a 'src=/tmp/helloworld dest=/var/www/'
ansible test -a 'cat /var/www/helloworld'# 使用synchronize模块同步目录
ansible test -m synchronize -a 'src=/etc/ansible/playbooks dest=/tmp/ mode=push'
filesystem模块—在块设备上创建文件系统
#包含如下选项:
dev:目标块设备
force:在一个已有文件系统的设备上强制创建
fstype:文件系统的类型
opts:传递给mkfs命令的选项
mount-----配置挂载点
dump:
fstype:必选项,挂的文件的类型
name:必选项,挂载点
stat 模块
功能:检查文件或文件系统的状态
注意:对于Windows目标,请改用win_stat模块
选项
path:文件/对象的完整路径(必须)
常用的返回值判断
exists: 判断是否存在isuid: 调用用户的ID与所有者ID是否匹配
示例
root@ubuntu20:~# ansible 127.0.0.1 -m stat -a 'path=/root/testfile'
127.0.0.1 | SUCCESS => {"changed": false,"stat": {"atime": 1620783434.6542244,"attr_flags": "e","attributes": ["extents"],"block_size": 4096,"blocks": 8,"charset": "us-ascii","checksum": "9296e63da2444e14deac52fb58499ee02373ef5b","ctime": 1620783429.9102886,"dev": 2049,"device_type": 0,"executable": false,"exists": true,"gid": 0,"gr_name": "root","inode": 5509736,"isblk": false,"ischr": false,"isdir": false,"isfifo": false,"isgid": false,"islnk": false,"isreg": true,"issock": false,"isuid": false,"mimetype": "text/plain","mode": "0644","mtime": 1620783429.9102886,"nlink": 1,"path": "/root/testfile","pw_name": "root","readable": true,"rgrp": true,"roth": true,"rusr": true,"size": 45,"uid": 0,"version": "4282118675","wgrp": false,"woth": false,"writeable": true,"wusr": true,"xgrp": false,"xoth": false,"xusr": false}
}
root@ubuntu20:~#
示例
- name: install | Check if file is already configured.stat: path={{ nginx_file_path }}connection: localregister: nginx_file_result
- name: install | Download nginx fileget_url: url={{ nginx_file_url }} dest={{ software_files_path }}
validate_certs=noconnection: localwhen:,not. nginx_file_result.stat.exists
示例
root@ubuntu20:~# cat stat.yaml
---
- hosts: dbremote_user: rootgather_facts: notasks:- name: checkfilestat: path=/data/mysqlregister: st- name: debugdebug:msg: "/data/mysql is not exist"when: not st.stat.exists
root@ubuntu20:~# ansible-playbook stat.yamlPLAY [db] ********************************************************************************************************************TASK [checkfile] *************************************************************************************************************
ok: [10.0.0.16]
ok: [10.0.0.15]TASK [debug] *****************************************************************************************************************
skipping: [10.0.0.16]
ok: [10.0.0.15] => {"msg": "/data/mysql is not exist"
}PLAY RECAP *******************************************************************************************************************
10.0.0.15 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.16 : ok=1 changed=0 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0root@ubuntu20:~#
unarchive
功能:解包解压缩
实现有两种用法:
-
1、将ansible主机上的压缩包传到远程主机后解压缩至特定目录,设置copy=yes,此为默认值,可省略
-
2、将远程主机上的某个压缩包解压缩到指定路径下,设置copy=no
常见参数
header 1 | header 2 |
---|---|
copy | 默认为yes,当copy=yes,拷贝的文件是从ansible主机复制到远程主机上,如果设置为copy=no, 会在远程主机上寻找src源文件 |
remote_src | 和copy功能一样且互斥,yes表示在远程主机,不在ansible主机,no表示文件在ansible 主机上 |
src | 源路径,可以是ansible主机上的路径,也可以是远程主机(被管理端或者第三方主机)上的路径, 如果是远程主机上的路径,则需要设置copy=no |
dest | 远程主机上的目标路径 |
mode | 设置解压缩后的文件权限 |
ansible all -m unarchive -a 'src=/data/foo.tgz dest=/var/lib/foo owner=song group=bin'ansible all -m unarchive -a 'src=/tmp/foo.zip dest=/data copy=no mode=0777'ansible all -m unarchive -a 'src=https://example.com/example.zip dest=/data copy=no'ansible websrvs -m unarchive -a 'src=https://releases.ansible.com/ansible/ansible-2.1.6.0-0.1.rc1.tar.gz dest=/data/ owner=root remote_src=yes'ansible websrvs -m unarchive -a 'src=http://nginx.org/download/nginx-1.18.0.tar.gz dest=/usr/local/src/ copy=no'
Archive 模块
功能:打包压缩保存在被管理节点
示例
ansible websrvs -m archive -a 'path=/var/log/ dest=/data/log.tar.bz2 format=bz2 owner=song mode=0600'
Lineinfile 模块
ansible在使用sed进行替换时,经常会遇到需要转义的问题,而且ansible在遇到特殊符号进行替换时, 存在问题,无法正常进行替换 。其实在ansible自身提供了两个模块:lineinfile模块和replace模块,可 以方便的进行替换
一般在ansible当中去修改某个文件的单行进行替换的时候需要使用lineinfile模块
regexp参数 :使用正则表达式匹配对应的行,当替换文本时,如果有多行文本都能被匹配,则只有最后面被匹配到的那行文本才会被替换,当删除文本时,如果有多行文本都能被匹配,这么这些行都会被删除。
如果想进行多行匹配进行替换需要使用replace模块
功能:相当于sed,可以修改文件内容
示例
ansible websrvs -m lineinfile -a "path=/etc/httpd/conf/httpd.conf regexp='^Listen' line='Listen 80'"ansible all -m lineinfile -a "path=/etc/selinux/config regexp='^SELINUX='line='SELINUX=disabled'"ansible all -m lineinfile -a 'dest=/etc/fstab state=absent regexp="^#"'
Replace 模块
该模块有点类似于sed命令,主要也是基于正则进行匹配和替换,建议使用
示例
ansible all -m replace -a "path=/etc/fstab regexp='^(UUID.*)' replace='#\1'"ansible all -m replace -a "path=/etc/fstab regexp='^#(UUID.*)' replace='\1'"
SELinux 模块
该模块管理 SELInux 策略
示例
root@ubuntu20:~# ansible 10.0.0.11 -m selinux -a 'state=disabled'
10.0.0.11 | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/libexec/platform-python"},"changed": false,"configfile": "/etc/selinux/config","msg": "","policy": "targeted","reboot_required": false,"state": "disabled"
}
root@ubuntu20:~#[root@centos8 ~]#grep -v '#' /etc/selinux/configSELINUX=disabled
SELINUXTYPE=targeted[root@centos8 ~]#getenforce
Disabled
[root@centos8 ~]#
reboot 模块
ansible web -m reboot
mount 挂载和卸载
功能: 挂载和卸载文件系统
示例
# 临时挂载
mount web -m mount -a 'src="UUID=b3e48f45-f933-4c8e-a700-22a159ec9077" path=/home fstype=xfs opts=noatime state=present'# 临时取消挂载
mount web -m mount -a 'path=/home fstype=xfs opts=noatime state=unmounted'# 永久挂载
ansible web -m mount -a 'src=10.0.0.11:/data/wordpress path=/var/www/html/wp- content/uploads opts="_netdev" state=mounted'# 永久卸载
ansible web -m mount -a 'src=10.0.0.11:/data/wordpress path=/var/www/html/wp- content/uploads state=absent'
debug 模块
此模块可以输出信息
注意: msg后面的变量需要加 " " 引起来
示例
root@ubuntu20:~# ansible db -m debug
10.0.0.16 | SUCCESS => {"msg": "Hello world!"
}
10.0.0.15 | SUCCESS => {"msg": "Hello world!"
}
root@ubuntu20:~#
示例
root@ubuntu20:~# cat debug.yaml
---
- hosts: dbremote_user: rootgather_facts: notasks:- name: output hello worlddebug:# 默认没有指定msg,默认输出"Hello world!"
root@ubuntu20:~# ansible-playbook debug.yamlPLAY [db] ********************************************************************************************************************TASK [output hello world] ****************************************************************************************************
ok: [10.0.0.15] => {"msg": "Hello world!"
}
ok: [10.0.0.16] => {"msg": "Hello world!"
}PLAY RECAP *******************************************************************************************************************
10.0.0.15 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.16 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0root@ubuntu20:~#
示例:利用 debug 模块输出变量
root@ubuntu20:~# cat debug.yaml
---
- hosts: dbremote_user: rootgather_facts: yestasks:- name: output variablesdebug:msg: HostName "{{ ansible_nodename }}" IPaddr "{{ ansible_default_ipv4.address }}"
root@ubuntu20:~# ansible-playbook debug.yamlPLAY [db] ********************************************************************************************************************TASK [Gathering Facts] *******************************************************************************************************
ok: [10.0.0.16]
ok: [10.0.0.15]TASK [output variables] ******************************************************************************************************
ok: [10.0.0.15] => {"msg": "HostName \"song-VirtualBox\" IPaddr \"172.18.1.125\""
}
ok: [10.0.0.16] => {"msg": "HostName \"ubuntu20\" IPaddr \"172.18.1.4\""
}PLAY RECAP *******************************************************************************************************************
10.0.0.15 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.16 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0root@ubuntu20:~#
注意:此处如果 gather_facts: no
将无法得到变量的值,会报错
root@ubuntu20:~# ansible-playbook debug.yamlPLAY [db] ********************************************************************************************************************TASK [output variables] ******************************************************************************************************
fatal: [10.0.0.15]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was:
'ansible_nodename' is undefined\n\nThe error appears to be in '/root/debug.yaml': line 7, column 7,
but may\nbe elsewhere in the file depending on the exact syntax problem.\n\n
The offending line appears to be:\n\n tasks:\n - name: output variables\n ^ here\n"}
fatal: [10.0.0.16]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was:
'ansible_nodename' is undefined\n\nThe error appears to be in '/root/debug.yaml': line 7, column 7,
but may\nbe elsewhere in the file depending on the exact syntax problem.\n\n
The offending line appears to be:\n\n tasks:\n - name: output variables\n ^ here\n"}PLAY RECAP *******************************************************************************************************************
10.0.0.15 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
10.0.0.16 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0root@ubuntu20:~#
示例:显示字符串特定字符
root@ubuntu20:~# cat debug.yaml
---
- hosts: dbremote_user: rootgather_facts: novars:str: "abcdefg"tasks:- debug:msg: "{{ str[3] }}"
root@ubuntu20:~# ansible-playbook debug.yamlPLAY [db] ********************************************************************************************************************TASK [debug] *****************************************************************************************************************
ok: [10.0.0.15] => {"msg": "d"
}
ok: [10.0.0.16] => {"msg": "d"
}PLAY RECAP *******************************************************************************************************************
10.0.0.15 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.0.0.16 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0root@ubuntu20:~#