IT教程 ·

怎样高效地长途布置?自动化运维利器 Fabric 教程

关于 Python 自动化的话题,在上一篇文章中,我引见了 Invoke 库,它是 Fabric 的最重要组件之一。Fabric 也是一个被广泛运用的自动化东西库,是不得不提的自动化运维利器,所以,本文将来引见一下它。

Fabric 重要用在运用布置与系统治理等使命的自动化,简朴轻量级,供应有雄厚的 SSH 扩大接口。在 Fabric 1.x 版本中,它殽杂了当地及长途两类功用;但自 Fabric 2.x 版本起,它星散出了自力的 Invoke 库,来处置惩罚当地的自动化使命,而 Fabric 则聚焦于长途与收集层面的使命。

为了做到这点,Fabric 重要依靠另一大中心组件 Paramiko,它是基于 SSH 协定的长途掌握模块,Fabric 在其基础上封装出了越发友爱的接口,可以长途实行 Shell 敕令、传输文件、批量操纵效劳器、身份认证、多种设置与设置代办,等等。

一、Fabric 的版本辨别

Python 2 版本已被官宣在本年除夕“退休”了,将来只会是 Python 3 的舞台。为了顺应 Python 版本的非兼容性迁徙,许多项目也必需推出自身的新版本(兼容或只支撑 Python 3),个中就包含本文的主角 Fabric。

Fabric 自身存在着 2 个大版本:Fabric 1 和 Fabric 2,而在这个库的基础上,另有两个很轻易殽杂的相干库:Fabric2 和 Fabric3(注重这里的数字是库名的一部份)。

它们的辨别以下:

  • Fabric 1.x:支撑 Python 2.5-2.7,但不支撑 Python 3
  • Fabric 2.x:支撑 Python 2.7 与 3.4+,但不兼容 Fabric 1.x 的 fabfile
  • Fabric2:等同于 Fabric 2.x,为了使差别版本共存(装一个 1.x 旧版本,再装它作为新版本)
  • Fabric3:一个基于 Fabric 1.x 的 fork(非官方),兼容 Python 2&3,兼容 Fabric1.x 的 fabfile

综上可见,我们引荐运用官方的 Fabric 2.x 系列版本,但同时要注重,某些过期的教程多是基于初期版本的(或非官方的 Fabric3,也是基于 Fabric 1.x),须要注重辨认。

比方,在 Fabric 1.x 系列中这么写导入:from fabric.api import run;在新版本中将报错:“ImportError: No module named api”(PS:可依据是不是有 fabric.api 来推断 Fabric 的版本,就像在 Python 中依据 print 语句或 print 函数来推断版本一样)。同时,由于新版本不支撑老版本的 fabfile,在运用时就可能报错:“No idea what 'xxx' is!”

Fabric 2 黑白兼容性版本,比拟于前个版本,它重要革新的点有:

  • 支撑 Python 2.7 与 3.4+
  • 线程平安,取消了多历程的并发完成
  • API 缭绕 fabric.connection.Connection 举行了重组
  • 周全修改了敕令行剖析器,许可在每一个使命的基础上运用划定规矩的 GNU/POSIX 作风的标志和选项(不再须要 fab mytask:weird = custom,arg = format)
  • 可以声明前置使命与后置使命
  • ……(官方列了10几条 [1],本文不一一排列)

之前引见过的 invoke,就是在开发 Fabric 2 时被星散出来的,细致的缘由可拜见这个回覆 [2]。总而言之,在运用 Fabric 时,应当注重版本差别的问题。

二、Fabric 的基础用法

1、装置

首先是装置:pip intall fabric ,装置后,可在敕令行窗口检察版本信息:

>>> fab -V
Fabric 2.5.0
Paramiko 2.7.1
Invoke 1.4.0

实行“fab -V”,以上效果可看出我装置的是 Fabric 2.5.0 版本,同时可看到它的两个中心依靠库 Paramiko 及 Invoke 的版本信息。

2、一个简朴的例子

Fabric 重要用于长途使命,即要对长途效劳器举行操纵,下面是一个简朴的例子:

# 可运用恣意的文件名
from fabric import Connection

host_ip = '47.xx.xx.xx'  # 效劳器地点
user_name = 'root' # 效劳器用户名
password = '****'  # 效劳器暗码
cmd = 'date'  # shell 敕令,查询效劳器上的时刻

con = Connection(host_ip, user_name, connect_kwargs={'password': password})
result = con.run(cmd, hide=True)

print(result)

以上代码,经由过程账号+暗码登录到长途效劳器,然后实行date敕令,检察效劳器的时刻,实行效果:

Command exited with status 0.
=== stdout ===
Fri Feb 14 15:33:05 CST 2020

(no stderr)

如今打印的效果中,除了效劳器时刻,另有一些无关的信息。这是由于它打印的“result”是一个"fabric.runners.Result"类,我们可以把个中的信息剖析出来:

print(result.stdout)  # Fri Feb 14 15:33:05 CST 2020
print(result.exited)  # 0
print(result.ok)      # True
print(result.failed)  # False
print(result.command) # date
print(result.connection.host) # 47.xx.xx.xx

上述代码运用了 Connection 类及其 run() 要领,可在衔接的效劳器上运转 shell 敕令。假如须要用治理员权限,则需替换成 sudo() 要领。假如要在当地实行 shell 敕令,则需替换成 local() 要领。

除此以外,另有 get()、put() 等要领,详见下文引见。

3、敕令行用法

上例代码可写在恣意的 .py 剧本中,然后运转该剧本,或许轻微封装下再导入到别的剧本中运用。

别的,Fabric 照样个敕令行东西,可以经由过程fab敕令来实行使命。我们轻微革新一下上例的代码:

# 文件名:fabfile.py
from fabric import Connection
from fabric import task

host_ip = '47.xx.xx.xx'  # 效劳器地点
user_name = 'root' # 效劳器用户名
password = '****'  # 效劳器暗码
cmd = 'date'  # shell 敕令,查询效劳器上的时刻

@task
def test(c):
    """
    Get date from remote host.
    """
    con = Connection(host_ip, user_name, connect_kwargs={'password': password})
    result = con.run(cmd, hide=True)
    print(result.stdout)  # 只打印时刻

诠释一下,重要的修改点有:

  • fabfile.py 文件名:进口代码的剧本名必需用这个名字
  • @task 装潢器:须要从 fabric 中引入这个装潢器,它是对 invoke 的 @task 装潢器的封装,现实用法跟 invoke 一样(注重:它也须要有上下文参数“c”,但现实上它并没有在代码块中运用,而是用了 Connection 类的实例)

然后,在该剧本同级目次的敕令行窗口中,可以检察和实行响应的使命:

>>> fab -l
Available tasks:
  test   Get date from remote host.

>>> fab test
Fri Feb 14 16:10:24 CST 2020

fab 是 Invoke 的扩大完成,继承了许多原有功用,所以实行“fab --help”,与之前引见的“inv --help”比拟,你会发明它们的许多参数与诠释都是如出一辙的。

怎样高效地长途布置?自动化运维利器 Fabric 教程 IT教程 第1张

fab 针对长途效劳的场景,增加了几个敕令行选项(已标蓝),个中:

  • --prompt-for-login-password:令程序在敕令行中输入 SSH 登录暗码(上例在代码中指定了 connect_kwargs.password 参数,若用此选项,可请求在实行时再手工输入暗码)
  • --prompt-for-passphrase:令程序在敕令行中输入 SSH 私钥加密文件的途径
  • -H 或 --hosts:指定要衔接的 host 名
  • -i 或 --identity:指定 SSH 衔接所用的私钥文件
  • -S 或 --ssh-config:指定运转时要加载的 SSH 设置文件

关于 Fabric 的敕令行接口,更多内容可检察文档 [3]。

4、交互式操纵

长途效劳器上如有交互式提醒,请求输入暗码或“yes”之类的信息,这就请求 Fabric 可以监听并作出回应。

以下是一个简朴示例。引入 invoke 的 Responder,初始化内容是一个正则字符串和回应信息,末了赋值给 watchers 参数:

from invoke import Responder
from fabric import Connection
c = Connection('host')
sudopass = Responder(
     pattern=r'[sudo] password:',
     response='mypasswordn')
c.run('sudo whoami', pty=True, watchers=[sudopass])

5、传输文件

当地与效劳器间的文件传输是罕见用法。Fabric 在这方面做了很好的封装,Connection 类中有以下两个要领可用:

  • get(*args, **kwargs):拉取远端文件到当地文件系统或类文件(file-like)对象
  • put(*args, **kwargs):推送当地文件或类文件对象到远端文件系统

在已竖立衔接的情况下,示例:

# (略)
con.get('/opt/123.txt', '123.txt')
con.put('test.txt', '/opt/test.txt')

第一个参数指的是要传输的源文件,第二个参数是要传输的目的地,可以指定成文件名或许文件夹(为空或 None 时,运用默许途径):

# (略)
con.get('/opt/123.txt', '')  # 为空时,运用默许途径
con.put('test.txt', '/opt/') # 指定途径 /opt/

get() 要领的默许存储途径是os.getcwd ,而 put() 要领的默许存储途径是 home 目次。

6、效劳器批量操纵

关于效劳器集群的批量操纵,最简朴的完成要领是用 for 轮回,然后一一竖立 connection 和实行操纵,相似如许:

for host in ('web1', 'web2', 'mac1'):
    result = Connection(host).run('uname -s')

但有时刻,如许的计划会存在问题:

  • 假如存在多组差别的效劳器集群,须要实行差别操纵,那末须要写许多 for 轮回
  • 假如想把每组操纵的效果聚合起来(比方字典情势,key-主机,value-效果),还得在 for 轮回以外增加分外的操纵
  • for 轮回是序次同步实行的,效力太低,而且缺少非常处置惩罚机制(若中心出现非常,会致使跳出后续操纵)

关于这些问题,Fabric 提出了 Group 的观点,可将一组主机定义成一个 Group,它的 API 要领跟 Connection 一样,即一个 Group 可简化地视为一个 Connection。

然后,开发者只须要简朴地操纵这个 Group,末了获得一个效果集即可,减少了自身在非常处置惩罚及实行序次上的事情。

Fabric 供应了一个 fabric.group.Group 基类,并由其派生出两个子类,区别是:

  • SerialGroup(*hosts, **kwargs):按串行体式格局实行操纵
  • ThreadingGroup(*hosts, **kwargs):按并发体式格局实行操纵

Group 的范例决议了主机集群的操纵体式格局,我们只须要做出挑选即可。然后,它们的实行效果是一个fabric.group.GroupResult类,它是 dict 的子类,存储了每一个主机 connection 及其实行效果的对应关联。

>>> from fabric import SerialGroup
>>> results = SerialGroup('web1', 'web2', 'mac1').run('uname -s')
>>> print(results)
<GroupResult: {
    <Connection 'web1'>: <CommandResult 'uname -s'>,
    <Connection 'web2'>: <CommandResult 'uname -s'>,
    <Connection 'mac1'>: <CommandResult 'uname -s'>,
}>

别的,GroupResult 还供应了 failed 与 succeeded 两个属性,可以掏出失利/胜利的子集。由此,也可以轻易地批量举行二次操纵。 原文

三、Fabric 的进阶用法

1、身份认证

Fabric 运用 SSH 协定来竖立长途会话,它是一种相对平安的基于运用层的加密传输协定。

基础来讲,它有两种级别的平安认证体式格局:

  • 基于口令的身份认证:运用账号与暗码来登录长途主机,平安性较低,轻易遭到“中心人”进击
  • 基于密钥的身份认证:运用密钥对体式格局(公钥放效劳端,私钥放客户端),不会遭到“中心人”进击,但登录耗时较长

前文在举例时,我们用了第一种体式格局,即经由过程指定 connect_kwargs.password 参数,运用口令来登录。

Fabric 固然也支撑采纳第二种体式格局,有三种要领来指定私钥文件的途径,优先级以下:

  • 优先查找 connect_kwargs.key_filename 参数,找到则用作私钥
  • 其次查找敕令行用法的 --identify 选项
  • 末了默许运用操纵系统的 ssh_config 文件中的IdentityFile 的值

假如私钥文件自身还被加密过,则须要运用 connect_kwargs.passphrase 参数。

2、设置文件

Fabric 支撑把一些参数项与营业代码星散,即经由过程设置文件来治理它们,比方前面提到的暗码和私钥文件,可写在设置文件中,避免与代码耦合。

Fabric 基础沿用了 Invoke 的设置文件系统(官方文档中列出了 9 层),同时增加了一些跟 SSH 相干的设置项。支撑的文件花样有 .yaml、.yml、.json 与 .py(按此序次排优先级),引荐运用 yaml 花样(后缀可简写成 yml)。

个中,比较经常使用的设置文件有:

  • 系统级的设置文件:/etc/fabric.yml
  • 用户级的设置文件:~/.fabric.yml(Windows 在 C:Usersxxx 下)
  • 项目级的设置文件:/myproject/fabric.yml

以上文件的优先级递减,由于我本机是 Windows,为了轻易,我在用户目次建一个".fabric.yml"文件,内容以下:

# filename:.fabric.yml

user: root
connect_kwargs:
  password: xxxx
# 若用密钥,则以下
#  key_filename:
#    - your_key_file

我们把用户名和暗码抽离出来了,所以 fabfile 中就可以删掉这些内容:

# 文件名:fabfile.py
from fabric import Connection
from fabric import task

host_ip = '47.xx.xx.xx'  # 效劳器地点
cmd = 'date'  # shell 敕令,查询效劳器上的时刻

@task
def test(c):
    """
    Get date from remote host.
    """
    con = Connection(host_ip)
    result = con.run(cmd, hide=True)
    print(result.stdout) 

然后,在敕令行中实行:

>>> fab test
Tue Feb 18 10:33:38 CST 2020

设置文件中还可以设置许多参数,细致可检察文档 [4]。

3、收集网关

假如长途效劳是收集断绝的,没法直接被访问到(处在差别局域网),这时刻须要有网关/代办/隧道,这个中心层的机械一般被称为跳板机或碉堡机。

Fabric 中有两种网关解决计划,对应到 OpenSSH 客户端的两种选项:

  • ProxyJump:简朴,开支少,可嵌套
  • ProxyCommand:开支大,不可嵌套,更天真

在建立 Fabric 的 Connection 对象时,可经由过程指定 gateway 参数来运用这两种计划:

怎样高效地长途布置?自动化运维利器 Fabric 教程 IT教程 第2张

ProxyJump 体式格局就是在一个 Connection 中嵌套一个 Connection 作为前者的网关,后者运用 SSH 协定的direct-tcpip 为前者翻开与现实长途主机的衔接,而且后者还可以继承嵌套运用自身的网关。

from fabric import Connection

c = Connection('internalhost', gateway=Connection('gatewayhost'))

ProxyCommand 体式格局是客户端在当地用 ssh 敕令(相似“ssh -W %h:%p gatewayhost”),建立一个子历程,该子历程与效劳端举行通讯,同时它能读取规范输入和输出。

这部份的完成细节分别在paramiko.channel.Channelparamiko.proxy.ProxyCommand,除了在参数中指定,也可以在 Fabric 支撑的设置文件中定义。更多细节,请查阅文档 [5]。

四、小结

Fabric 的非兼容版本造成了肯定水平的社辨别裂,这无疑跟 Python 3 的履行脱不开关联,然则我们有理由置信,新版本优胜于老版本。

网上关于 Fabric 的文章,许多已过期了。本文针对最新的官方文档,梳理出了较为周全的知识点,可以带人人很好地入门 Fabric。

读完本文,置信读者们只须要几分钟就可以轻松上手运用。如如有所疑问,迎接经由过程以下体式格局联络我。

 

参与评论