python 自动化部署工具Fabric简介

自动化部署工具Fabric简介

Fabric就是一个帮助我们在上线时减少重复/繁琐操作的自动化部署利器,对于缺乏成熟运维平台的众多小公司的运维或开发人员来说,掌握这个工具是有必要的。

1. Fabric是什么

Fabric官方文档的描述如下: 
     Fabric is a Python (2.5-2.7) library and command-line tool for streamlining the use of SSH for application deployment or systems administration tasks. 
具体来说,Fabric是一个Python库,只要目标机器支持ssh访问,就可以借助fabric来进行远程操作(如在host1上对host2远程运行shell命令),显然,由于fabric是个Python package,故其它Python package都可以被import到fabric特有的fabfile.py脚本中,这使得fabric如虎添翼,在功能的丰富程度和运维脚本的可维护性上,远远超过用shell实现的自动化部署脚本,更不要说与纯手工敲命令的上线方式相比所体现出的巨大优势了。

在系统运维和部署自动化领域,与fabric类似的工具还有很多(如Puppet, Chef),感兴趣的话,可以参考这篇文章48 Best Cloud Tools for Infrastructure Automation的介绍。

Fabric的安装非常方便,pip install fabric就可以搞定,这里不赘述。

2. Fabric支持的操作

Fabric支持的常用命令列出如下: 
1)local Run a command on the local system. 
它是对subprocess模块的封装(Shell=True)可以通过设置Capture = True/False来捕获其执行结果。 
2)run  Run a shell command on a remote host. 
该命令的返回值包含了远程命令是否执行成功以及远程命令的返回码等信息。通过run执行命令时,通常会要求输入目标机器密码,如果对多台机器进行部署,可以通过设置env.passwords来避免手动输入密码,具体的设置方法会在下篇笔记中介绍。 
3)get  Download one or more files from a remote host. 
4)put  Upload one or more files to a remote host. 
5)sudo  Run a shell command on a remote host, with superuser privileges. 
功能与run操作类似,它可以对当前用户临时提权来执行某些需要root权限的命令。

此外,还有些不常用的命令(如:prompt, reboot, open_shell, require)这里没有列出,感兴趣的话,可以参考Fabric Operations文档

需要特别注意的是,fabric通过run或sudo执行远程任务时,每次都会新建ssh连接,也即任务之间是不会耦合状态的,所以在实现需要多步操作的任务时,需要把多个命令放入同一行,命令间用逗号隔开。实例说明如下: 
假设要在远程机器上cd至/home/work/tmp目录后创建test目录,则下面的命令无法实现预期目的:

run(‘cd /home/work/tmp‘)
run(‘mkdir test‘)  ## 第2次run会重新创建ssh连接,且不会记忆上次cd到的目录!!12

需要用下面的命令来实现:

run(‘cd /home/work/tmp; mkdir test‘)1
run(‘cd /home/work/tmp && mkdir test‘)1

当然,还可以借助fabric提供的context manager来实现:

with cd(‘/home/work/tmp‘):
    run(‘mkdir test‘)12

上面介绍了fabric支持的元操作,那么如何基于这些操作实现复杂功能呢? 
在fabric中,一组具有逻辑关系的操作通常被封装成一个task,fabric以task为粒度来执行命令,下面开始介绍如何定义task。

3. 在fabfile中定义tasks

3.1 fabfile是什么

根据fabric的约定,当运行例如”fab deploy”这样的命令时,fab会默认搜索名为fabfile.py的python文件或名为fabfile的package,故基于fabric的部署脚本通常以fabfile.py命名且应该位于当期工作目录下以便于fab进行搜索,在该文件中实现我们想要的任务即可。当然,如果要实现的部署任务比较复杂,这些任务也可以写在多个脚本中,统一置于fabric package下。关于fabfile的细节,可以参考官方文档Fabfile construction and use。

3.2 定义task

在语法约定上,fabric有两种定义task的方式: 
1)经典方式(classic method) 
所有定义在fabfile中的可调用对象(如函数、类)均可被当作task被fab执行,这种方式不支持嵌套,也即:若fabfile.py中import了其它模块,则即使这些模块中定义了可调用对象,这些不是直接定义在fabfile中的可调用对象也不会被当作fab task。

以classic方式定义的task示例下(摘自Fabric Overview and Tutorial):

from fabric.api import localdef prepare_deploy():
    local("./manage.py test my_app")
    local("git add -p && git commit")
    local("git push")

上述示例代码在fabfile.py中定义了一个普通函数prepare_deploy,不难看出,其功能是在本地执行代码测试后,将本地的最新codebase更新到版本管理系统中以便后续以该codebase进行部署。

2)基于Task类的新风格task 
从fabric 1.1开始,这种new-style的task定义方式被引入。该方式约定,所有的fab任务必须定义成Task类的实例或子类,其最大的优点是支持嵌套namespaces,也即,task可以定义在其它文件,fabfile.py通过import引入该文件后,定义在该文件的task也是可以被fab识别并支持的。

在new-style方式定义task的具体实现上,由2种方法:a. 定义一个继承自Task的子类并为其实现run()方法; b. 借助@task装饰器。示例分别如下:

class MyTask(Task):
    name = "deploy"  ## 指定task name,会在fab --list输出中显示
    def run(self, environment, domain="whatever.com"):
        run("git clone foo")
        sudo("service apache2 restart")

instance = MyTask()

上述示例与借助@task定义task的方式等价:

@taskdef deploy(environment, domain="whatever.com"):
    run("git clone foo")
    sudo("service apache2 restart")

被@task装饰的函数默认继承自Task类,我们可以让函数继承自定义的类,具体的用法可以参考文档Defining tasks的”Using custom subclasses with @task”部分,这里只是抛砖引玉,不再赘述。

需要特别注意的:

两种task的定义方式是互斥的!具体而言,如果fabric在fabfile或它import的文件中发现了基于Task类的new-style定义,那么,所有以classic方式定义的task(s)均会被fabric忽略。个人认为,如果要用fabric实现复杂系统的自动化部署,最好以new-style定义任务,因为这种方式支持嵌套namespace,可以用不同的脚本文件分层组织不同的任务,更方便维护。

备注:可以运行”fab –list”来查看fabric可以识别的任务。

完成task定义后,fabric是如何执行的?尤其是远程部署多台机器时,如何更好地管理这些机器(如角色、密码等)?

这些问题会在下篇笔记中进行说明。

参考资料

[1] 48 Best Cloud Tools for Infrastructure Automation 
[2] Deployment Management Tools: Chef vs. Puppet vs. Ansible vs. SaltStack vs. Fabric 
[3] Fabric Doc: Overview and Tutorial 
[4] Fabric Doc: Operations 
[5] Fabric Doc: Context Managers 
[6] Fabric Doc: Defining tasks

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, env

env.hosts = [‘host1‘, ‘host2‘]
def taskA():
    run(‘ls‘)
def taskB():
    run(‘whoami‘)

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

$ fab taskA taskB1

结果示例如下:

taskA executed on host1taskA executed on host2
taskB executed on host1taskB executed on host2

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

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

from fabric.api import *
@parallel
def runs_in_parallel():
    pass
def runs_serially():
    pass

当运行如下命令时:

fab -H host1,host2,host3 runs_in_parallel runs_serially1

执行结果示例如下:

runs_in_parallel on host1, host2, and host3
runs_serially on host1
runs_serially on host2
runs_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由[email protected]:port三部分构成,其中username和port部分可以缺省。本篇笔记前面的第1个代码实例其实已经说明了如何用env.hosts全局地指定task的目标机器列表,这里不再赘述。

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

from fabric.api import env

env.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 mytask1

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

from fabric.api import env, run

env.hosts.extend([‘host3‘, ‘host4‘])
def mytask():
    run(‘ls /var/www‘)123456

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

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

$ fab mytask:hosts="host1;host2"1

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

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

from fabric.api import env, run

env.hosts.extend([‘host3‘, ‘host4‘])
def mytask():
    run(‘ls /var/www‘)
    
    
   ##or#
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必须由[email protected]:port三部分构成,缺一不可,否则运行时还是会要求输入密码
env.passwords = {    ‘[email protected]:22‘: ‘xxx‘,    
              ‘[email protected]:23‘: ‘yyy‘,
}

@hosts(‘10.123.11.209‘, ‘10.123.11.210‘)
def host_os_type():
    run(‘uname -a‘)

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

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

时间: 2024-11-25 05:54:40

python 自动化部署工具Fabric简介的相关文章

Jenkins+GitLab+dotnet+Python自动化部署.Net Core项目

部署环境与流程1) Jenkins是java产品,需安装JDK8.由于.netFreamwork项目自动化时是基于Windows,所以继续使用Windows server 2012环境下的已有的Jenkins,部署.构建dotnet Core项目继续在Windows平台下操作.2) .NET Core SDK:2.2.402.dotnet build构建.3) 代码仓库GitLab.4) .NET Core服务端CentOS7部署环境流程: 需求一个项目下分两个子项目,而子项目需分别进行构建部署

利用Fabric+Capistrano实现Python自动化部署

Fabric是一个用于应用(批量)部署和系统(批量)管理的Python库和命令行工具,关于Fabric的介绍请参考:http://www.fabfile.org/. Capistrano是一个用Ruby语言编写的远程服务器自动化和部署工具,关于Capistrano的介绍请参考:http://capistranorb.com/. 本文仅使用Python语言和部分Linux或Windows系统命令,借助Fabric模块和Capistrano的部署思路,实现在Linux平台和Windows平台的自动化

python部署工具fabric

两台机器:10.1.6.186.10.1.6.159.fabric部署在10.1.6.186上面 1  执行和1相同的任务,不过排除掉10.1.6.159这台机器 1 #!/usr/bin/python 2 from fabric.api import * 3 from fabric.context_managers import * 4 5 env.hosts=['10.1.6.186','10.1.6.159'] 6 env.password='xxxxxx' 7 env.exclude_h

自动化部署工具——Ansible二次探索

playbook简介     playbook是ansible用于配置.部署和管理被控节点的剧本,通过playbook的详细描述,执行其中的一系列tasks,可以让远程主机达到预期的状态,playbook就像Ansible控制器给被控节点列出的一系列to-do-list,而被控节点必须要完成. 也可以这样理解,pplaybook是由一个或多个"play"组成的列表.play的主要功能在于将事先归并为一组的主机装扮成事先通过ansible中的task定义好的角色.从根本上来讲所谓task

持续集成部署工具jenkins简介

1. Jenkins基本介绍 Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能.现在企业一般使用jenkins落实持续集成.持续部署.持续交付.也可以利用jenkins实现docker自动化流水 2. 安装gitlab gitlab部署 参考 https://blog.51cto.com/flyfish225/2145495下载gitlab 最新版https://packages.gitlab

java自动化配置工具 - autoconfig 简介

对于java程序员来说各种各样的配置文件是司空见惯的,比如spring的bean配置,struts的action配置等等.有些配置会随着运行环境的变化而各不相同,最典型的就是jdbc驱动的配置,在开发环境可能链接到开发本地的数据库,测试环境则有一套测试专用的数据库环境,线上的生产环境也会有一套数据库,如果一个应用要部署到多个idc中,那这些配置又有可能各不相同.解决这个问题,可能有些团队使用同一份配置文件,在部署到不同的环境之前人肉的修改一下配置,还有些团队会为每一个环境维护一份配置文件.这些做

Capistrano自动化部署工具安装详细过程

Capistrano是一种通过ssh向多个服务器部署web应用的一种框架和工具.具体更详细的介绍,大家可以登录官方网站或其它相关网站进行了解. 一.软件版本 1. 操作系统:CentOS6.8最小化安装 2. Ruby:2.4.0 3. gem:2.6.10 4. capistrano:3.7.2 二.安装ruby 1. 下载 wget https://cache.ruby-lang.org/pub/ruby/2.4/ruby-2.4.0.tar.gz (请先安装wget: yum instal

大规模集群自动化部署工具--Chef的安装部署

Chef脚本管理工具部署 部署节点 节点类型 IP(虚拟假设的IP) Server 192.168.10.191 Workstation 192.168.10.36 Node 192.168.10.35 安装的版本 Chef-Server:chef-server-11.1.0-1.el6.x86_64.rpm Chef-Client:chef-11.10.0-1.el6.x86_64.rpm 安装前需要了解的 首先Chef的官网有许多的发布版本,首先按照操作系统类别来分主要有Red Hat和Ub

Python自动化部署

# -*- coding: utf-8 -*- #!/bin/env python ''' #Auth: tyk #Function: released version #Date:2017/6/27 #Version:V1.0 ''' import  sys,re,os,time,datetime import  paramiko import logging import socket import ConfigParser import traceback from progressbar