当我通过 ssh 进入远程服务器并运行时,env
我得到了以下路径:
PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/myusername/bin
相反,当我执行 ansible 命令时ansible -a "env"
,我得到以下 PATH:
PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin
可以想象,这在尝试运行 诸如、等sbin
命令时会导致问题,因为它需要输入 sbin 命令的完整路径。 (是的,我知道有 ansible 模块可以做到这一点,但我正在尝试解决为什么 PATH 会缩短/截断。)service
ntpdate
有人知道为什么会发生这种情况吗?
编辑:我之所以询问这个问题是因为我正在遵循书中的例子Ansible for DevOps
,但由于这个原因,有些例子不起作用。
我尝试使用的示例来自书中的第 28 页:
$ ansible multi -s -a "service ntpd stop"
$ ansible multi -s -a "ntpdate -q 0.rhel.pool.ntp.org"
$ ansible multi -s -a "service ntpd start"
这些命令总是会引发错误。但如果我将它们更改为包含完整路径,它们就会起作用。
$ ansible multi -s -a "/sbin/service ntpd stop"
$ ansible multi -s -a "/usr/sbin/ntpdate -q 0.rhel.pool.ntp.org"
$ ansible multi -s -a "/sbin/service ntpd start"
当然,我不想必须输入我发出的每个临时命令的完整路径。(我不知道每个命令的路径。)
有什么方法可以让我的 shell 中的正常路径包含在 ansible 中吗? 是否有一个路径变量可以添加到 inventory 文件或 ansible.cfg 文件中以实现这一点?
答案1
任何时候我使用 ansible,它都会以不同的用户身份运行..在不同的 shell 下。应该能够通过执行以下操作来查看用户:
ansible -a "id"
然后你就可以看到用户 shell 定义在:
cat /etc/passwd
添加路径的最佳做法是添加一行:
/home/<username>/.profile
或者 ~/.bash_profile
答案2
ansible -a
正在使用命令模块并且这不使用 shell 来执行命令。
http://docs.ansible.com/ansible/intro_adhoc.html
通常命令也采用 -m 作为模块名称,但默认模块名称是“命令”。
路径的组成部分,例如/usr/sbin
由 shell 采购文件添加到路径中/etc/profile
,而命令模块不会创建登录shell 所以它不会读取该文件。
http://linux.die.net/man/1/bash
当 bash 作为交互式登录 shell 或使用 --login 选项作为非交互式 shell 调用时,它首先从文件 /etc/profile 中读取并执行命令(如果该文件存在)。读取该文件后,它会按顺序查找 ~/.bash_profile、~/.bash_login 和 ~/.profile,然后从第一个存在且可读的文件中读取并执行命令。启动 shell 时可以使用 --noprofile 选项来禁止此行为。
ansible 文档说,如果你想要一个 shell,可以使用壳模块。但是,似乎没有从 shell 模块启动登录 shell 的选项(通过传递 --login 选项)。
事实上,在很多地方都提到,ansible 策略是不信任环境,并在定义任务时明确设置任何 VARS。
但是,在 ad-hoc 模式下使用 ansible 时可以设置路径。这些是我能做的最接近复制您在交互式/bin/bash
shell 中看到的 PATH 的方法;
$ ansible raspberrypi -m shell \
-a 'PATH=$PATH:/usr/local/sbin:/usr/sbin:$HOME/bin env' \
| grep PATH
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games:/usr/local/sbin:
/usr/sbin:/home/pi/bin
或者您也可以获取该/etc/profile
文件;
$ ansible raspberrypi -m shell \
-a 'executable=/bin/bash source /etc/profile ; env | grep PATH'
PATH=/opt/consul/bin:/usr/local/sbin:/usr/local/bin:
/usr/sbin:/usr/bin:/sbin:/bin
这似乎也有效;
$ ansible raspberrypi -a '/bin/bash -l -c "env"'
PATH=/opt/consul/bin:/usr/local/sbin:/usr/local/bin:
/usr/sbin:/usr/bin:/sbin:/bin
答案3
因此,鉴于您的问题最终是关于使用 ansible 在 sudo 下运行命令,我再次查看了使用时如何设置 PATH ansible -s -a env
。我认为重要的是要注意,-s
在 ansible 中使用 sudo 标志时,$PATH 的设置机制与仅使用时不同ansible -a env
。
当使用sudo command
或用户环境被重置时,$PATH 由中的设置ansible -s
控制,这在Default secure_path
/etc/sudoers
人 sudoers文档;
默认情况下,env_reset 选项处于启用状态。这将导致使用新的最小环境执行命令。新环境包含 TERM、PATH、HOME、MAIL、SHELL、LOGNAME、USER、USERNAME 和 SUDO_* 变量,以及 env_check 和 env_keep 选项允许的调用进程的变量。
如果你没有设置值Default secure_path
,那么这些值将被硬编码到 sshd 二进制文件中,请参阅这个答案了解详情。
然而默认情况下,在 fedora/centros/ubuntu 上,$PATH 的值取自设置的 secure_path /etc/sudoers
;
secure_path-从 sudo 运行的每个命令使用的路径。
例如,在我的 fedora localhost 上,有以下行/etc/sudoers
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
如果我env
通过 ssh 和 sudo 远程运行该命令,我会得到该精确的路径;
$ ssh localhost "sudo env" | grep PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin
我使用 ansible 也得到了同样的结果;
$ ansible localhost -s -a 'env' | grep PATH
PATH=/sbin:/bin:/usr/sbin:/usr/bin
我在 raspbian(debian)实例上尝试了同样的事情,得到了类似的行为;
$ ansible raspberrypi -s -a 'cat /etc/sudoers' | grep secure
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
这就是 ansible 通过选项看到的路径-s -a
;
$ ansible raspberrypi -s -a env | grep PATH
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
因此,对于您最初的问题,我会查看该/etc/sudoers
文件,并检查其值Defaults secure_path="/some/path/here"
。
如果您那里没有包含适当目录的值sbin/
,那么在没有给出完整路径的情况下,ansible 中的以下命令将无法工作;
ansible multi -s -a "service ntpd stop"