Fabric:系统管理员的最佳伙伴

作者:Adrian Hannah

您是否经常一次性更改十几台以上的机器?阅读本文,了解一款可以使该任务变得更加轻松的工具。

老实说,即使这个库已经有五年历史了,大约六个月前我才听说过 Fabric。现在我无法想象我的数字工具箱里没有它。Fabric 是一个 Python 库/工具,旨在通过 SSH 在一台或多台远程机器上执行系统管理和部署任务。无需再逐台机器运行相同的任务,即可在所有机器上进行一次更改。它是一个简单的即用即弃工具,会让您的生活变得更加简单。您不仅可以通过 SSH 在多台机器上运行简单任务,而且由于您使用 Python 代码来执行项目,您可以将其与任何任意 Python 代码结合使用,为部署或管理任务创建强大、复杂、优雅的应用程序。

安装

Fabric 需要 Python 2.5 或更高版本、setuptools 打包/安装库、ssh Python 库以及 SSH 及其依赖项。在大多数情况下,您不必担心这些,因为可以通过各种软件包管理器轻松安装 Fabric。安装 Fabric 最简单、最普遍的方法是使用 pip(或 easy_install)。在大多数系统上,您可以使用系统软件包管理器(apt-get、install 等)来安装它(软件包名称为 fabric 或 python-fabric)。如果您有兴趣,可以查看 git 存储库并深入研究源代码。

安装完成后,您将可以从命令行访问 fab 脚本。

操作

Fabric 库由九个独立的操作组成,这些操作可以结合使用以达到您想要的效果。只需将这些函数插入到您的 fabfile 中即可开始使用

  • get(remote_path, local_path=None)get 允许您将文件从远程机器拉取到本地机器。这就像使用 rsyncscp 从多台机器复制一个或多个文件。这对于系统地收集中央位置的日志文件或备份非常有效。远程路径是您要抓取的远程机器上文件的路径,本地路径是您要将文件保存到的本地机器上的路径。如果省略本地路径,Fabric 会假定您要将文件保存到工作目录。

  • local(command, capture=False) — local 函数允许您在本地主机上执行操作,类似于 Python subprocess 模块(实际上,local 是一个位于 subprocess 模块之上的简化包装器)。只需提供要运行的命令,如果需要,还可以指定是否要捕获输出。如果您指定 capture=True,输出将作为字符串从 local 返回,否则将输出到 STDOUT。

  • open_shell(command=None) — 此函数主要用于调试目的。它在远程端打开一个交互式 shell,允许您运行任意数量的命令。如果您正在运行一系列特别复杂的命令,并且似乎在某些机器上不起作用,这将特别有帮助。

  • prompt(text, key=None, default='', validate=None) — 在您需要提供值,但出于任何原因不想在命令行上指定值的情况下,prompt 是理想的方法。我有一个 fabfile,我用它来添加/删除/检查我维护的所有服务器上的软件状态,当我忘记指定我要处理的软件时,我会在脚本中使用它。此提示将针对您指定的每个主机显示,因此请确保您考虑到这一点!

  • put(local_path, remote_path, use_sudo=False, mirror_local_mode=False, mode=None) — 这是 get 的相反命令,尽管与 get 相比,put 到远程系统时您有更多选项。本地路径可以是相对或绝对文件路径,也可以是实际的文件对象。如果 local_pathremote_path 留空,将使用工作目录。如果指定 use_sudo=True,Fabric 会将文件放在远程机器上的临时位置,然后使用 sudo 将其从临时位置移动到指定位置。当移动系统文件(如 /etc/resolv.conf 或类似文件,标准用户无法移动,并且您已在 SSH 中关闭 root 登录)时,这特别方便。如果您希望通过复制保留文件模式,请使用 mirror_local_mode=True;否则,您可以使用 mode 设置模式。

  • reboot(wait=120)reboot 完全按照其名称所示执行操作:重启远程机器。默认情况下,reboot 将等待 120 秒,然后尝试重新连接到机器以继续执行任何后续命令。

  • require(*keys, **kwargs)require 强制指定的键存在于共享环境字典中,以便继续执行。如果这些键不存在,Fabric 将中止。可选地,您可以指定 used_for 以指示键在此特定上下文中的用途。

  • run(command, shell=True, pty=True, combine_stderr=True, quiet=False, warn_only=False, stdout=None, stderr=None) — 这和 sudo 是 Fabric 中最常用的两个函数,因为它们实际上在远程主机上执行命令(这正是 Fabric 的重点)。使用 run,您可以以给定用户身份执行指定的命令。run 返回命令的输出,作为可以检查 failed、succeeded 和 return_code 属性的字符串。shell 控制是否为命令创建 shell 解释器。如果关闭,命令中的字符将不会自动转义。传递 pty=False 会导致在执行此命令时不会创建伪终端;如果正在运行的命令与伪终端交互存在问题,这可能会有一些好处,但否则,默认情况下会创建伪终端。如果您希望 stderr 与 stdout 分开解析,请使用 combine_stderr=False 来指示。quiet=True 将使命令静默运行,执行时不会向屏幕发送任何输出。当 Fabric 中发生错误时,脚本通常会中止并指示错误。您可以使用 warn_only 参数指示如果特定命令出错,Fabric 不需要中止。最后,您可以重定向远程 stderr 和 stdout 在本地端的重定向位置。例如,如果您希望 stderr 管道传输到本地端的 stdout,您可以使用 stderr=sys.stdout 来指示。

  • sudo(command, shell=True, pty=True, combine_stderr=True, user=None, quiet=False, warn_only=False, stdout=None, stderr=None, group=None)sudo 的工作方式与 run 完全相同,只是它会在执行命令之前提升权限。它的工作方式基本相同,就像您使用 run 运行命令,但在命令前面加上 sudo 一样。sudo 还接受 user 和 group 参数,允许您指定以哪个用户或组身份运行命令。只要原始用户有权为该特定用户/组和命令提升权限,您就可以正常使用。

基础知识

现在您了解了 Fabric 的基础知识,您可以开始使用它了。在本文中,我将解释如何制作一个简单的 fabfile,用于安装/删除软件和您的机器。首先,您需要所谓的 fabfile。fabfile 包含您的所有 Fabric 函数。默认情况下,它需要命名为 fabfile.py 并位于工作目录中,但如前所述,如果需要,您可以从命令行指定 fabfile。因此,打开您的 fabfile 并以 from fabric.api import * 开头,以包含所有 Fabric 功能。然后定义您的所有函数。让我们从安装一些软件开始


def install(pkg=None):
   if pkg is not None:
      env["pkg"] = pkg
   elif pkg is None and env.get("pkg") is None:
      env["pkg"] = prompt("Which package? ")
   sudo('yum install -y %s' % env["pkg"])

然后,您可以通过在所有机器上运行以下命令,通过 yum 安装软件包


$ fab --hosts=host1,host2,host3 install

然后,系统只会提示您输入一次要安装的软件包。或者,由于您指示了 pkg 的可选参数,您可以从命令行指示该参数,这样在执行时就不会提示您,如下所示


$ fab --hosts=host1,host2,host3 install:pkg=wormux


$ fab --hosts=host1,host2,host3 install:wormux

另请注意,系统只会提示您输入一次 SSH 和 sudo 的密码。Fabric 会将密码存储在内存中,并在可能的情况下为每台其他机器重复使用它。恭喜!您刚刚成功创建了您的第一个 Fabric 脚本。就这么简单!

提示和技巧

自从我开始使用 Fabric 以来,我学到了一些巧妙的技巧。首先,您通常永远不会看到像上面那样简单的 Fabric 命令。当完全自动化时,它看起来更像这样


$ fab --skip-bad-hosts -u user -p 12345 -i ~/.ssh/id_dsa --warn-only
 ↪--hosts=host1,host2,host3,host4,host5,host6,host7,host8,host9,host10
 ↪--parallel --pool-size=20 install:pkg=wormux

谁愿意每次想要运行命令时都输入这么多内容?没人!这就是为什么几乎所有内容的别名都如此方便和高效。将以下内容添加到您的 .bashrc 文件中


alias f="fab --skip-bad-hosts -u user -p 12345 -i ~/.ssh/id_dsa
 ↪--warn-only
 ↪--hosts=host1,host2,host3,host4,host5,host6,host7,host8,host9,host10
 ↪--parallel"

然后,您每次想要运行 Fabric 时所要做的就是这样


$ f install:pkg=wormux

即使使用此技术,如果您的常用管理机器超过几台,您的别名也可能变得笨重。一个简单的解决方案是将此函数添加到您的 fabfile 中


def set_hosts():
   env.hosts = open('hosts', 'r').readlines()

然后,将您的所有主机名放在与您的 fabfile 相同的目录中名为 hosts 的文件中,并将您的别名修改为如下所示


alias f="fab --skip-bad-hosts -u user -p 12345 -i ~/.ssh/id_dsa
 ↪--warn-only --parallel set_hosts"

如果您有各种 fabfile 用于不同的机器组或不同的上下文中,这将特别方便。

有时您需要在特定目录中执行某些命令。由于每个命令都是与机器的离散且非持久连接,因此这本身并不简单。但是,只需将必要的命令括在 with 语句中,您就可以得到一个解决方案


with cd("~/gitrepo"):
   run('git add --all')
   run('git commit -m "My super awesome automated 
   ↪commit script for `date`"')
更多信息

有几种方法可以获得 Fabric 的帮助。最有效的方法是使用 fab-file 邮件列表。开发人员通常会非常迅速地回复。还有一个 Fabric Twitter 帐户 @pyfabric,发布 Fabric 新闻和公告。您可以通过 Fabric Github 页面 提交和查看错误。当然,您也不能忽视 Freenode 上的 #fabric 频道,您可以在那里与社区联系并获得一些快速解答。最后,您可以随时浏览托管在 http://www.fabfile.org 的文档。

关于应用程序部署的简要说明

开发团队也使用 Fabric 将新代码部署到生产环境。它实际上以与系统管理员使用它的方式非常相似的方式使用(复制文件,运行一些命令等等),只是方式非常具体。由于 Fabric 的自动化程度很高,因此很容易将其集成到持续集成周期中,甚至可以完全自动化您的部署过程。

命令行参数
  • -a, --no_agent — 将 env.no_agent 设置为 True,强制您的 SSH 层在尝试解锁私钥文件时不与 SSH 代理通信。

  • -A, --forward-agent — 将 env.forward_agent 设置为 True,启用代理转发。

  • --abort-on-prompts — 将 env.abort_on_prompts 设置为 True,强制 Fabric 在需要提示输入时中止。

  • -c RCFILE, --config=RCFILE — 将 env.rcfile 设置为给定的文件路径,Fabric 将尝试在启动时加载该文件路径并用于更新环境变量。

  • -d COMMAND, --display=COMMAND — 打印给定任务的整个文档字符串(如果存在)。它目前不打印任务的函数签名,因此描述性文档字符串是一个好主意。(当然,它们始终是一个好主意,只是在这里更重要。)

  • --connection-attempts=M, -n M — 设置尝试连接的次数。设置 env.connection_attempts

  • -D, --disable-known-hosts — 将 env.disable_known_hosts 设置为 True,阻止 Fabric 加载用户的 SSH known_hosts 文件。

  • -f FABFILE, --fabfile=FABFILE — 要搜索的 fabfile 名称模式(默认为 fabfile.py),或者是要加载为 fabfile 的显式文件路径(例如,/path/to/my/fabfile.py)。

  • -F LIST_FORMAT, --list-format=LIST_FORMAT — 允许控制 --list 的输出格式。short 等同于 --shortlistnormal 与完全省略此选项相同(默认值),nested 打印嵌套的命名空间树。

  • -g HOST, --gateway=HOST — 将 env.gateway 设置为 HOST 主机字符串。

  • -h, --help — 显示包含所有可能选项的标准帮助消息以及对它们作用的简要概述,然后退出。

  • --hide=LEVELS — 默认情况下要隐藏的输出级别逗号分隔列表。

  • -H HOSTS, --hosts=HOSTS — 将 env.hosts 设置为给定的逗号分隔的主机字符串列表。

  • -x HOSTS, --exclude-hosts=HOSTS — 将 env.exclude_hosts 设置为给定的逗号分隔的主机字符串列表,以将其排除在最终主机列表之外。

  • -i KEY_FILENAME — 设置为文件路径时,将加载给定文件作为 SSH 身份文件(通常是私钥)。此选项可以重复多次。设置(或附加到)env.key_filename

  • -I, --initial-password-prompt — 在会话开始时(在 fabfile 加载和选项解析之后,但在执行任何任务之前)强制密码提示,以便预填充 env.password。当通过 --password 设置密码或通过在 fabfile 中设置 env.password 是不可取的情况下,这对于即用即弃运行(尤其是运行时输入不可能的并行会话)非常有用。

  • -k — 将 env.no_keys 设置为 True,强制 SSH 层不要在用户的 home 目录中查找 SSH 私钥文件。

  • --keepalive=KEEPALIVE — 将 env.keepalive 设置为给定的(整数)值,指定 SSH keepalive 间隔。

  • --linewise — 强制输出逐行缓冲而不是逐字节缓冲。通常对于并行执行很有用或必需。

  • -l, --list — 像往常一样导入 fabfile,然后打印所有已发现任务的列表并退出。如果任务有文档字符串,还将打印每个任务的文档字符串的第一行(如有必要,会截断)。

  • -p PASSWORD, --password=PASSWORD — 将 env.password 设置为给定的字符串;然后,它将用作建立 SSH 连接或调用 sudo 程序时的默认密码。

  • -P, --parallel — 将 env.parallel 设置为 True,使任务并行运行。

  • --no-pty — 将 env.always_use_pty 设置为 False,使所有 run/sudo 调用表现得好像已指定 pty=False 一样。

  • -r, --reject-unknown-hosts — 将 env.reject_unknown_hosts 设置为 True,导致 Fabric 在连接到用户 SSH known_hosts 文件中未找到的主机时中止。

  • -R ROLES, --roles=ROLES — 将 env.roles 设置为给定的逗号分隔的角色名称列表。

  • --set KEY=VALUE,... — 允许您为任意 Fabric env vars 设置默认值。以此方式设置的值优先级较低。它们不会覆盖在命令行上同时指定的更具体的 env vars。

  • -s SHELL, --shell=SHELL — 将 env.shell 设置为给定的字符串,覆盖用于执行远程命令的默认 shell 包装器。

  • --shortlist — 类似于 --list,但没有任何修饰—只有任务名称,以换行符分隔,没有缩进或文档字符串。

  • --show=LEVELS — 要添加到默认显示的输出级别中的逗号分隔列表。

  • --ssh-config-path — 设置 env.ssh_config_path

  • --skip-bad-hosts — 设置 env.skip_bad_hosts,使 Fabric 跳过不可用的主机。

  • --timeout=N, -t N — 以秒为单位设置连接超时。设置 env.timeout

  • -u USER, --user=USER — 将 env.user 设置为给定的字符串;然后,它将用作建立 SSH 连接时的默认用户名。

  • -V, --version — 显示 Fabric 的版本号,然后退出。

  • -w, --warn-only — 将 env.warn_only 设置为 True,即使命令遇到错误情况,Fabric 也会继续执行。

  • -z, --pool-size — 设置 env.pool_size,指定并行执行期间要并发运行的进程数。

加载 Disqus 评论