Fabric:系统管理员的最佳伙伴
您是否经常一次性更改十几台以上的机器?阅读本文,了解一款可以使该任务变得更加轻松的工具。
老实说,即使这个库已经有五年历史了,大约六个月前我才听说过 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
允许您将文件从远程机器拉取到本地机器。这就像使用rsync
或scp
从多台机器复制一个或多个文件。这对于系统地收集中央位置的日志文件或备份非常有效。远程路径是您要抓取的远程机器上文件的路径,本地路径是您要将文件保存到的本地机器上的路径。如果省略本地路径,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_path
或remote_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
等同于--shortlist
;normal
与完全省略此选项相同(默认值),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
,指定并行执行期间要并发运行的进程数。