Execution Mode
执行模式--Execution Mode
之前定义了主机列表和任务列表,fabric根据主机列表和任务列表就可以执行任务,下面就是分析其执行策略及其他相关细节。由fab传入相应的参数就可以实现之前的多个主机执行多个任务的目标。现在先来看默认执行策略是什么样的。
执行策略
fabric函数默认是单个、顺序执行方式,当然它也提供并行执行。默认执行行为:
1.创建一个任务列表,这些任务就是fab命令的参数,并且保持fab传参的顺序
2.对于每个任务,会通过特定方式创建特定主机列表
3.任务按照顺序执行,每个人物会在指定特定主机上执行一次
4.对于没有指定主机的任务,默认是本地任务,仅执行一次
from fabric.api import run, env
env.hosts = ['host1', 'host2']
def taskA():
run('ls')
def taskB():
run('whoami')
$ fab taskA taskB
执行顺序就会是:
taskA on host1
taskA on host2
taskB on host1
taskB on host2
智能执行
在1.3版本之前,fabric只能针对特定任务指定特定主机列表,或者全局使用相同主机列表,若一个任务使用role1,而另一个任务使用role2,而定义了新的函数来执行这两个任务,role1,和role2不尽相同。则此时需要使用execute 来执行。
举例如下:
from fabric.api import run, roles
env.roledefs = {
'db': ['db1', 'db2'],
'web': ['web1', 'web2', 'web3']
}
@roles('db')
def migrate():
pass
@roles('web')
def update():
pass
定义新函数实现在同一任务调用时用db来migrate,而用web来update
def deploy():
execute(migrate)
execute(update)
建立连接
fab 自身并不与远程主机建立实际连接。而是对于每一个需要执行的任务的主机列表的每一个主机,该任务的env 变量中 env.hoststring 指定正确的值(主机)。env.hoststring 指定当前host string,当需要网络的函数执行时 fabric 用来决定是建立连接还是在共享字典(映射 SSH 连接对象)里查找并重用。像run/put这样的操作使用env.host_string作为一个共享字典的查找表来映射host strings和ssh 连接对象。
需要使用fabric作为类库来使用时需要手动设定须连接的对象 。这在类库使用部分有详细介绍几种使用方式。
fabric 建立的连接是一种懒惰连接,任务相关,不到万不得已不会建立,而连接的释放并不会随着缓存的消失而关闭,直到任务执行结束或显示调用disconnect_all 去关闭连接。
对于多连接中可能遇到的某些 bad hosts,可以显式设置env.skipbadhosts以及超时时间和连接次数等.
from fabric.api import *
@hosts('host1')
def clean_and_upload():
local('find assets/ -name "*.DS_Store" -exec rm '{}' \;')
local('tar czf /tmp/assets.tgz assets/')
put('/tmp/assets.tgz', '/tmp/assets.tgz')
with cd('/var/www/myapp/'):
run('tar xzf /tmp/assets.tgz')
两个local调用不会建立任何网络连接
put向连接缓存中要求同host1建立连接
连接缓存中没有该连接的host string,则SSH创建新的连接,返回给put
put通过该连接上传文件
最后,run询问连接缓存同样的host string,由于已经有了,则该连接被重用。
这就是连接过程,直到执行完毕。
密码管理
fabric在内存保留两层缓存来帮助记住login和sudo的密码,这避免了当多个系统密码相同时不断重复输入密码。
第一层是默认简单的密码缓存,env.password。这个环境变量保存一个单一的当当前特定主机(host_string)需要密码时会尝试的密码。
第二层env.passwords保存了最近输入的每一个不同的user/host/port组合的密码,它是一个per-user/per-host缓存。由于这个缓存,在同一个会话中连接多个不同user或者host每个只需要一个单一密码。
根据你的配置和你的回话连接的主机数量,你也许会发现任一或全部env vars会比较有用。当然,fabric会自动填写相关值而不需要额外的设置。特别地,每一次密码prompt,用户敲入的密码都会被用来更新当前连接的host_string的两个缓存的值。
并行执行
fabric默认的执行模式是串行执行,正如我们在前面所看到的一样。fabric同样提供并行执行功能,目前是通过python的multiprocessing模块来实现。它为每一个主机和任务组合创建一个线程,有选择地使用sliding window来阻止同时创建过多线程。
对于之前串行的例子,如果执行
$ fab -P taskA taskB
执行结果就会是:
taskA on host1,host2
taskB on host1,host2
怎样使用:
装饰器:
@parallel(另@serial default值)
命令行:
-P(default为serial)
from fabric.api import *
@parallel
def runs_in_parallel():
pass
$fab run_in_parallel
Bubble Size
对于大量的主机列表,如果执行太多并发fabric进程会容易使机器宕机。为此,使用poolsize来限制fabric并发活动进程数量。默认poolsize为1.
使用方法:
from fabric.api import *
@parallel(pool_size=5)
def heavy_task():
# lots of heavy local lifting or lots of IO here
或者通过-z选项来指定:
$ fab -P -z 5 heavy_task
Linewise output
fabric默认输出终端的方式是typebytype,为了支持远程交互。这会导致在并行执行时糟糕的输出,因为多线程可能同时向终端标准输出流。所以在并行执行时,fabric默认是linewise output。这是并行和输出的折中,虽然fabric远程交互特点大打折扣,但是相对那些在并行时没有很好处理输出应经好很多。
现在并行时虽然不同执行行与行之间交叉,但可以通过每行的host string前缀处理 。就是很多命令交叉着出现
[host1]out:xxx
[host2]out:yyy
[host3]run:zzz
[host2]out:ppp
这样很乱,如果需要提取每一台主机返回的信息,需要进行字符串处理。
blog comments powered by Disqus