参考文章:http://zmrenwu.com/post/21/

Fabric是一个Python的库,它提供了丰富的同SSH交互的接口,可以用来在本地或远程机器上自动化、流水化地执行Shell命令。因此它非常适合用来做应用的远程部署及系统维护。其上手也极其简单,你需要的只是懂得基本的Shell命令。

安装Fabric

pip install fabric

第一个例子

我们创建一个”fabfile.py”文件,然后写个hello函数:

def hello():
print "Hello Fabric!"

现在,让我们在”fabfile.py”的目录下执行命令:

fab hello

你可以在终端看到”Hello Fabric!”字样。

解释下,”fabfile.py”文件中每个函数就是一个任务,任务名即函数名,上例中是”hello”。”fab”命令就是用来执行”fabfile.py”中定义的任务,它必须显式地指定任务名。你可以使用参数”-l”来列出当前”fabfile.py”文件中定义了哪些任务:

fab -l

任务可以带参数,比如我们将hello函数改为:

def hello(name, value):
print "Hello Fabric! %s=%s" % (name,value)

此时执行hello任务时,就要传入参数值:

fab hello:name=Year,value=2016

Fabric的脚本建议写在”fabfile.py”文件中,如果你想换文件名,那就要在”fab”命令中用”-f”指定。比如我们将脚本放在”script.py”中,就要执行:

fab -f script.py hello

执行本地命令

“fabric.api”包里的”local()”方法可以用来执行本地Shell命令,比如让我们列出本地”/home/bjhee”目录下的所有文件及目录:

from fabric.api import local

def hello():
local('ls -l /home/bjhee/')

“local()”方法有一个”capture”参数用来捕获标准输出,比如:

def hello():
output = local('echo Hello', capture=True)

这样,Hello字样不会输出到屏幕上,而是保存在变量output里。”capture”参数的默认值是False。

执行远程命令

Fabric真正强大之处不是在执行本地命令,而是可以方便的执行远程机器上的Shell命令。它通过SSH实现,你需要的是在脚本中配置远程机器地址及登录信息:

from fabric.api import run, env

env.hosts = ['example1.com', 'example2.com']
env.user = 'bjhee'
env.password = '' def hello():
run('ls -l /home/bjhee/')

“fabric.api”包里的”run()”方法可以用来执行远程Shell命令。上面的任务会分别到两台服务器”example1.com”和”example2.com”上执行”ls -l /home/bjhee/”命令。这里假设两台服务器的用户名都是”bjhee”,密码都是6个1。你也可以把用户直接写在hosts里,比如:

env.hosts = ['bjhee@example1.com', 'bjhee@example2.com']
如果你的”env.hosts”里没有配置某个服务器,但是你又想在这个服务器上执行任务,你可以在命令行中通过”-H”指定远程服务器地址,多个服务器地址用逗号分隔:
fab -H bjhee@example3.com,bjhee@example4.com hello

多台机器的任务是串行执行的,关于并行任务的执行我们在之后会介绍。

如果对于不同的服务器,我们想执行不同的任务,上面的方法似乎做不到,那怎么办?我们要对服务器定义角色:

from fabric.api import env, roles, run, execute, cd

env.roledefs = {
'staging': ['bjhee@example1.com','bjhee@example2.com'],
'build': ['build@example3.com']
} env.passwords = {
'staging': '',
'build': ''
} @roles('build')
def build():
with cd('/home/build/myapp/'):
run('git pull')
run('python setup.py') @roles('staging')
def deploy():
run('tar xfz /tmp/myapp.tar.gz')
run('cp /tmp/myapp /home/bjhee/www/') def task():
execute(build)
execute(deploy)

现在让我们执行:

fab task

这时Fabric会先在一台build服务器上执行build任务,然后在两台staging服务器上分别执行deploy任务。”@roles”装饰器指定了它所装饰的任务会被哪个角色的服务器执行。

如果某一任务上没有指定某个角色,但是你又想让这个角色的服务器也能运行该任务,你可以通过”-R”来指定角色名,多个角色用逗号分隔:

fab -R build deploy

这样”build”和”staging”角色的服务器都会运行”deploy”任务了。注:”staging”是装饰器默认的,因此不用通过”-R”指定。

上面的例子中,服务器的登录密码都是明文写在脚本里的。这样做不安全,推荐的方式是设置SSH自动登录

SSH功能函数

到目前为止,我们介绍了”local()”和”run()”函数分别用来执行本地和远程Shell命令。Fabric还提供了其他丰富的功能函数来辅助执行命令,这里我们介绍几个常用的:

sudo: 以超级用户权限执行远程命令

功能类似于”run()”方法,区别是它相当于在Shell命令前加上了”sudo”,所以拥有超级用户的权限。使用此功能前,你需要将你的用户设为sudoer,而且无需输密码。具体操作可参见这篇文章

from fabric.api import env, sudo

env.hosts = ['bjhee@example1.com', 'bjhee@example2.com']
env.password = '' def hello():
sudo('mkdir /var/www/myapp')

get(remote, local): 从远程机器上下载文件到本地

它的工作原理是基于scp命令,使用的方法如下:

from fabric.api import env, get

env.hosts = ['bjhee@example.com',]
env.password = '' def hello():
get('/var/log/myapp.log', 'myapp-0301.log')

上述任务将远程机上”/var/log/myapp.log”文件下载到本地当前目录,并命名为”myapp-0301.log”。

put(local, remote): 从本地上传文件到远程机器上

同get一样,put方法也是基于scp命令,使用的方法如下

from fabric.api import env, put

env.hosts = ['bjhee@example1.com', 'bjhee@example2.com']
env.password = '' def hello():
put('/tmp/myapp-0301.tar.gz', '/var/www/myapp.tar.gz')

上述任务将本地”/tmp/myapp-0301.tar.gz”文件分别上传到两台远程机的”/var/www/”目录下,并命名为”myapp.tar.gz”。如果远程机上的目录需要超级用户权限才能放文件,可以在”put()”方法里加上”use_sudo”参数:

put('/tmp/myapp-0301.tar.gz', '/var/www/myapp.tar.gz', use_sudo=True)

prompt: 提示输入

该方法类似于Shell中的”read”命令,它会在终端显示一段文字来提示用户输入,并将用户的输入保存在变量里:

from fabric.api import env, get, prompt

env.hosts = ['bjhee@example.com',]
env.password = '' def hello():
filename = prompt('Please input file name: ')
get('/var/log/myapp.log', '%s.log' % filename)

现在下载后的文件名将由用户的输入来决定。我们还可以对用户输入给出默认值及类型检查:

port = prompt('Please input port number: ', default=8080, validate=int)

执行任务后,终端会显示:

Please input port number: [8080] 

如果你直接按回车,则port变量即为默认值8080;如果你输入字符串,终端会提醒你类型验证失败,让你重新输入,直到正确为止。

reboot: 重启服务器

有时候安装好环境后,需要重启服务器,这时就要用到”reboot()”方法,你可以用”wait”参数来控制其等待多少秒后重启,没有此参数则代表立即重启:

from fabric.api import env, reboot

env.hosts = ['bjhee@example.com',]
env.password = '' def restart():
reboot(wait=60)

上面的restart任务将在一分钟后重启服务器。

上下文管理器

Fabric的上下文管理器是一系列与Python的”with”语句配合使用的方法,它可以在”with”语句块内设置当前工作环境的上下文。让我们介绍几个常用的:

cd: 设置远程机器的当前工作目录

“cd()”方法在之前的范例中出现过,”with cd()”语句块可以用来设置远程机的工作目录:

from fabric.api import env, cd, put

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with cd('/var/www/'):
put('/tmp/myapp-0301.tar.gz', 'myapp.tar.gz')

上例中的文件会上传到远程机的”/var/www/”目录下。出了”with cd()”语句块后,工作目录就回到初始的状态,也就是”bjhee”用户的根目录。

lcd: 设置本地工作目录

“lcd()”就是”local cd”的意思,用法同”cd()”一样,区别是它设置的是本地的工作目录:

from fabric.api import env, cd, lcd, put

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with cd('/var/www/'):
with lcd('/tmp/'):
put('myapp-0301.tar.gz', 'myapp.tar.gz')

这个例子的执行效果跟上个例子一样。

path: 添加远程机的PATH路径

from fabric.api import env, run, path

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with path('/home/bjhee/tmp'):
run('echo $PATH')
run('echo $PATH')

假设我们的PATH环境变量默认是”/sbin:/bin”,在上述”with path()”语句块内PATH变量将变为”/sbin:/bin:/home/bjhee/tmp”。出了with语句块后,PATH又回到原来的值。

settings: 设置Fabric环境变量参数

Fabric环境变量即是我们例子中一直出现的”fabric.api.env”

from fabric.api import env, run, settings

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with settings(warn_only=True):
run('echo $USER')

我们将环境参数”warn_only”暂时设为True,这样遇到错误时任务不会退出。

shell_env: 设置Shell环境变量

可以用来临时设置远程和本地机上Shell的环境变量。

from fabric.api import env, run, local, shell_env

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with shell_env(JAVA_HOME='/opt/java'):
run('echo $JAVA_HOME')
local('echo $JAVA_HOME')

prefix: 设置命令执行前缀

from fabric.api import env, run, local, prefix

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with prefix('echo Hi'):
run('pwd')
local('pwd')

在上述”with prefix()”语句块内,所有的”run()”或”local()”方法的执行都会加上”echo Hi && “前缀,也就是效果等同于:

  run('echo Hi && pwd')
local('echo Hi && pwd')

配合后一节我们会讲到的错误处理,它可以确保在”prefix()”方法上的命令执行成功后才会执行语句块内的命令。

错误处理

默认情况下,Fabric在任务遇到错误时就会退出,如果我们希望捕获这个错误而不是退出任务的话,就要开启”warn_only”参数。在上面介绍”settings()”上下文管理器时,我们已经看到了临时开启”warn_only”的方法了,如果要全局开启,有两个办法:

  • 在执行”fab”命令时加上”-w”参数
fab -w hello
  • 设置”env.warn_only”环境参数为True
from fabric.api import env

env.warn_only = True

现在遇到错误时,控制台会打出一个警告信息,然后继续执行后续任务。那我们怎么捕获错误并处理呢?像”run()”, “local()”, “sudo()”, “get()”, “put()”等SSH功能函数都有返回值。当返回值的”succeeded”属性为True时,说明执行成功,反之就是失败。你也可以检查返回值的”failed”属性,为True时就表示执行失败,有错误发生。在开启”warn_only”后,你可以通过”failed”属性检查捕获错误,并执行相应的操作。

from fabric.api import env, cd, put

env.hosts = ['bjhee@example1.com', ]
env.password = '' def hello():
with cd('/var/www/'):
upload = put('/tmp/myapp-0301.tar.gz', 'myapp.tar.gz')
if upload.failed:
sudo('rm myapp.tar.gz')
put('/tmp/myapp-0301.tar.gz', 'myapp.tar.gz', use_sudo=True)

并行执行

多台机器的任务默认情况下是串行执行的。Fabric支持并行任务,当服务器的任务之间没有依赖时,并行可以有效的加快执行速度。怎么开启并行执行呢?办法也是两个:

  • 在执行”fab”命令时加上”-P”参数
fab -P hello
  • 设置”env.parallel”环境参数为True
from fabric.api import env

env.parallel = True

如果,我们只想对某一任务做并行的话,我们可以在任务函数上加上”@parallel”装饰器:

from fabric.api import parallel

@parallel
def runs_in_parallel():
pass def runs_serially():
pass

这样即便并行未开启,”runs_in_parallel()”任务也会并行执行。反过来,我们可以在任务函数上加上”@serial”装饰器:

from fabric.api import serial

def runs_in_parallel():
pass @serial
def runs_serially():
pass

这样即便并行已经开启,”runs_serially()”任务也会串行执行

补充

来补充Fabric的一些特别功能:

  • 终端输出带颜色

我们习惯上认为绿色表示成功,黄色表示警告,而红色表示错误,Fabric支持带这些颜色的输出来提示相应类型的信息:

from fabric.colors import *

def hello():
print green("Successful")
print yellow("Warning")
print red("Error")
  • 限制任务只能被执行一次

通过”execute()”方法,可以在一个”fab”命令中多次调用同一任务,如果想避免这个发生,就要在任务函数上加上”@runs_once”装饰器。

from fabric.api import execute, runs_once

@runs_once
def hello():
print "Hello Fabric!" def test():
execute(hello)
execute(hello)

现在不管我们”execute”多少次hello任务,都只会输出一次”Hello Fabric!”字样

Python 远程部署 Fabric的更多相关文章

  1. 推荐 远程部署 fabric

    自己写的一个例子: from fabric.api import run, env env.hosts = ['nanjing','hefei','haerbin','lanzhou','taiyua ...

  2. Python模块学习 - fabric

    简介 fabric是一个Python的库,同时它也是一个命令行工具.使用fabric提供的命令行工具,可以很方便地执行应用部署和系统管理等操作. fabric依赖于paramiko进行ssh交互,fa ...

  3. python模块之 fabric

    Python模块之Fabric   Fabric简介 Fabric是一个Python库,可以通过SSH在多个host上批量执行任务.你可以编写任务脚本,然后通过Fabric在本地就可以使用SSH在大量 ...

  4. Pycharm中进行Python远程开发

    http://blog.csdn.net/pipisorry/article/details/52269952 PyCharm提供两种远程调试(Remote Debugging)的方式:    配置远 ...

  5. 使用pycharm进行远程开发部署调试设置 与 远程部署调试是否必须使用远程主机的解释器?

    远程开发部署调试目的: 配置pycharm远程部署调试主要用于本地代码与远程服务器上的代码进行同步,使得本地代码经过修改后,可以很容易的同步到远程服务器上.同时设置pycharm的解释器为远程服务器的 ...

  6. 阿里云(ecs服务器)使用3-安装mysql数据库以及远程部署

    1.安装 1.下载rpm包,下载地址 http://dev.mysql.com/downloads/mysql/,选择Linux-Generic版本 .新建 /usr/local/mysql 文件夹, ...

  7. WinServer远程部署系统(RDSystem)

    系统简介 RemoteDeploySystem是一套BS结构的远程部署管理系统(简称RDSystem),可以通过浏览器上传web站点和windows服务的更新包到RDSystem服务器,然后对多个服务 ...

  8. WinServer远程部署系统打包批处理文件

    前言 工作中一直在使用一个部署系统WinServer远程部署系统(RDSystem),部署.回滚都很方便.我们一直都是增量发布或者只更新需要更新的文件,每次发布完之后要整理出一个增量更新包,压缩成zi ...

  9. tomcat远程部署应用

    Tomcat安装成功后,在ip地址:8080上就可以看见熟悉的首页,在这个首页中,上方有一个manage app按钮,点击就可以进行应用管理了.这样就不需要使用ftp把war包传上去了. 要想远程部署 ...

随机推荐

  1. CF#462 div1 D:A Creative Cutout

    CF#462 div1 D:A Creative Cutout 题目大意: 原网址戳我! 题目大意: 在网格上任选一个点作为圆中心,然后以其为圆心画\(m\)个圆. 其中第\(k\)个圆的半径为\(\ ...

  2. 【Luogu1373】小a和uim之大逃离(动态规划)

    [Luogu1373]小a和uim之大逃离(动态规划) 题面 题目背景 小a和uim来到雨林中探险.突然一阵北风吹来,一片乌云从北部天边急涌过来,还伴着一道道闪电,一阵阵雷声.刹那间,狂风大作,乌云布 ...

  3. [BZOJ4071][APIO2015]八邻旁之桥

    BZOJ(这题是BZOJ权限题,有权限号的就去看看吧) Luogu(良心洛谷) 题目描述 一条东西走向的穆西河将巴邻旁市一分为二,分割成了区域\(A\)和区域\(B\). 每一块区域沿着河岸都建了恰好 ...

  4. BZOJ2820:YY的GCD

    Sol 推导:\(n<m,p为质数\) \(ans=\sum_p\sum_{i=1}^{\frac{n}{p}}\mu(i)\frac{n}{pi}\frac{m}{pi}\) \(=\sum_ ...

  5. Cow Contest POJ - 3660

    题意 有n(1<=n<=100)个学生参加编程比赛. 给出m条实力信息.(1<=M<=4500) 其中每一条的格式为 A B (1<=A<=N,1<=B< ...

  6. [BZOJ1031] [JSOI2007] 字符加密Cipher (后缀数组)

    Description 喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考.一天,他突然想出了一种他认为是终极的加密办法 :把需要加密的信息排成一圈,显然,它们有很多种不同的读法.例如下图,可以读作 ...

  7. [BZOJ1207] [HNOI2004] 打鼹鼠 (dp)

    Description 鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的.根据这个特点阿Q编写了一个打鼹鼠的游戏:在一个n*n的网格中,在某些时刻鼹鼠会在某一个网格探 ...

  8. 【Spring源码分析】.properties文件读取及占位符${...}替换源码解析

    前言 我们在开发中常遇到一种场景,Bean里面有一些参数是比较固定的,这种时候通常会采用配置的方式,将这些参数配置在.properties文件中,然后在Bean实例化的时候通过Spring将这些.pr ...

  9. 【learning】多项式乘法&fft

    [吐槽] 以前一直觉得这个东西十分高端完全不会qwq 但是向lyy.yxq.yww.dtz等dalao们学习之后发现这个东西的代码实现其实极其简洁 于是趁着还没有忘记赶紧来写一篇博 (说起来这篇东西的 ...

  10. 关系型数据库工作原理-归并排序(翻译自Coding-Geek文章)

    本文翻译自Coding-Geek文章:< How does a relational database work>. 原文链接:http://coding-geek.com/how-dat ...