Python遠程部署工具Fabric詳解

簡介

Fabric是Python的一個模塊,基於SSH提供了豐富的交互接口,能夠用來在本地或遠程機器上自動化的執行Shell命令,很是適合用來作應用的遠程部署及系統維護。php

fabric底層基於paramiko(paramiko是用於ssh鏈接的庫)。java

應用

安裝Fabric

$ pip install fabric
複製代碼

小試牛刀

Fabric默認的腳本文件是fabfile.py,建立該文件並定義以hello函數:python

def hello():
    print("Hello Fabric!")
複製代碼

可使用參數-l來列出當前fabfile.py中定義了哪些任務,而後在fabfile.py目錄下執行命令能夠看到輸出結果:nginx

$ fab -l
Available commands:

    hello
    
$ fab hello
Hello Fabric!

Done.
複製代碼

fabfile.py中每一個函數表明一個任務,任務名即函數名。fab命令用來執行fabfile.py中定義的任務,它必須顯示的指定任務名。web

任務也能夠帶參數,好比咱們將hello函數改成:shell

def hello(name, value):
    print("Hello Fabric! %s %s." % (name, value))
複製代碼

此時執行hello任務時須要傳入參數:api

$ fab hello:name=Year,value=2017
複製代碼

fabric默認執行的腳本是fabfile.py,若是要換腳本文件須要使用-f指定。好比咱們將hello任務放到script.py中就要執行:安全

$ fab -f script.py hello:name=Year,value=2017
複製代碼

執行本地命令

fabfile.py內容以下:bash

#-*- coding:utf-8 -*-
from fabric.api import local

def taskA():
    local('touch fab.out && echo "fabric" >> fab.out')

def taskB():
    # capture參數能夠捕獲標準輸出存到變量,默認爲False
    output = local('echo "Hello World."', capture=True)
    print output
複製代碼

執行任務:服務器

$ fab taskA taskB
複製代碼

執行遠程命令

Fabric真正強大在於能夠很方便的執行遠程機器上的Shell命令,它基於SSH實現。

#-*- coding:utf-8 -*-
from fabric.api import run, env

# env被稱爲環境字典,用來配置一些運行環境相關的信息
env.hosts = ['192.168.1.100', '192.168.1.101']
env.user = 'user'
env.password = 'passwd'

def taskA():
    run('cd /usr/local/webserver/php && ls -l')
    run('sudo /usr/local/webserver/nginx/sbin/nginx -t')
複製代碼

env.hosts是設置機器列表的,也能夠把用戶直接寫到hosts裏:

env.hosts = ['user@192.168.1.100', 'user@192.168.1.101']
複製代碼

若是代碼中沒有設置env.hosts,也能夠在執行任務時經過-H參數進行指定:

$ fab -H 192.168.1.100 taskA
複製代碼

環境字典fabric.state.env是做爲全局單例實現的,爲方便使用也包含在fabric.api中。env中的鍵一般也被稱爲環境變量。

幾個經常使用的環境變量以下:

  • user:能夠經過設置env.user來指定Fabric創建SSH鏈接時使用的用戶名(默認使用本地用戶名)。
  • password:用來顯式設置默認鏈接或者在須要的時候提供sudo密碼。若是沒有設置密碼或密碼錯誤,Fabric將會提示你輸入。
  • passwords:密碼字典,針對不一樣的機器設置密碼。
  • warn_only:布爾值,用來設置Fabric是否在檢測到遠程錯誤時退出。
  • hosts:全局主機列表。
  • roledefs:定義角色名和主機列表的映射字典。

若是對於不一樣的服務器想執行不一樣的任務,上面的程序就作不到了,咱們須要對服務器定義角色:

#-*- coding:utf-8 -*-
from fabric.api import env, roles, run, execute, cd

env.roledefs = {
    'dev': ['user1@10.216.224.65', 'user2@10.216.224.66'],
    'online': ['user3@45.33.108.82']
}

# host strings必須由username@host:port三部分構成,缺一不可,不然運行時仍是會要求輸入密碼
env.passwords = {
    'user1@10.216.224.65:22': 'passwd1',
    'user2@10.216.224.66:22': 'passwd2',
    'user3@45.33.108.82:22': 'passwd3'
}

@roles('dev')
def taskA():
    with cd('/usr/local/webserver'):
        run('pwd')

@roles('online')
def taskB():
    run('pwd')

def task():
    execute(taskA)
    execute(taskB)
複製代碼

而後執行task任務便可:

$ fab task
複製代碼

Fabric會在dev機器上執行taskA任務,而後在online機器上執行taskB任務。@roles裝飾器指定了它所裝飾的任務會被哪一個角色的服務器執行。

SSH自動登錄

上面的例子都是將登錄密碼寫到腳本文件裏的,這樣作不安全,推薦的方法是設置SSH KEY自動登錄。登錄本地機器生成KEY:

$ ssh-keygen -t rsa -f ~/.ssh/id_rsa_fabric
複製代碼

生成密鑰對以後將公鑰添加到遠程服務器的~/.ssh/authorized_keys文件中,就能夠實現自動登錄了。

#-*- coding:utf-8 -*-
from fabric.api import env, roles, run, execute, cd

env.hosts = ['10.216.224.65', '10.216.224.66']
env.user = 'user'
env.key_filename = '~/.ssh/id_rsa_fabric'

def taskA():
    with cd('/usr/local/webserver'):
        run('pwd')
複製代碼

authorized_keys文件權限只全部者可寫,其餘用戶均無寫權限,不然sshd將認爲不安全不容許使用該文件致使還須要輸入密碼認證。

上下文管理器

Fabric的上下文管理器是一系列與Python的with語句配合使用的方法,它能夠在with語句塊內設置當前工做環境的上下文。

#-*- coding:utf-8 -*-
from fabric.api import env, lcd, local, cd, path, settings, shell_env, prefix, sudo, run

env.hosts = ['10.216.224.66']
env.user = 'user'
env.key_filename = '~/.ssh/id_rsa_fabric'

def task():
    # 設置本地工做目錄
    with lcd('/usr/local/webserver'):
        local('touch local.out')

    # 設置遠程機器的工做目錄
    # sudo功能相似run方法,以超級用戶權限執行遠程命令
    with cd('/usr/local/webserver'):
        sudo('touch remote.out')

    # 添加遠程機器的path路徑
    # 出了with語句path又回到原來的值
    with path('/usr/local/webserver'):
        run('echo $PATH')
    run('echo $PATH')

    # 設置Fabric環境變量參數
    # fabric.api.env
    # warn_only設置爲True,遇到錯誤不會退出
    with settings(warn_only=True):
        run('echo $USER')

    # shell_env能夠用來臨時設置遠程和本機上的Shell環境變量
    with shell_env(JAVA_HOME='/opt/java'):
        run('echo $JAVA_HOME')
        local('echo $JAVA_HOME')

    # 設置命令執行前綴,等同於 run('echo Hi && pwd')
    with prefix('echo Hi'):
        run('pwd')
        local('pwd')
複製代碼

錯誤處理

默認狀況下,Fabric在任務遇到錯誤時就會退出,若是咱們但願捕獲這個錯誤而不是退出任務的話,就要開啓warn_only參數。在上面介紹settings()上下文管理器時,咱們已經看到了臨時開啓warn_only的方法了,若是要全局開啓,有兩個方法:

  1. 在執行fab時加上-w參數
$ fab -w task
複製代碼
  1. 設置env.warn_only環境參數爲True
#-*- coding:utf-8 -*-
from fabric.api import env

env.warn_only = True
複製代碼

如今遇到錯誤時,控制檯會打出一個警告信息,而後繼續執行後續任務。那咱們怎麼捕獲錯誤並處理呢?像local/run/sudo/get/put等函數都有返回值,當返回值的succeeded屬性爲True時,說明執行成功,反之就是失敗;也能夠檢查返回值的failed屬性,爲True表示執行失敗,有錯誤發生。

#-*- coding:utf-8 -*-
from fabric.api import env, local, cd, put

env.hosts = ['10.216.224.66']
env.user = 'liuzhen'
env.key_filename = '~/.ssh/id_rsa_fabric'
env.warn_only=True

def task():
    with cd('/data/server'):
    	local('touch /data/server/README.md')
    	upload = put('/data/server/README.md', 'README.md')
    	if upload.failed:
    	    put('/data/server/README.md', 'README.md', use_sudo=True)
複製代碼

並行執行

Fabric在多臺機器上執行任務時默認狀況下是串行的。Fabric支持在多臺服務器上並行執行任務,並行能夠有效的加快執行速度。開啓並行執行有以下兩個方法:

  1. 在執行fab命令時加上-w參數
$ fab -P task
複製代碼
  1. 設置env.parallel環境參數爲True
#-*- coding:utf-8 -*-
from fabric.api import env
env.parallel = True
複製代碼

以上是對任務並行作一個全局控制。若是隻想對某一個任務作並行的話,咱們能夠在任務函數上加上@parallel裝飾器,這樣即使全局並行未開啓,被@parallel裝飾的任務也會並行執行:

#-*- coding:utf-8 -*-
from fabric.api import env, run, parallel

env.hosts = ['10.216.224.65', '10.216.224.66']
env.user = 'user'
env.key_filename = '~/.ssh/id_rsa_fabric'

@parallel
def taskA():
    run('echo "parallel"')

def taskB():
    run('echo "serial"')
複製代碼

假如全局並行已開啓,咱們想讓某個任務串行執行,咱們能夠在任務函數上加上@serial裝飾器,這樣即使並行已開啓,被@serial裝飾的任務也會串行執行:

#-*- coding:utf-8 -*-
from fabric.api import env, run, serial

env.hosts = ['10.216.224.65', '10.216.224.66']
env.user = 'user'
env.key_filename = '~/.ssh/id_rsa_fabric'
env.parallel = True

def taskA():
    run('echo "parallel"')

@serial
def taskB():
    run('echo "serial"')
複製代碼

Fabric常規用法這裏就基本介紹完了,詳細的能夠參考官方文檔。

相關文章
相關標籤/搜索