常见问题/解答(FAQ)

这些是我们从用户那里收到的最常见的问题或常见问题。它们不能代替阅读文档的其余部分,因此如果您的问题没有在这里得到回答,请确保您已经检查过了。

备注

大多数API示例和链接都是针对版本2和更高版本的;针对版本1的常见问题通常会标记为类似的。

警告

回答了许多关于Shell命令执行和任务行为的问题 Invoke's FAQ page -请在那里也检查一下!

远程端未正确设置显式设置的环境变量!

如果您尝试为以下内容设置环境变量 Connection.run appear to silently fail, you're almost certainly talking to an SSH server which is setting a highly restrictive AcceptEnv

要进行修复,您可以修改服务器的配置以允许您正在设置的环境变量,或者使用 inline_ssh_env Connection 参数(或 global config option 同名),强制Fabric发送前缀在命令字符串之前的环境变量。

远程Shell环境与交互式Shell不匹配!

您可能会发现环境变量(或它们触发的行为)与通过Fabric编写脚本的环境变量不同。例如,您的计算机上的某个程序 $PATH 当您手动 ssh 在使用时可能看不到 Connection.run ;或者特殊的每个程序的环境变量,如那些用于Python、pip、Java等的环境变量没有生效;等等。

其根本原因通常是因为SSH服务器通过非常有限的Shell调用运行非交互命令: /path/to/shell -c "command" (例如, OpenSSH )。当以这种方式运行时,大多数Shell都不会被认为是 interactivelogin 这会影响加载哪些启动文件。

用户通常只修改与交互操作相关的Shell文件(例如 ~/.bash_profile/etc/zshrc );当SSH服务器运行一次性命令时,此类更改不会生效。

要解决此问题,请参考您的Shell文档,查看它是否提供了任何非登录、非交互的配置文件;例如, zsh 允许您配置 /etc/zshrc~/.zshenv 为了这个目的。

备注

bash 似乎不提供标准的非登录/非交互启动文件,即使在版本4中也是如此。但是,它可能会尝试确定它是否正在由远程执行守护程序运行,并显然会 ~/.bashrc 如果是,请检查您的目标系统上是否存在这种情况。

备注

另一种解决方法是 bash 用户将在其上回复 $BASH_ENV 功能,该功能将文件路径命名为要加载的启动文件:

  • 将SSH服务器配置为 AcceptEnv BASH_ENV ,这样您实际上可以在顶层设置远程会话的env var(大多数SSH服务器默认不允许使用这种方法)。

  • 决定这应该是哪个文件,但是如果您已经在修改文件,比如 ~/.bash_profile~/.bashrc ,您可能只想指向那条确切的路径。

  • 设置结构配置值 run.env 要瞄准上述道路,例如 {"BASH_ENV": "~/.bash_profile"}

我的 (cd /`` workon`/`` export``/etc)调用似乎不起作用!

虽然fabric可以用于许多类似shell脚本的任务,但有一个稍微不明确的捕获:每个 runsudo 呼叫(或) run/sudo v1)中的函数有自己独特的shell会话。为了让fabric在命令运行后可靠地确定其标准out/error和返回代码是什么,这是必需的。

不幸的是,这意味着像下面这样的代码并不像您想象的那样工作:

@task
def deploy(c):
    c.run("cd /path/to/application")
    c.run("./update.sh")

如果那是一个shell脚本,那么第二个 run 调用的当前工作目录为 /path/to/application/ --但是,由于这两个命令都在各自的不同会话中通过ssh运行,因此它实际上尝试执行 $HOME/update.sh 相反(因为远程主目录是默认的工作目录)。

一个简单的解决方法是使用shell逻辑操作,例如 && ,将多个表达式链接在一起(如果左侧执行时没有错误),如下所示:

def deploy(c):
    c.run("cd /path/to/application && ./update.sh")

备注

您也可以使用绝对路径,跳过目录更改:

def deploy(c):
    c.run("/path/to/application/update.sh")

但是,这要求所讨论的命令对当前工作目录不做任何假设!

为什么我有时会看到 err: stdin: is not a tty 是吗?

Invoke's FAQ 为此,即使对于不基于invoke的结构v1,答案也是一样的。

为什么我不能在后台运行程序 & ?它使 Fabric 挂起。

因为每次调用 runsudo (see also )时,后台进程可能会阻止调用shell退出,直到进程停止运行,这反过来又会阻止结构继续执行自己的执行。

修复此问题的关键是确保进程的标准管道都与调用shell断开,调用shell可以通过多种方式完成(按稳健性顺序列出):

  • 如果手头的程序存在守护程序,请使用预先存在的守护程序技术——例如,调用init脚本而不是直接调用服务器二进制文件。

    • 或利用流程管理器,如 supervisordupstartsystemd -这些工具允许您定义“运行”某个后台进程的含义,然后发出诸如start/stop/restart/status命令之类的init脚本。与经典的init脚本相比,它们也提供了许多优势。

  • 使用 tmuxscreendtach 为了使进程与正在运行的shell完全分离,这些工具的好处是允许您在以后需要时重新附加到进程(尽管它们比 supervisord 像工具一样。

  • 在下运行程序 nohup 或者类似的“在shell中”工具——请注意,对于大多数用户来说,这种方法的成功率是有限的。

有时我被错误地要求输入 passphrase 而不是 password 。

由于在我们的ssh层中有一个类似的错误,目前Fabric不可能总是准确地检测所需的身份验证类型。我们必须尝试猜测我们是被要求使用私钥密码还是远程服务器密码,在某些情况下,我们的猜测是错误的。

最常见的这种情况是,本地用户您似乎有一个ssh keychain代理正在运行,但是远程服务器无法使用您的ssh密钥,例如,您还没有将公钥传输过来,或者使用的用户名不正确。在这种情况下,fabric会提示您“请输入私钥的密码短语”,但您输入的文本实际上正被发送到远程端的密码验证。

我们希望在将来的版本中通过对前面提到的ssh库的贡献来解决这个问题。