nwnusun

   ::  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

fabric简介

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

fabric 依赖于 paramiko 进行 ssh 交互,fabric 的设计思路是通过几个 API 接口来完成所有的部署,因此 fabric 对系统管理操作进行了简单的封装,比如执行命令,上传文件,并行操作和异常处理等。

paramiko 是一个用于做远程控制的模块,使用该模块可以对远程服务器进行命令或文件操作,fabric 和 ansible 内部的远程管理就是使用的 paramiko 来现实。

版本

fabric 简介 和 各个版本差异比较:http://www.mamicode.com/info-detail-2337088.html

1、Python 官网发布的地址

Fabric1:https://pypi.org/project/Fabric/
Fabric2:https://pypi.org/project/fabric2/
Fabric3:https://pypi.org/project/Fabric3/
2、区别

1). Fabric1、Fabric和fabric2:Fabric 和 Fabric2 在 Pypi 中就是同一个东西,fabric2 只是 Fabric 的替代名称,为了便于使用备用名称进行安装。Fabric2 和之前的 Fabric1 相比,完全重写了,接口和功能都有很大改动,官网也不建议继续用 Fabric1,建议升级到 Fabric2。‘而最新版也早就支持 Python 3.4+、Python2.7 了。
2). Fabric3:Fabric3 是非官网的,是之前使用 Fabric 时,没有支持 Python3 的版本,有人fork 出来,加了 Python3 的支持,但现在应该已经不维护了。

3、总结

尽量使用最新的 Fabric2。

Fabric 在升级 2.x 之后,几乎就是重写了。很多以前的用法都变了,然后在 1.x 时代,本地和远程都是用一套代码处理,但是 2.x 的时候将 local 处理部分和远程处理部分分别拆分为 fab 和 invoke了,拆分的理由可以参考 这里。

1. 安装fabric2

Linux

sudo pip3 install fabric

如果是windows系统, 假设你下载安装的就是python3的软件, 那么当你使用 pip install 的时候, 这个pip 就是3的版本. 所以不需要再多设置

pip install fabric  -i "https://pypi.doubanio.com/simple/"

2. fabric2基础命令

1.Connection类

 conn = fabric.Connection(host , user = 'root',port = 22, config = None, geteway = None, connect_kwargs={"password": "123456"})

Connection类属性

def __init__(
    self,
    host,                       #主机ip
    user=None,                  #用户名
    port=None,                  #ssh端口,默认是22
    config=None,                #登录配置文件
    gateway=None,               #连接网关
    forward_agent=None,         #是否开启agent forwarding
    connect_timeout=None,       #设置超时
    connect_kwargs=None,        #设置 密码登录connect_kwargs={"password": "123456"}) 还是 密钥登录connect_kwargs={"key_filename": "/home/myuser/.ssh/private.key"}
    inline_ssh_env=None,      
    )

Conection类方法:

cnn获取Connetction对象后,有很多属性方法可以使用,介绍下几个常用的:

run:   #执行远程命令,如:run('uname -a')

cd:    #切换远程目录,如:cd('/root');   with conn.cd('/root'):继承这个状态

put:   #上传本地文件到远程主机,如:put('/root/test.py','/root/test.py')

get:    #获取服务器上文件,如:get('/root/project/test.log')

sudo:   #sudo方式执行远程命令,如:sudo('service docker start')

对多台机器使用时,Connection

import fabric
def get_hostname():
    for host in ['192.168.2.250',
                 '192.168.2.224',
                 '192.168.2.219']:
        conn = fabric.Connection(host, user='root', connect_kwargs={"password": "123456"})
        print("%s:" % host)
        conn.run("hostname")
get_hostname()

2. Group类

连接多个服务器,组成一个group,一个group同时执行run命令时,会返回一个 GroupResult-dict,包含了每个服务器的运行结果。

from fabric2 import SerialGroup

class fra_utils:
 def get_Ip_BySC(self, *host):
    pool = SerialGroup(*host, connect_kwargs={'password': '123456'})
    pool.run('cd /opt && touch fabric2.txt')

if __name__ == '__main__':
    hosts = ('root@192.168.2.250', 'root@192.168.2.224')
    results=fra_utils().get_Ip_BySC(*hosts)
    for connection, result in results.items():
	print("{0.host}: {1.stdout}".format(connection, result))

3. 扩展,运行本地命令

import invoke
 
invoke.run('ls')

3. 安装fabric3

pip install fabric3

4. fabric3基本命令

fab 语法

fab 是 fabric 程序的命令行入口,在命令行使用!!!,语法:

fab [options] <command>[arg1,arg2:val2,host=foo]

fab 命令的执行,默认依赖一个 fabfile.py 的文件,可以对该文件进行编辑,也可以执行其他的文件,用 -f 参数指定文件即可

fab 参数

可以使用 fab -help 查看具体参数:

-l,     显示定义好的任务函数名
-f,     指定 fab 入口文件,默认 fabfile.py
-g,     指定网关设备,比如堡垒机环境,填写堡垒机 ip 即可
-H, 指定目标主机,多台用逗号隔开
-P      以异步并行方式运行多主机任务,默认串行运行
-R, 指定 role,以角色名区分不同业务组设备
-t      设置设备连接超时时间
-T      设置远程主机命令执行超时时间
-w      当命令失败的时候,发出警告,而不是终止任务
-p      指定密码

fabric 常用 api

fabric 执行本地命令和远程命令,必须先导入 fabric 对应的 api 接口。

api调用方法

from fabric.api import *
env.hosts = 'localhost'

def hello():
    local('echo hello world')

def check():
    local('ls /Users/')

def remote():
    run('ping www.baidu.com')

env 全局环境变量

导入 env 变量

from fabric.api import env
env.hosts,  定义目标主机,多个主机用列表的形式体现
env.exclude_hosts,  排除指定的主机,env.exclude_hosts=['192.168.184.2']

env.user,   定义用户名
env.port,   定义目标主机端口

env.password,   定义密码
env.passwords,  与 password 功能一样,需要指定主机。env.passwords = {'user1@host':'password','user2@host':'password'}

env.gateway,    定义网关(中转、堡垒机)IP

env.roledefs,   定义角色分组。env.roledefs = {'webserver':['host1','host2'], 'dbserver':['db1','db2']}

env.deploy_release_dir  自定义全局变量,env.deploy_release_dir, env.age, env.sex 等等

命令行执行

fab 依赖的 fabric.py 文件中创建函数。
import fabric.api

def hello():
    fabric.api.local('echo hello world')

def check():
    fabric.api.local('ls /Users/')

def remote(cmd):
    fabric.api.run(cmd)

在命令行执行命令的时候,使用 fab + fun函数即可。

$ fab hello
$ fab check

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

$ fab remote:cmd='ifconfig'

执行远程命令

from fabric.api import *

env.user = 'root'
env.hosts = ['192.168.184.2', '192.168.184.22']
env.password = 'yourpassword'
env.passwords = {
    'staging': '11111',
    'build': '123456'
}
env.roledefs = {
    'webserver': ['bjhee@example1.com','bjhee@example2.com'],
    'dbserver': ['build@example3.com']
}

@roles('webserver')
def remote_task():
    with cd('/data/logs'):     # with 的左右是让后面的表达式,继承前面的状态
        run('ls -l')           # 实现 'cd /data/logs/ && ls -l' 的效果

@roles('dbserver')
def remote_build():
    with cd('/tmp/citizen_wang'):
        run('git pull')

def remote_deploy():
    run('tar zxvf /tmp/fabric.tar.gz')
    run('mv /tmp/fabric/setup.py /home/www/')

def task():
    execute(remote_build)
    execute(remote_deploy)

如果不使用execute这个函数去执行remote_build,则remote_build只能用 【 fab -f fabric.py remote_build】的方式执行。用了execute后就可以用'python3 fabric.py'的方式执行了

命令行调用:

$ fab task
$ fab remote_build

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

$  fab -R webserver remote_deploy

SSH功能函数

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

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

from fabric.api import *

env.hosts = ['192.168.201.169']
env.password = '123456'
env.user = 'root'

@task
def hello():
    sudo('hostname')

if __name__ == '__main__':
   execute(hello)
  1. get(remote, local): 从远程机器上下载文件到本地

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

@task
def get_file():
    get('/opt/sun.txt', 'sun1.txt')

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

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

@task
def put_file():
    put('sun1.txt', '/root')
  1. prompt: 提示输入

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

@task
def download_file():
    filename = prompt('请输入文件名:')
    get('/opt/sun.txt', '%s.log' % filename)

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

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

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

Please input port number: [8080]

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

5. reboot: 重启服务器

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

@task
def reboot_server():
    reboot(wait=60)

上下文管理器

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

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

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

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

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

2. lcd: 设置本地工作目录

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

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

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

3. path: 添加远程机的PATH路径

from fabric.api import env, run, path
 
env.hosts = ['bjhee@example1.com', ]
env.password = '111111'
 
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又回到原来的值。

2. settings: 设置Fabric环境变量参数

Fabric环境变量即是我们例子中一直出现的”fabric.api.env”,它支持的参数可以从官方文档中查到。

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

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

3. shell_env: 设置Shell环境变量

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

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

4. prefix: 设置命令执行前缀

from fabric.api import env, run, local, prefix
 
env.hosts = ['bjhee@example1.com', ]
env.password = '111111'
 
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支持并行任务,当服务器的任务之间没有依赖时,并行可以有效的加快执行速度。怎么开启并行执行呢?办法也是两个:

  1. 在执行”fab”命令时加上”-P”参数
 fab -P hello

​ 2. 设置”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的一些特别功能:

终端输出带颜色(Python3 好像不行)

我们习惯上认为绿色表示成功,黄色表示警告,而红色表示错误,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!”字样

posted on 2022-10-26 11:12  匿名者nwnu  阅读(181)  评论(0编辑  收藏  举报