Fabric


Fabric是一个python的远程执行shell的库,同时它也是一个命令行工具。它提供了丰富的同 SSH 交互的接口,可以用来在本地或远程机器上自动化、流水化地执行 Shell 命令。

Python 的 Fabric 是一个基于 SSH 协议的自动化部署与运维工具,它在 Paramiko(底层 SSH 实现)的基础上封装了更简洁的 API,支持通过任务(Task) 定义批量操作(如远程命令执行、文件传输、环境配置等),并可通过命令行直接调用,极大简化了多服务器集群的管理工作。

一、Fabric 版本与安装

Fabric 有两个主要版本,API 差异较大:
- Fabric 1.x:较早版本,使用 fab 命令和 env 全局变量配置,目前已停止维护。
- Fabric 2.x+:重构后的新版本,采用面向对象 API(如 Connection 类),支持更灵活的任务定义,推荐使用。

本文以 Fabric 2.x+ 为例讲解。

安装 Fabric

pip install fabric  # 安装最新版本(2.x+)

二、核心概念:任务(Task)与连接(Connection)

Fabric 的核心是任务(Task)连接(Connection)
- 任务(Task):用 @task 装饰器定义的函数,封装了一组操作(如执行命令、传输文件),可通过命令行调用。
- 连接(Connection):代表与远程服务器的 SSH 连接,通过它执行远程命令(run)、sudo 操作(sudo)、文件传输(put/get)等。

三、基础使用:定义与执行任务

1. 编写任务文件(fabfile.py

Fabric 默认读取当前目录下的 fabfile.py(或 fabfile/ 目录)中的任务,文件名固定(方便命令行识别)。

# fabfile.py
from fabric import task
from fabric.connection import Connection

# 定义任务:通过装饰器 @task
@task
def hello(c):
    """简单任务:打印远程服务器信息"""
    # c 是 Connection 对象(由 Fabric 自动传入,代表与远程服务器的连接)
    c.run("uname -a")  # 执行远程命令(如查看系统信息)
    c.run("echo 'Hello from remote server!'")

2. 执行任务(命令行)

通过 fab 命令调用任务,需指定远程服务器的连接信息(主机、用户等)。

# 格式:fab [任务名] -H [主机] -u [用户] -p [密码]
# 示例:执行 hello 任务,连接到 192.168.1.100,用户 root,密码 123456
fab hello -H 192.168.1.100 -u root -p 123456

输出类似:

Linux server 5.4.0-100-generic #113-Ubuntu SMP Thu Feb 3 18:43:29 UTC 2022 x86_64 x86_64 x86_64 GNU/Linux
Hello from remote server!

四、核心操作详解

1. 连接配置(避免硬编码)

直接在命令行传递密码(-p)不安全,推荐通过配置文件密钥认证管理连接信息。

(1)通过参数指定连接信息
# 密钥认证(推荐,无需密码)
fab hello -H 192.168.1.100 -u root -i ~/.ssh/id_rsa  # -i 指定私钥路径
(2)在任务中硬编码连接(适合固定服务器)
@task
def hello_fixed(c):
    # 直接创建 Connection 对象(手动指定连接信息)
    conn = Connection(
        host="192.168.1.100",
        user="root",
        connect_kwargs={
            "key_filename": "/home/user/.ssh/id_rsa"  # 私钥路径
        }
    )
    conn.run("uname -a")

2. 执行远程命令(runsudo

  • c.run(command):以当前用户权限执行命令。
  • c.sudo(command):以 sudo 权限执行命令(需输入密码时,可通过 password 参数指定)。
@task
def manage_service(c):
    """管理远程服务器的 Nginx 服务"""
    # 查看 Nginx 状态(普通用户权限)
    c.run("systemctl status nginx")

    # 重启 Nginx(需要 sudo 权限,假设 sudo 密码为 '123456')
    c.sudo("systemctl restart nginx", password="123456")  # 若免密 sudo 可省略 password

    # 检查重启后状态
    c.run("systemctl status nginx | grep 'active (running)'")

3. 文件传输(putget

通过 c.put() 上传本地文件到远程,c.get() 从远程下载文件到本地,类似 SFTP。

@task
def transfer_files(c):
    """上传本地文件到远程,下载远程文件到本地"""
    # 上传本地文件(local_path → remote_path)
    c.put("local_script.sh", "/tmp/remote_script.sh")  # 上传当前目录的脚本到远程 /tmp
    c.run("chmod +x /tmp/remote_script.sh")  # 赋予执行权限

    # 下载远程文件(remote_path → local_path)
    c.get("/var/log/syslog", "local_syslog.log")  # 下载远程日志到本地

4. 批量操作多台服务器

通过 -H 参数指定多个主机(逗号分隔),Fabric 会按顺序在每台服务器上执行任务。

# 同时在 192.168.1.100 和 192.168.1.101 上执行 hello 任务
fab hello -H 192.168.1.100,192.168.1.101 -u root -i ~/.ssh/id_rsa

5. 任务依赖(@task(pre=[...])

通过 pre 参数指定“前置任务”,执行当前任务前会先执行前置任务(类似流水线)。

@task
def prepare(c):
    """前置任务:更新系统包"""
    c.sudo("apt update -y", password="123456")

@task(pre=[prepare])  # 执行 install_nginx 前先执行 prepare
def install_nginx(c):
    """安装 Nginx(依赖 prepare 任务)"""
    c.sudo("apt install nginx -y", password="123456")
    c.run("nginx -v")  # 验证安装

执行 install_nginx 任务时,会先自动执行 prepare

fab install_nginx -H 192.168.1.100 -u root -i ~/.ssh/id_rsa

五、进阶:动态主机与并行执行

1. 动态生成主机列表(适合动态集群)

通过 @taskhosts 参数或在任务中动态返回主机列表,灵活适配动态变化的服务器集群。

@task(hosts=["192.168.1.100", "192.168.1.101"])  # 静态指定主机
def check_all(c):
    c.run("hostname")

# 动态生成主机列表(例如从配置文件读取)
def get_dynamic_hosts():
    return ["192.168.1.102", "192.168.1.103"]  # 实际可从数据库/API 读取

@task
def check_dynamic(c):
    for host in get_dynamic_hosts():
        conn = Connection(host, user="root", connect_kwargs={"key_filename": "~/.ssh/id_rsa"})
        conn.run("hostname")

2. 并行执行任务(加速多服务器操作)

默认情况下,Fabric 按顺序在多台服务器上执行任务。通过 --parallel(或 -P)参数可并行执行,大幅提升效率(适合无依赖的批量操作)。

# 并行在 10 台服务器上执行任务(同时运行,而非顺序)
fab update_config -H host1,host2,...,host10 -u root -P

六、Fabric 与 Paramiko 的区别

工具 定位 优势 适用场景
Paramiko 底层 SSH 协议实现 灵活,可自定义任意 SSH 交互逻辑 复杂 SSH 交互(如交互式命令)
Fabric 高层自动化运维工具 简化 API,任务化组织,命令行集成 批量部署、标准化运维、重复任务自动化

七、应用场景

Fabric 适合以下自动化场景:
1. 批量部署应用:在多台服务器上同步代码、安装依赖、启动服务(如部署 Django/Flask 应用)。
2. 服务器配置标准化:统一设置时区、防火墙规则、安装基础工具(如 gitpython)。
3. 日志收集与监控:定期从多台服务器下载日志文件,或执行性能检查命令(如 topfree)。
4. 应急操作:批量重启服务、临时修改配置(如应对流量峰值)。

总结

Fabric 是基于 Paramiko 的高层封装,核心优势在于:
- 任务化组织:用 @task 装饰器定义可复用的操作,逻辑清晰。
- 命令行集成:通过 fab 命令直接调用任务,无需编写完整脚本。
- 批量与并行:轻松支持多服务器操作,并行执行提升效率。

对于需要频繁操作多台远程服务器的场景(如运维、部署),Fabric 能显著减少重复劳动,是自动化工具链中的重要组件。

安装Fabric

Fabric的官网是 www.fabfile.org,源码托管在Github上。你可以clone源码到本地,然后通过下面的命令来安装。但是在源码安装前,你必须先将Fabric的依赖包Paramiko装上。

python setup.py develop

同时也可以使用pip安装,因为fabric是python的一个第三方库,只需一条命令即可:

 pip install fabric

python3 安装时使用的是fabric3 :( 安装fabric3之前,需要先卸载fabric.)

# fabric3 支持 python3

pip uninstall fabric

pip3 install fabric3

fabric 不只是一个Python 模块,fabric 还是一个命令行工具,可以使用fab -h查看帮助信息

E:\my_data\hk-project>fab -V
Fabric3 1.14.post1
Paramiko 2.4.2
E:\my_data\hk-project>fab -h 

入门使用

fabric的使用方式是通过编写一个python文件,该文件中包含多个函数,然后使用fab命令调用这些函数,做相应的任务。这些函数在fabric中称为task。

# filename:abc.py

from fabric.api import *

def task1():
     print("hello")

def hello():
     print("hello world")

写好这个python文件后,在当前目录的路径下使用fab工具执行文件中的函数

[root@localhost python文件所在的目录]# fab -f abc.py hello
 hello world

# -f 指定fabfile文件,默认为fabfile.py,若文件名是当前目录下的fabfile.py则无需指定

任务参数

此时你可能会想,如果这个函数有参数怎么办呢?应该如何传递参数给函数呢?Fabric 支持 Shell 兼容的参数用法: <任务名>:<参数>, <关键字参数名>=<参数值>,... 用起来就是这样。

 def hello(name="world"):
     print("hello {}".format(name))

我们可以这样去指定参数

$ fab hello:name=Jeff   # 或者 fab hello:Jeff
hello Jeff

Done.

小试牛刀

现在我们假设需要写一个fabfile.py,能够在每次web项目代码更新后使用git提交并远程服务器拉去最新代码并运行,需求描述清楚了,开干吧!

# fabfile.py
 # 这里建议将该文件放入项目文件的根目录中,方便git提交

from fabric.api import local

def test():
     local('python manage.py test myapp')
     # 测试是否能正常运行

def commit():
     local('git add -p && git commit -m "for test"')

def push():
     local('git push')

def prepare_deploy():
     test()
     commit()
     push()

这个 prepare_deploy 任务可以单独调用,也可以调用更细粒度的子任务。

故障

Fabric 会检查被调用程序的返回值,如果这些程序没有干净地退出,Fabric 会终止操作。我们什么都不用做,Fabric 检测到了错误并终止,不会继续执行 commit 任务。

我们也可以对故障进行一定的处理和判断

from fabric.api import local, settings, abort
from fabric.contrib.console import confirm

def test():
     with settings(warn_only=True):
         result = local('./manage.py test my_app', capture=True) 
         # result.return_code返回码(0/1)和result.failed
     if result.failed and not confirm("Tests failed. Continue anyway?"): # confirm判断用户输入
         abort("Aborting at user request.")  # 指定错误退出信息

 # 一个名为 warn_only 的设置(或着说 环境变量 ,通常缩写为 env var )可以把退出换为警告,以提供更灵活的错误处理。如果设置为False,则一条命令运行失败会就会退出,不再执行后面的命令。

建立连接

终于到了连接了,这个工具主要作用就是在远程执行命令呀,学会了这个,我们就可以在本地执行远程服务器的命令了。

from fabric.api import *

env.hosts = ['root@192.168.10.11:22']

def deploy():
     run('ls')  # run()用于执行远程命令,local()执行本地命令

 # 执行后会提示你输入密码,输入密码即可

使用fabric安装lamp

# 采用ThreadingGroupd对象并发执行
from fabric import ThreadingGroup as Group

hosts = (
    "root@192.168.10.50", "root@192.168.10.51"
)
group = Group(*hosts, connect_kwargs={"password": "abc123"})
print("自动安装LAMP ......")
# 安装Apache服务器
group.run("yum install httpd -y")
# 安装并启动MariaDB服务器
group.run("yum install mariadb mariadb-server -y")
group.run("systemctl start mariadb")
group.run("systemctl enable mariadb")
# 以非交互方式运行MariaDB数据库安全配置向导
group.run("echo -e '\ny\nabc123\nabc123\ny\ny\ny\ny\n' | /usr/bin/mysql_secure_installation")
# 安装PHP
group.run(
    "yum install pcre gcc-c++ zlib* php php-mysqlnd php-gd libjpeg* php-ldap php-odbc php-pear php-xml* php-json php-mbstring php-bcmath php-mhash -y")
# 生成PHP测试文件
group.run("echo '<?php phpinfo(); ?>' |  tee /var/www/html/test.php")
# 启动Apache服务器
group.run("systemctl start httpd")
group.run("systemctl enable httpd")
# 防火墙开启HTTP和HTTPS服务
group.run("systemctl start firewalld", warn=True)
group.run("firewall-cmd --permanent --zone=public --add-service=http  --add-service=https", warn=True)
group.run("firewall-cmd  --reload")
# 安装phpMyAdmin
group.run("curl -o phpMyAdmin.zip https://files.phpmyadmin.net/phpMyAdmin/4.9.10/phpMyAdmin-4.9.10-all-languages.zip")
group.run("mv phpMyAdmin.zip /var/www/html")
group.run("unzip -d /var/www/html /var/www/html/phpMyAdmin.zip")
group.run("rm /var/www/html/phpMyAdmin.zip")
group.run("mv /var/www/html/phpMyAdmin-4.9.10-all-languages /var/www/html/phpmyadmin")
group.run("mv /var/www/html/phpmyadmin/config.sample.inc.php /var/www/html/phpmyadmin/config.inc.php")
group.close()

参考链接:

fabric官方中文文档:https://fabric-chs.readthedocs.io/zh_CN/chs/tutorial.html