前面ansible系列的内容介绍了基础信息, 而番外篇则介绍了定位准备ansible环境过程中如何定位SSH带来的问题的全过程, 本文开始笔者将从实践的角度介绍ansible。

如图所示, ansible有两种常用的使用方式,分别是ad-hoc和palybook, 其中playbook又包含基本的playbook及复杂的使用roles组织的形式。 本文先介绍ad-hoc模式, 其它的放到后续的文章介绍。
ad-hoc模式(http://ansible.com.cn/docs/intro_adhoc.html), 顾名思义,ad-hoc有单次的意思, 就是说通过命令行方式单次执行单个命令的一种使用模式。 它适用于用来快速地验证环境或者做一些比较简单的模式等场景。
我们先来看下ansible支持的命令行, 采用的ansible版本信息如下:(约定, 主机/用户名等敏感信息约定进行脱敏, 采用<host-xx>、<user-xx>等形式来替代)
(base) bash-4.1$ ansible --versionansible 2.9.6config file = /home/<user-xx>/.ansible.cfgconfigured module search path = ['/home/<user-xx>/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']ansible python module location = home/<user-xx>/anaconda3/lib/python3.7/site-packages/ansibleexecutable location = home/<user-xx>/anaconda3/bin/ansiblepython version = 3.7.4 (default, Aug 13 2019, 20:35:49) [GCC 7.3.0]
ansible提供的命令如下:
(base) bash-4.1$ ansible -husage: ansible[-h] # 帮助信息[--version] # 版本信息[-v] # 同--version[-b] #以提权后的用户执行命令[--become-method BECOME_METHOD] # 提权方法,通常是sudo[--become-user BECOME_USER] # 切换帐户[-K] # 请求sudo时密码[-i INVENTORY] # 指定主机文件路径[--list-hosts] # 列出主机清单[-l SUBSET] # 指定一种模式, 用于过滤出有效主机[-P POLL_INTERVAL] # 定期POLL_INTERVAL秒返回后台任务进度[-B SECONDS] # 超过SECONDS秒后杀死后台执行命令[-o] # 标准输出到一行[-t TREE] # 输出信息到TREE目录下[-k] # 请求ssh密码[--private-key PRIVATE_KEY_FILE] # 私有密钥路径[-u REMOTE_USER] # 登录远程被管节点的帐户[-c CONNECTION] # 指定连接方式, 包括ssh、 pramiko等[-T TIMEOUT] # SSH连接超时[--ssh-common-args SSH_COMMON_ARGS] # ssh通用参数[--sftp-extra-args SFTP_EXTRA_ARGS] # sftp额外参数[--scp-extra-args SCP_EXTRA_ARGS] # scp额外参数[--ssh-extra-args SSH_EXTRA_ARGS] # ssh额外参数[-C] # 模拟执行但不会真正执行[--syntax-check] # 语法检查,通用是playbook[-D] # 比较文件、模板的区别[-e EXTRA_VARS] # 额外变量[--vault-id VAULT_IDS] # 用于加密的保险库ID?[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES] 用于加密的保险库密码?[-f FORKS] # 进程并发数量[-M MODULE_PATH] # 使用的模块的路径[--playbook-dir BASEDIR] # playbook的根路径[-a MODULE_ARGS] # 模块参数[-m MODULE_NAME] # 选用模块pattern #与哪台主机进行交互
先来看一下用于确认基础环境是否OK的常用的ping和command模块,如下:
(base) bash-4.1$ ansible host_02 -m ping<host-xx> | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"},"changed": false,"ping": "pong"}(base) bash-4.1$ ansible host_02 -m command -a uptime<host-xx> | CHANGED | rc=0 >>22:38:09 up 11 days, 6:25, 1 user, load average: 1.79, 1.88, 1.75(base) bash-4.1$
命令的基本格式是 ansible <主机信息> -m 模块信息 -a 模块参数
第一条命令是使用ping模块测试连通性, 第二个命令是使用command模块(缺省模块,可以不显示指出来)执行uptime命令获取开机时间。
ad-hoc模式的使用方式就是类似上面这样简单方便, 在特定的场景下起着重要的作用。
之前定位SSH问题时, 曾经加上了-vvv (3个v就够了, 4个更详细)来调试具体的交互过程, 同样地我们可以来看一下ad-hoc模式下, 整个过程大概都做了哪些事情,还是以上面ping命令为例子, 如下:
(base) bash-4.1$ ansible host_02 -m ping -vvv#获取并显示当前ansible版本、模块等基础信息ansible 2.9.6config file = home/<user-xx>/.ansible.cfgconfigured module search path = ['/home/<user-xx>/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']ansible python module location = home/<user-xx>/anaconda3/lib/python3.7/site-packages/ansibleexecutable location = home/<user-xx>/anaconda3/bin/ansiblepython version = 3.7.4 (default, Aug 13 2019, 20:35:49) [GCC 7.3.0]# 读取配置文件Using home/<user-xx>/.ansible.cfg as config filehost_list declined parsing home/<user-xx>/.ansible/hosts as it did not pass its verify_file() methodscript declined parsing home/<user-xx>/.ansible/hosts as it did not pass its verify_file() methodauto declined parsing home/<user-xx>/.ansible/hosts as it did not pass its verify_file() methodParsed /home/<user-xx>/.ansible/hosts inventory source with ini pluginMETA: ran handlers# 与被管节点建立连接, 获取使用的帐户的home目录<host-xx> ESTABLISH SSH CONNECTION FOR USER: None## 具体执行命令<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 <host-xx> '/bin/sh -c '"'"'echo ~ && sleep 0'"'"''## 返回的结果<host-xx> (0, b'/home/<user-xx>\n', b'')# 在被管节点的home目录下建立tmp目录并创建本次会话需要的临时文件<host-xx> ESTABLISH SSH CONNECTION FOR USER: None<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 <host-xx> '/bin/sh -c '"'"'( umask 77 && mkdir -p "` echo /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425 `" && echo ansible-tmp-1605883636.6817505-49446542390425="` echo /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425 `" ) && sleep 0'"'"''<host-xx> (0, b'ansible-tmp-1605883636.6817505-49446542390425=/home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425\n', b'')<host-xx> Attempting python interpreter discovery# 查找被管节点的python执行环境信息<host-xx> ESTABLISH SSH CONNECTION FOR USER: None<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 <host-xx> '/bin/sh -c '"'"'echo PLATFORM; uname; echo FOUND; command -v '"'"'"'"'"'"'"'"'/usr/bin/python'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.7'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.6'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python3.5'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python2.7'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python2.6'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'/usr/libexec/platform-python'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'/usr/bin/python3'"'"'"'"'"'"'"'"'; command -v '"'"'"'"'"'"'"'"'python'"'"'"'"'"'"'"'"'; echo ENDFOUND && sleep 0'"'"''<host-xx> (0, b'PLATFORM\nLinux\nFOUND\n/usr/bin/python\n/usr/bin/python2.7\n/usr/bin/python\nENDFOUND\n', b'')# 查询被管节点的系统信息<host-xx> ESTABLISH SSH CONNECTION FOR USER: None<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 <host-xx> '/bin/sh -c '"'"'/usr/bin/python && sleep 0'"'"''<host-xx> (0, b'{"osrelease_content": "NAME=\\"CentOS Linux\\"\\nVERSION=\\"7 (Core)\\"\\nID=\\"centos\\"\\nID_LIKE=\\"rhel fedora\\"\\nVERSION_ID=\\"7\\"\\nPRETTY_NAME=\\"CentOS Linux 7 (Core)\\"\\nANSI_COLOR=\\"0;31\\"\\nCPE_NAME=\\"cpe:/o:centos:centos:7\\"\\nHOME_URL=\\"https://www.centos.org/\\"\\nBUG_REPORT_URL=\\"https://bugs.centos.org/\\"\\n\\nCENTOS_MANTISBT_PROJECT=\\"CentOS-7\\"\\nCENTOS_MANTISBT_PROJECT_VERSION=\\"7\\"\\nREDHAT_SUPPORT_PRODUCT=\\"centos\\"\\nREDHAT_SUPPORT_PRODUCT_VERSION=\\"7\\"\\n\\n", "platform_dist_result": ["centos", "7.5.1804", "Core"]}\n', b'')Using module file /home/<user-xx>/anaconda3/lib/python3.7/site-packages/ansible/modules/system/ping.py# 将要执行的任务放到临时目录, 并通过 sftp上传到被管节点<host-xx> PUT /home/<user-xx>/.ansible/tmp/ansible-local-32382jry0hz_b/tmp4uuzwwg7 TO /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425/AnsiballZ_ping.py<host-xx> SSH: EXEC sftp -b - -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 '[<host-xx> ]'<host-xx> (0, b'sftp> put /home/<user-xx>/.ansible/tmp/ansible-local-32382jry0hz_b/tmp4uuzwwg7 /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425/AnsiballZ_ping.py\n', b'')# 给被管节点的任务文件添加执行权限<host-xx> ESTABLISH SSH CONNECTION FOR USER: None<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 <host-xx> '/bin/sh -c '"'"'chmod u+x /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425/ /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425/AnsiballZ_ping.py && sleep 0'"'"''<host-xx> (0, b'', b'')# 在被管节点执行任务, 这里是ping<host-xx> ESTABLISH SSH CONNECTION FOR USER: None<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 -tt <host-xx> '/bin/sh -c '"'"'/usr/bin/python /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425/AnsiballZ_ping.py && sleep 0'"'"''<host-xx> (0, b'\r\n{"invocation": {"module_args": {"data": "pong"}}, "ping": "pong"}\r\n', b'Shared connection to <host-xx> closed.\r\n')# 删除被管节点的临时文件<host-xx> ESTABLISH SSH CONNECTION FOR USER: None<host-xx> SSH: EXEC ssh -C -o ControlMaster=auto -o ControlPersist=60s -o StrictHostKeyChecking=no -o KbdInteractiveAuthentication=no -o PreferredAuthentications=gssapi-with-mic,gssapi-keyex,hostbased,publickey -o PasswordAuthentication=no -o ConnectTimeout=10 -o ControlPath=/home/disk3/<user-xx>/.ansible/cp/472fc29db8 <host-xx> '/bin/sh -c '"'"'rm -f -r /home/<user-xx>/.ansible/tmp/ansible-tmp-1605883636.6817505-49446542390425/ > /dev/null 2>&1 && sleep 0'"'"''<host-xx> (0, b'', b'')<host-xx> | SUCCESS => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"},"changed": false,"invocation": {"module_args": {"data": "pong"}},"ping": "pong"}META: ran handlersMETA: ran handlers(base) bash-4.1$
经历的步骤大概如下:
a. 获取并显示当前ansible版本、模块等基础信息
b. 读取配置文件
c. 与被管节点建立连接, 获取使用的帐户的home目录
d. 在被管节点的home目录下建立tmp目录并创建本次会话需要的临时文件
e. 查询被管节点的python执行环境信息
f. 查询被管节点的系统信息
g. 将要执行的任务放到临时目录, 并通过 sftp上传到被管节点
h. 给被管节点的任务文件添加执行权限
i. 在被管节点执行任务, 这里是ping
j. 删除被管节点的临时文件
可以看到看起来一个简单的命令, 实际上发生了多次交互, 同时也看到缺省模式需要多次建立远程的ssh连接, 效率会相对比较低。可以通过SSH的长链接属性来减少SSH本身的消耗,另外可以通过pipelining配置来将多条命令压缩在一个SSH去执行。
总的来说, ad-hoc模式对用户来说还是非常方便的, 且在一些场景下很管用, 值得好好学习一下常用的命令。




