Command命令模块
command模块在主机上面执行命令。
command模块获取以空格分隔的列表组成的命令。- 所指定的命令会在所有选择的主机上面执行。
- 不能处理shell命令,不能使用
$HOME以及重定向(>,<)、管道(|)、分号(;)、And符号(&)等。此时应使用shell模块。 - 要创建比使用空格分隔的参数更易于阅读的命令任务,请使用
args任务关键字传递参数或使用cmd参数。 - 自由格式命令或cmd参数是必须的。
command模块的帮助文档:https://docs.ansible.com/ansible/latest/modules/command_module.html
command模块的源码:https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/command.py
获取帮助信息:
| |
从command模块的官方文档https://docs.ansible.com/ansible/latest/modules/command_module.html中可以看出,此时使用了大量的playbook剧本做为示例,因此此时有必要去初步了解了Ansible剧本的使用,可以简单的了解一下Ansible剧本。
1. command模块参数
| 参数 | 可选值 | 默认值 | 说明 |
|---|---|---|---|
argv | list,将命令作为列表而不是字符串传递。使用argv避免引用否则会被错误解释的值(例如“用户名”)。只能提供字符串或列表形式,不能同时提供。 | ||
chdir | path,在执行命令前切换到指定的工作目录,类似于使用cd命令切换working directory工作目录 | ||
cmd | string,需要运行的命令 | ||
creates | path,文件名或glob模式,如果对应的文件存在,则忽略此步A filename or (since 2.0) glob pattern. If a matching file already exists, this step will not be run. This is checked before removes is checked. | ||
free_form | 自由形式运行,可执行任何linux命令,该参数实际不存在!!.比如,当我们想要在远程主机上执行ls命令时,我们并不需要写成free_form=ls,这样写反而是错误的,因为并没有任何参数的名字是free_form,当我们想要在远程主机中执行ls命令时,直接写成ls即可,这就是free_form参数的含义,因为command模块的作用是执行命令,所以,任何一个可以在远程主机上执行的命令都可以被称为free_form | ||
removes | path,文件名或glob模式,如果对应的文件存在,则执行此步A filename or (since 2.0) glob pattern. If a matching file exists, this step will be run. This is checked after creates is checked. | ||
stdin | path, 将指定路径设置为标准输入 | ||
stdin_add_newline | yes/no | yes | boolean,如果设置yes,则会在标准输入后面增加一行 |
strip_empty_ends | yes/no | yes | boolean,如果设置yes,则会移除标准输入/标准错误最后的空行 |
warn | yes/no | yes | boolean,如果设置yes,则会警告,在2.14版本会移除该参数 |
2. command模块返回值
| 键 | 是否返回 | 描述 |
|---|---|---|
cmd | 一直返回 | list,在远程主机上面执行的命令列表 |
start | 一直返回 | string,命令开始时间 |
end | 一直返回 | string,命令结束时间 |
delta | 一直返回 | string,命令运行时间 |
3. 执行剧本
为了便于测试,我们仅在一个节点(node1)上面执行剧本。
3.1 剧本文件语法检查、彩排和运行
| |
3.1.1 命令添加其他参数
| |
3.1.2 增加creates参数,如果文件存在则不会执行命令
| |
3.1.3 同时执行多个任务
| |
3.1.4 使用args任务关键字和cmd模块参数
| |
3.1.5 使用chdir改变工作路径以及argv增加命令列表
| |
可以看到第一个任务的标准输出是/tmp,说明工作目录已经正常切换到/tmp目录下。第二个任务中通过使用argv来定义任务列表,这样使得命令执行更加安全,可以避免Shell注入攻击。
3.1.6 注册变量和打印
| |
使用register关键字来注册变量,{{ variable }} 来输出变量。
将转义的内容放在
<code v-pre> ... </code>中。
3.1.7 测试free_form参数
Ansible实际上并没有free_form参数的。我们如果使用free_form参数反而会出错:
| |
3.1.8 使用removes参数检查文件是否存在,存在则执行任务
| |
可以发现/tmp路径存在,执行了命令pwd,而/tmp1路径不存在,没有执行命令pwd。
我们使用剧本运行测试一下:
| |
可以发现/tmp路径存在,执行了命令pwd,而/tmp1路径不存在,没有执行命令pwd。removes参数与creates参数刚好相反。
3.1.9 stdin与stdin_add_newline标准输入设置
可以参考https://www.stacknoob.com/s/5TsgVmKHFN4fn8qfn8V3gV和How to use command stdin in Ansible? 的指导设置stdin参数。
If you want to use the
stdinargument to thecommandmodule, take a look at the docs, which show examples using other options such ascreates, which looks like this:
1 2 3 4 5 6# You can also use the 'args' form to provide the options. - name: This command will change the working directory to somedir/ and will only run when /path/to/database doesn't exist. command: /usr/bin/make_database.sh arg1 arg2 args: chdir: somedir/ creates: /path/to/databaseFor your use case, you would want:
1 2 3 4- name: Log into Docker registry command: docker login --username "{{ docker_registry_username }}" --password-stdin args: stdin: "{{ docker_registry_password }}"Your first attempt failed because you were setting
stdinas a key at the task level (likewhenorignore_errors, etc), when you actually want it to be an argument to thecommandmodule.Your second attempt failed because it wasn’t valid YAML.
command – Execute commands on targets, see the examples. For Windows targets, use the win_command module instead. added in 2.4. Set the stdin of the command directly to the specified value. raw – Executes a low-down and dirty command. The official documentation on the raw module. script – Runs a local script on a remote node after transferring it. The official documentation on the script module. shell – Execute shell commands on targets. The official documentation on the shell module.
参照上面的例子进行docker hub登陆。
- 主机清单配置
增加docker-node节点
| |
- 修改剧本文件
| |
- 语法检查后执行脚本
| |
注意,本例中通过vars中定义了两个变量docker_registry_username和docker_registry_password,指定登陆docker hub的用户名和密码,参考ansible各种变量定义及引用。将密码直接写在剧本文件中比较危险,应该考虑使用Ansible Vault对密码进行加密,想了解Ansible Vault,请参考https://docs.ansible.com/ansible/latest/user_guide/playbooks_vault.html#playbooks-vault。
默认stdin_add_newline为yes,即在标准输入最后添加一个换行符,保持默认即可,不需要特别设置。
3.1.10 strip_empty_ends移除标准输出、标准异常最后的空行
Ansible默认会移除标准输出、标准异常最后的空行的。当指定strip_empty_ends: no时就不会移除最后的空行。
| |
可以看到,当不进行最后的空行移除时,标准输出时"stdout_lines": ["not remove empty endlines", "", "", ""],说明最后的三个空行没有被移除。
需要注意的是,如果结尾行中不是空行,而是由空格或Tab键组成的内容,也不会被移除,这种行不会被当作空行!
3.1.11 Ansible警告warn设置
在ansible配置文件/etc/ansible/ansible.cfg 中可以看到以下内容:
| |
Ansible默认开启命令异常的提示。
我们此时测试一下,在剧本中添加warn参数来查看警告输出。
| |
此时可以看到仅任务check open warning有警告[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo,其他的两个任务check default warn和check close warning都没有警告。
我们改变一下三个任务的顺序,将任务check default warn调到第一个位置,任务check open warning调到第二个位置,再运行剧本:
| |
此时可以看到仅任务check default warn有警告[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo,其他的两个任务check open warning和check close warning都没有警告。
而通过查看更详细的信息:
| |
可以看到实质上,任务check default warn和任务check open warning都是有警告信息的,但只有任务check default warn打印出了警告信息。
我们再来调整一下顺序,把任务check close warning放在第一个位置,任务check open warning放在第二个位置,任务check default warn放在最后的位置。再运行剧本看一下:
| |
此时可以看到,如果通过warn: no关闭了警告则该任务不会了生警告信息。而check open warning任务和check default warn任务都可以看到warnings字段信息,但仅check open warning任务会打印出[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo警告输出.初步判断Ansible只进行一种警告输出。
我们此时修改一下默认的配置修改,设置command_warnings = False即不开启命令异常。
| |
此时可以看到,只有通过warn: yes开启警告功能,Ansible才会发出[WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo警告信息。即仅任务check open warning有警告信息!
通过以上实验对比我们可以发现,保持Ansible默认的warn设置即开启警告信息输出比较好,防止我们在编写命令时使用不正确的命令方式或者模块。因此,建议将command_warnings的设置改成默认的!注释掉command_warnings的设置即可。
| |
此时将commad.yml剧本中任务顺序改一下,将check default warn任务放到check open warning任务前面,再运行剧本:
| |
可以看到默认的警告功能又开启了!
