如何高效地远程部署?自动化运维利器Fabric教程

来源:51CTO  责任编辑:小易  

感谢邀请。上海大众途观共提供都会版、风尚、菁英、旗舰版4个版本7款车型。分别搭载大众主打的1.8TSI及2.0TSI引擎,无论动力性能还是经济性都有着出色的表现,与之匹配的6速手动变速箱及爱信6速手自一体变速箱,可以将动力更好地发挥,在享受到澎湃的动力同时,排放也更加环保。与原型车大众Tiguan相比,途观车长增加了68mm,轴距也达到了2684mm,在同级车中处于中上水平,目的是满足国人的使用需求。途观的行李箱可以在400L与1530L之间自由变换,大大提高了实用性,这也是作为一款SUV车型不得不关注的一点。提及德系车,大多数人都会想到安全。安全已成为德系车的代名词。大众途观全系标配ESP车

【金融特辑】光大银行科技部DBA女神带你从0到1揭秘MGR-->

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

OPPOR9s从2016年10月底开售至今,两个月的出货量笑傲国产手机市场,在2500元档位市场的表现无人能及。相信每个R9s的用户都已经知道它的拍照实力,但还有很多隐藏小功能,平常大家都用过吗?  更全面的联系人设计  以微信为首的即时社交应用已经深入每个人的生活,手机中的一项基本功能——通讯录的意义似乎变得越来越弱。表面上看起来确实如此,但实际上通讯录和微信的存在并不冲突。因为微信终究是网络应用的一种,每个人在不停的变换昵称/头像的同时也在变换“身份”,而能够进入你通讯录的联系人才是更真实的“朋友圈”。那么现在问题来了,你有多久没有关心过你“真实的朋友圈”了?  OPPOR9s的联系人可以

Fabric 主要用在应用部署与系统管理等任务的自动化,简单轻量级,提供有丰富的 SSH 扩展接口。在 Fabric 1.x 版本中,它混杂了本地及远程两类功能;但自 Fabric 2.x 版本起,它分离出了独立的 Invoke 库,来处理本地的自动化任务,而 Fabric 则聚焦于远程与网络层面的任务。

牛仔裤怎么穿搭显得时髦?牛仔裤的单品有很多,所以你要首先弄清楚,你的牛仔裤是什么类型的。牛仔裤的种类,现在比较火爆的,一般是破洞牛仔裤,直筒牛仔裤,喇叭牛仔裤,铅笔牛仔裤,当然还有今夏比较受欢迎的牛仔短裤。小编一一为你列出,不同的牛仔裤的正确穿搭的时髦方式破洞牛仔裤白色T恤+破洞牛仔裤+休闲运动鞋破洞牛仔裤+高跟鞋牛仔裤搭配红色高跟鞋,效果也是不错的。T恤+破洞牛仔裤+休闲鞋皮衣外套+破洞牛仔裤小西服上衣+破洞牛仔裤这是黑色侧西服。这是白色的小西服。直筒牛仔裤直筒牛仔裤牛仔上衣+小直筒牛仔裤T恤+背带小直筒牛仔裤西服大衣+小直筒牛仔裤+高跟鞋长开衫+T恤+小直筒牛仔字母T恤+大直筒牛仔裤白背心

为了做到这点,Fabric 主要依赖另一大核心组件 Paramiko,它是基于 SSH 协议的远程控制模块,Fabric 在其基础上封装出了更加友好的接口,可以远程执行 Shell 命令、传输文件、批量操作服务器、身份认证、多种配置与设置代理,等等。

一、Fabric 的版本区分

口臭的人嘴巴中都有一种“产臭菌”——幽门螺旋杆菌,它是口臭的罪魁祸首。教你3招可以有效清除“产臭菌”最后一步是关键,要看好第一步:讲卫生,刷走细菌刷牙、牙线清洁、刷舌苔等日常清洁,都可以清除产臭菌。研究发现,刷牙多于2次/天的人,其口臭患病率远低于刷牙少于这个频率的人。而适当刷舌苔,则可降低嘴里口臭气体浓度的35%~56%。第二步:“饿死”细菌饭后记得赶快漱口,或者嚼无糖口香糖,口腔里的食物残渣少了,产臭菌没了“口粮”,就无法繁衍。第三步:“毒死”细菌我们很多人家里都有火麻油,火麻油和原生蜂蜜搭配吃可以有效杀死幽门螺旋杆菌。做法:取火麻油、蜂蜜各一小勺温水50ml倒入搅匀即可,每天2-3次。科

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”相比,你会发现它们的很多参数与解释都是一模一样的。

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='mypassword\n'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:\Users\xxx 下) 项目级的配置文件:/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 参数来应用这两种方案:

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.Channel 和 paramiko.proxy.ProxyCommand,除了在参数中指定,也可以在 Fabric 支持的配置文件中定义。更多细节,请查阅文档 [5]。

四、小结

Fabric 的非兼容版本造成了一定程度的社区分裂,这无疑跟 Python 3 的推行脱不开关系,但是我们有理由相信,新版本优胜于老版本。

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

扩展阅读,根据您访问的内容系统为您准备了以下内容,希望对您有帮助。

如何用Fabric实现无密码输入提示的远程自动部署

上篇笔记介绍了Fabric的概念、支持的元操作及task的定义方法,本篇笔记旨在说明如何在多台目标机器上正确地执行tasks以实现远程自动部署或运维。特别地,文中会说明如何配置fabric task以便远程执行命令时不会弹出密码输入提示。

1. Fabric的任务运行规则

根据Fabric Execution model的说明,fabric默认以串行方式运行tasks,具体而言:

1)在fabfile及其import文件中定义的task对象依次被创建(只是创建对象,并未真正执行),任务之间保持其定义的先后顺序。

2)对于每个task,生成将要运行该task的目标机器列表。

3)fab执行tasks时,按任务被指定的顺序依次执行这些任务;针对每个任务,依次在其指定的目标机器运行且只运行一次。

4)未指定目标机器的task被当作本地任务运行,且只会被运行一次。

假设在fabfile.py中定义了如下tasks:

from fabric.api import run, envenv.hosts = ['host1', 'host2']def taskA(): run('ls')def taskB(): run('whoami')

在终端运行fab –list时,我们会看到taskA和taskB两个任务,运行之:

$ fab taskA taskB

结果示例如下:

taskA executed on host1taskA executed on host2taskB executed on host1taskB executed on host2

通过上面的实例,大家应该可以明白fabric默认的串行执行策略是怎么回事。

Fabric还允许我们指定以并行方式(借助multiprocessing模块实现多个进程并行执行)在多台机器上并行地运行任务,甚至还可在同一个fabfile文件中指定某些task以并行方式运行,而某些task以默认的串行方式运行。具体地,可以借助@parallel或@serial指定任务的运行模式,还可以在命令行中通过-P参数指定任务是否要并性执行。示例如下:

from fabric.api import *@paralleldef runs_in_parallel(): passdef runs_serially(): pass

当运行如下命令时:

$ fab -H host1,host2,host3 runs_in_parallel runs_serially

执行结果示例如下:

runs_in_parallel on host1, host2, and host3runs_serially on host1runs_serially on host2runs_serially on host3

此外,还可以通过对@parallel传入pool_size参数来控制并行进程数以防并行进程太多把机器拖垮。

2. 为task指定目标机器

有多种方式可以指定任务的将要运行的目标机器,下面分别进行说明。

1)通过env.hosts或env.roles进行全局指定

Fabric的env模块中定义了一系列全局变量,可以将其理解为可以控制fabric行为的环境变量。其中env.hosts和env.roles可以用来全局指定task的目标机器列表,这两个“环境变量”的默认值都是空列表[]。

env.hosts的元素是fabric约定的”host strings”,每个host strings由username@hostname:port三部分构成,其中username和port部分可以缺省。本篇笔记前面的第1个代码实例其实已经说明了如何用env.hosts全局地指定task的目标机器列表,这里不再赘述。

env.roles则是在配置了env.roledefs的情况下才有用武之地。在很多时候,不同的机器有着不同的角色,如有些是接入层,有些是业务层,有些是数据存储层。env.roledefs可以用来组织这些机器列表以体现其角色,示例如下:

from fabric.api import envenv.roledefs = { 'web': { 'hosts': ['www1', 'www2', 'www3'], }, 'db': { 'hosts': ['db1', 'db2'], }}@roles('web')def mytask(): run('ls /var/www')

上例通过env.roledefs配置了两个角色web和db,分别包含3台、2台机器,并借助@roles为mytask指定了目标机器列表。

2)通过命令行进行全局指定

$ fab -H host1,host2 mytask

需要注意的是,命令行通过-H参数指定的机器列表在fabfile脚本load前被解释,故如果fabfile中重新配置了env.hosts或env.roles,则命令行指定的机器列表会被覆盖。为了避免fabfile覆盖命令行参数,在fabfile中应该借助list.extend()指定env.hosts或env.roles,示例如下:

from fabric.api import env, runenv.hosts.extend(['host3', 'host4'])def mytask(): run('ls /var/www')

此时,当我们运行”fab -H host1,host2 mytask”时,env.hosts包含来自命令行和fabfile的4台机器。

3)通过命令行为每个任务指定机器列表

$ fab mytask:hosts="host1;host2"

上述方式会覆盖全局指定的机器列表,确保mytask只会在host1, host2上执行。

4)借助装饰器@hosts为每个任务指定目标机器

from fabric.api import hosts, run@hosts('host1', 'host2')def mytask(): run('ls /var/www')

或者:

my_hosts = ('host1', 'host2')@hosts(my_hosts)def mytask(): # ...

每个任务的@hosts装饰器指定的机器列表会覆盖全局目标机器列表,但不会覆盖通过命令行为该任务单独指定的目标机器列表。

上述4种为task指定目标机器列表的方式之间的优先级规则总结如下:

1) Per-task, command-line host lists (fab mytask:host=host1) override absolutely everything else.

2) Per-task, decorator-specified host lists (@hosts(‘host1’)) override the env variables.

3) Globally specified host lists set in the fabfile (env.hosts = [‘host1’]) can override such lists set on the command-line, but only if you’re not careful (or want them to.)

4) Globally specified host lists set on the command-line (–hosts=host1) will initialize the env variables, but that’s it.

截止目前,我们可以看到,fabric允许我们混合使用上面列出的几种目标机器指定方式,但是我们要明白混合的结果是否符合预期。

此外,fabric默认会对通过不同来源出现多次的同一个目标机器做去重,当然,可以通过设置env.dedupe_hosts为False来关闭默认的去重策略。甚至还可以指定任务需要跳过的机器列表。具体细节可以参考Fabric Execution model的说明,这里不赘述。

3. 任务执行时,目标机器的密码管理

如果你亲自运行上面的示例代码,就会发现,每次在目标机器远程执行task时,fabric均会要求输入目标机器的登录名及密码。如果要在多台机器上执行task,那这些密码输入的过程可以自动化吗?

答案是肯定的。实现方式有两种,下面分别进行说明。

1)通过env.password或env.passwords配置目标机器的登录信息

下面的示例说明了如何通过env.passwords配置多台机器的登录信息:

#!/bin/env python#-*- encoding: utf-8 -*-from fabric.api import run, env, hosts## 需要注意的是,这里的host strings必须由username@host:port三部分构成,缺一不可,否则运行时还是会要求输入密码env.passwords = { 'slvher@10.123.11.209:22': 'xxx', 'work@10.123.11.210:23': 'yyy',}@hosts('10.123.11.209', '10.123.11.210')def host_os_type(): run('uname -a')

由于通过env.passwords配置了目标机器的登录用户名/密码,所以,当我们在终端运行fab host_os_type时,会发现不用手动输入密码了,大大方便了脚本远程自动执行。

但是,这种明文指定登录名/密码的方式存在安全性问题,所以,fabric还支持以ssh key认证的方式免密在远程机器执行任务。

在具体实现上,需要事先在目标机器上生成ssh public key并配置在~/.ssh/config文件中,然后在定义任务的fabfile中将env.use_ssh_config设置为True来启用基于ssh public key方式的身份认证,以便实现免密码远程执行任务。

具体细节可以参考Fabric Leveraging native SSH config files文档的说明,或者参考StackOverflow的这篇帖子Connecting to a host listed in ~/.ssh/config when using Fabric,限于篇幅,这里不再赘述。

最后,推荐DigitalOcean上一篇Fabric教程How To Use Fabric To Automate Administration Tasks And Deployments,浅显易懂,值得一读。Enjoy it

关于fabric 并行执行任务求助

上篇笔记介绍了Fabric的概念、支持的元操作及task的定义方法,本篇笔记旨在说明如何在多台目标机器上正确地执行tasks以实现远程自动部署或运维。特别地,文中会说明如何配置fabric task以便远程执行命令时不会弹出密码输入提示。

1. Fabric的任务运行规则

根据Fabric Execution model的说明,fabric默认以串行方式运行tasks,具体而言:

1)在fabfile及其import文件中定义的task对象依次被创建(只是创建对象,并未真正执行),任务之间保持其定义的先后顺序。

2)对于每个task,生成将要运行该task的目标机器列表。

3)fab执行tasks时,按任务被指定的顺序依次执行这些任务;针对每个任务,依次在其指定的目标机器运行且只运行一次。

4)未指定目标机器的task被当作本地任务运行,且只会被运行一次。

假设在fabfile.py中定义了如下tasks:

from fabric.api import run, envenv.hosts = ['host1', 'host2']def taskA(): run('ls')def taskB(): run('whoami')

在终端运行fab –list时,我们会看到taskA和taskB两个任务,运行之:

$ fab taskA taskB

结果示例如下:

taskA executed on host1taskA executed on host2taskB executed on host1taskB executed on host2

通过上面的实例,大家应该可以明白fabric默认的串行执行策略是怎么回事。

Fabric还允许我们指定以并行方式(借助multiprocessing模块实现多个进程并行执行)在多台机器上并行地运行任务,甚至还可在同一个fabfile文件中指定某些task以并行方式运行,而某些task以默认的串行方式运行。具体地,可以借助@parallel或@serial指定任务的运行模式,还可以在命令行中通过-P参数指定任务是否要并性执行。示例如下:

from fabric.api import *@paralleldef runs_in_parallel(): passdef runs_serially(): pass

当运行如下命令时:

$ fab -H host1,host2,host3 runs_in_parallel runs_serially

执行结果示例如下:

runs_in_parallel on host1, host2, and host3runs_serially on host1runs_serially on host2runs_serially on host3

此外,还可以通过对@parallel传入pool_size参数来控制并行进程数以防并行进程太多把机器拖垮。

2. 为task指定目标机器

有多种方式可以指定任务的将要运行的目标机器,下面分别进行说明。

1)通过env.hosts或env.roles进行全局指定

Fabric的env模块中定义了一系列全局变量,可以将其理解为可以控制fabric行为的环境变量。其中env.hosts和env.roles可以用来全局指定task的目标机器列表,这两个“环境变量”的默认值都是空列表[]。

env.hosts的元素是fabric约定的”host strings”,每个host strings由username@hostname:port三部分构成,其中username和port部分可以缺省。本篇笔记前面的第1个代码实例其实已经说明了如何用env.hosts全局地指定task的目标机器列表,这里不再赘述。

env.roles则是在配置了env.roledefs的情况下才有用武之地。在很多时候,不同的机器有着不同的角色,如有些是接入层,有些是业务层,有些是数据存储层。env.roledefs可以用来组织这些机器列表以体现其角色,示例如下:

from fabric.api import envenv.roledefs = { 'web': { 'hosts': ['www1', 'www2', 'www3'], }, 'db': { 'hosts': ['db1', 'db2'], }}@roles('web')def mytask(): run('ls /var/www')

上例通过env.roledefs配置了两个角色web和db,分别包含3台、2台机器,并借助@roles为mytask指定了目标机器列表。

2)通过命令行进行全局指定

$ fab -H host1,host2 mytask

需要注意的是,命令行通过-H参数指定的机器列表在fabfile脚本load前被解释,故如果fabfile中重新配置了env.hosts或env.roles,则命令行指定的机器列表会被覆盖。为了避免fabfile覆盖命令行参数,在fabfile中应该借助list.extend()指定env.hosts或env.roles,示例如下:

from fabric.api import env, runenv.hosts.extend(['host3', 'host4'])def mytask(): run('ls /var/www')

此时,当我们运行”fab -H host1,host2 mytask”时,env.hosts包含来自命令行和fabfile的4台机器。

3)通过命令行为每个任务指定机器列表

$ fab mytask:hosts="host1;host2"

上述方式会覆盖全局指定的机器列表,确保mytask只会在host1, host2上执行。

4)借助装饰器@hosts为每个任务指定目标机器

from fabric.api import hosts, run@hosts('host1', 'host2')def mytask(): run('ls /var/www')

或者:

my_hosts = ('host1', 'host2')@hosts(my_hosts)def mytask(): # ...

每个任务的@hosts装饰器指定的机器列表会覆盖全局目标机器列表,但不会覆盖通过命令行为该任务单独指定的目标机器列表。

上述4种为task指定目标机器列表的方式之间的优先级规则总结如下:

1) Per-task, command-line host lists (fab mytask:host=host1) override absolutely everything else.

2) Per-task, decorator-specified host lists (@hosts(‘host1’)) override the env variables.

3) Globally specified host lists set in the fabfile (env.hosts = [‘host1’]) can override such lists set on the command-line, but only if you’re not careful (or want them to.)

4) Globally specified host lists set on the command-line (–hosts=host1) will initialize the env variables, but that’s it.

截止目前,我们可以看到,fabric允许我们混合使用上面列出的几种目标机器指定方式,但是我们要明白混合的结果是否符合预期。

此外,fabric默认会对通过不同来源出现多次的同一个目标机器做去重,当然,可以通过设置env.dedupe_hosts为False来关闭默认的去重策略。甚至还可以指定任务需要跳过的机器列表。具体细节可以参考Fabric Execution model的说明,这里不赘述。

3. 任务执行时,目标机器的密码管理

如果你亲自运行上面的示例代码,就会发现,每次在目标机器远程执行task时,fabric均会要求输入目标机器的登录名及密码。如果要在多台机器上执行task,那这些密码输入的过程可以自动化吗?

答案是肯定的。实现方式有两种,下面分别进行说明。

1)通过env.password或env.passwords配置目标机器的登录信息

下面的示例说明了如何通过env.passwords配置多台机器的登录信息:

#!/bin/env python#-*- encoding: utf-8 -*-from fabric.api import run, env, hosts## 需要注意的是,这里的host strings必须由username@host:port三部分构成,缺一不可,否则运行时还是会要求输入密码env.passwords = { 'slvher@10.123.11.209:22': 'xxx', 'work@10.123.11.210:23': 'yyy',}@hosts('10.123.11.209', '10.123.11.210')def host_os_type(): run('uname -a')

由于通过env.passwords配置了目标机器的登录用户名/密码,所以,当我们在终端运行fab host_os_type时,会发现不用手动输入密码了,大大方便了脚本远程自动执行。

但是,这种明文指定登录名/密码的方式存在安全性问题,所以,fabric还支持以ssh key认证的方式免密在远程机器执行任务。

在具体实现上,需要事先在目标机器上生成ssh public key并配置在~/.ssh/config文件中,然后在定义任务的fabfile中将env.use_ssh_config设置为True来启用基于ssh public key方式的身份认证,以便实现免密码远程执行任务。

具体细节可以参考Fabric Leveraging native SSH config files文档的说明,或者参考StackOverflow的这篇帖子Connecting to a host listed in ~/.ssh/config when using Fabric,限于篇幅,这里不再赘述。

最后,推荐DigitalOcean上一篇Fabric教程How To Use Fabric To Automate Administration Tasks And Deployments,浅显易懂,值得一读。Enjoy it

  • 本文相关:
  • 【金融特辑】光大银行科技部DBA女神带你从0到1揭秘MGR
  • 学了这么久,你知道Python是如何运作的吗?
  • 为什么Python在数据科学领域比R更受欢迎呢?
  • 疫情之下,这是你也能上手的Python新冠病毒传播建模教程(附代码)
  • 这些好用却最不被看好的Python库,你知道多少?
  • Python和Go都很火,我要怎么选?
  • IT行业薪水:系统和数据架构师、云工程师薪资最高;增长最快技术K8s
  • 2020年3月编程语言排行榜:Go飞速大涨;Delphi走向没落
  • 浓缩精华的架构演进过程,我连看了六遍!
  • 中国博士开发可交互全球疫情地图,登上柳叶刀,GitHub已有4500星
  • 如何成为一个值得追随的技术管理者
  • 未来即将“触脸可及”,人脸识别技术大揭秘!
  • 关于智能运维的探索与实践
  • 你所不了解的移动支付背后的技术支撑
  • 如何用Fabric实现无密码输入提示的远程自动部署
  • 关于fabric 并行执行任务求助
  • 免责声明 - 关于我们 - 联系我们 - 广告联系 - 友情链接 - 帮助中心 - 频道导航
    Copyright © 2017 www.zgxue.com All Rights Reserved