背景:
关于Fabric的介绍,可以看官网说明。简单来说主要功能就是一个基于Python的服务器批量管理库/工具,Fabric 使用 ssh(通过 paramiko 库)在多个服务器上批量执行任务、上传、下载。在使用Fabric之前,都用Python的paramiko模块来实现需求,相比之后发现Fabric比paramiko模块强大很多。具体的使用方法和说明可以看官方文档介绍。下面写类一个用paramiko(apt-get install python-paramiko)封装的远程操作类的模板:
#!/usr/bin/python # -*- encoding: utf-8 -*- import paramiko import sys reload(sys) sys.setdefaultencoding('utf8') class Remote_Ops(): def __init__(self,hostname,ssh_port,username='',password=''): self.hostname = hostname self.ssh_port = ssh_port self.username = username self.password = password #密码登入的操作方法 def ssh_connect_exec(self,cmd): try: ssh_key = paramiko.SSHClient() ssh_key.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_key.connect(hostname=self.hostname, port=self.ssh_port, username=self.username, password=self.password, timeout=10) # paramiko.util.log_to_file('syslogin.log') except Exception, e: print('Connect Error:ssh %s@%s: %s' % (self.username, self.hostname, e)) exit() stdin, stdout, stderr = ssh_key.exec_command(cmd,get_pty=True) #切换root stdin.write(self.password+'\n') stdin.flush() err_list = stderr.readlines() if len( err_list ) > 0: print 'ERROR:' + err_list[0] exit() # print stdout.read() for item in stdout.readlines()[2:]: print item.strip() ssh_key.close() #ssh登陆的操作方法 def ssh_connect_keyfile_exec(self,file_name,cmd): try: ssh_key = paramiko.SSHClient() ssh_key.set_missing_host_key_policy(paramiko.AutoAddPolicy()) ssh_key.connect(hostname=self.hostname, port=self.ssh_port, key_filename=file_name, timeout=10) # paramiko.util.log_to_file('syslogin.log') except Exception, e: print e exit() stdin, stdout, stderr = ssh_key.exec_command(cmd) err_list = stderr.readlines() if len( err_list ) > 0: print 'ERROR:' + err_list[0] exit() for item in stdout.readlines(): print item.strip() ssh_key.close() if __name__ == '__main__': #密码登陆的操作方法: test = Remote_Ops('10.211.55.11', 22, 'zjy', 'zhoujinyi') test.ssh_connect_exec('sudo ls -lh /var/lib/mysql/') #ssh key登陆的操作方法:(需要到root下运行) file_name = '/var/root/.ssh/id_rsa' test1 = Remote_Ops('10.211.55.11', 22) test1.ssh_connect_keyfile_exec(file_name,'apt-get update')
关于更多的paramiko信息可以看官方文档和python运维之paramiko、python远程连接paramiko 模块。本文将要介绍的是Fabric的使用方法。
说明:
1.安装
$ pip install fabric
OR
$ sudo apt-get install fabric
2.参数(fab -h)
~$ fab -h Usage: fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ... #命令行的使用方法 Options: -h, --help show this help message and exit -d NAME, --display=NAME print detailed info about command NAME -F FORMAT, --list-format=FORMAT formats --list, choices: short, normal, nested -I, --initial-password-prompt Force password prompt up-front --initial-sudo-password-prompt Force sudo password prompt up-front -l, --list print list of possible commands and exit #显示出可以执行的命令函数名 --set=KEY=VALUE,... comma separated KEY=VALUE pairs to set Fab env vars --shortlist alias for -F short --list -V, --version show program's version number and exit -a, --no_agent don't use the running SSH agent -A, --forward-agent forward local agent to remote end --abort-on-prompts abort instead of prompting (for password, host, etc) #出现提示就中指,如密码、主机提示 -c PATH, --config=PATH specify location of config file to use --colorize-errors Color error output #输出颜色错误 -D, --disable-known-hosts do not load user known_hosts file -e, --eagerly-disconnect disconnect from hosts as soon as possible -f PATH, --fabfile=PATH #指定fab执行的文件,默认是fabfile.py python module file to import, e.g. '../other.py' -g HOST, --gateway=HOST #指定堡垒机(中转机)的地址 gateway host to connect through --gss-auth Use GSS-API authentication --gss-deleg Delegate GSS-API client credentials or not --gss-kex Perform GSS-API Key Exchange and user authentication --hide=LEVELS comma-separated list of output levels to hide #output隐藏的等级设置,多个等级逗号分隔 -H HOSTS, --hosts=HOSTS #指定操作的服务器,多个用逗号分隔 comma-separated list of hosts to operate on -i PATH path to SSH private key file. May be repeated. #指定私钥文件 -k, --no-keys don't load private key files from ~/.ssh/ --keepalive=N enables a keepalive every N seconds # --linewise print line-by-line instead of byte-by-byte -n M, --connection-attempts=M make M attempts to connect before giving up --no-pty do not use pseudo-terminal in run/sudo -p PASSWORD, --password=PASSWORD #指定远程登陆的密码包括sudo password for use with authentication and/or sudo -P, --parallel default to parallel execution method #指定是否并行执行的 --port=PORT SSH connection port #指定ssh的默认端口 -r, --reject-unknown-hosts #指定拒绝的主机 reject unknown hosts --sudo-password=SUDO_PASSWORD #指定sudo密码 password for use with sudo only --system-known-hosts=SYSTEM_KNOWN_HOSTS load system known_hosts file before reading user known_hosts -R ROLES, --roles=ROLES #指定role,以role来区分不同执行函数 comma-separated list of roles to operate on -s SHELL, --shell=SHELL #指定的shell的执行环境, specify a new shell, defaults to '/bin/bash -l -c' --show=LEVELS comma-separated list of output levels to show #指定显示output的等级,多个用逗号分隔 --skip-bad-hosts skip over hosts that can't be reached #指定跳过不能到达的主机 --skip-unknown-tasks skip over unknown tasks #指定跳过不识别的执行函数 --ssh-config-path=PATH #指定ssh配置文件的路径 Path to SSH config file -t N, --timeout=N set connection timeout to N seconds #指定连接超时时间 -T N, --command-timeout=N #指定远程命令超时时间 set remote command timeout to N seconds -u USER, --user=USER username to use when connecting to remote hosts #指定远程登陆用户 -w, --warn-only warn, instead of abort, when commands fail #指定命令错误发出警告而不是中止 -x HOSTS, --exclude-hosts=HOSTS comma-separated list of hosts to exclude #指定排除的主机 -z INT, --pool-size=INT number of concurrent processes to use in parallel mode #指定并发线程的数量
使用
①:命令行接口
~$ fab -u zjy -p zhoujinyi -H 10.211.55.9,10.211.55.11 -- 'ls -lh /tmp/'
效果:
[10.211.55.9] Executing task '<remainder>' [10.211.55.9] run: ls -lh /tmp/ [10.211.55.9] out: 总用量 16K [10.211.55.9] out: -rw-rw-r-- 1 zjy zjy 853 11月 10 18:42 change_pwd.py [10.211.55.9] out: [10.211.55.11] Executing task '<remainder>' [10.211.55.11] run: ls -lh /tmp/ [10.211.55.11] out: 总用量 12K [10.211.55.11] out: -rw-rw-r-- 1 zjy zjy 2.4K 11月 10 18:29 remote_ops.py [10.211.55.11] out:
不推荐使用命令行,最好都写到一个文件脚本里,方便也安全。
②:脚本
注:默认fabric使用一个名为fabfile.py文件里,如:
#!/usr/bin/python from fabric.api import local, lcd def lsfab(): with lcd('/tmp/'): local('ls')
效果:
[localhost] local: ls
com.apple.launchd.ESurbfatee com.apple.launchd.ykbSkcZdfZ mykey.txt parallels_crash_dumps
Done.
如果写到其他文件则需要通过-f来指定执行:
~$ mv fabfile.py ttt.py
~$ fab -f ttt.py lsfab
③:参数
定义的执行函数里带参数:
#!/usr/bin/python from fabric.api import * def hello(name,age): print "hello,%s,%s" %(name,age)
带参数的执行函数执行:
~$ fab hello:zhoujy,123 hello,zhoujy,123 Done.
④:模块说明
1:from fabric.api import * local #执行本地命令,如local('uname -s') lcd #切换本地目录,如lcd('/home') cd #切换远程目录,如cd('/var/logs') run #执行远程命令,如run('free -m') sudo #sudo方式执行远程命令,如sudo('/etc/init.d/httpd start') put #上次本地文件导远程主机,如put('/home/user.info','/data/user.info') get #从远程主机下载文件到本地,如:get('/data/user.info','/home/user.info') prompt #获得用户输入信息,如:prompt('please input user password:') confirm #获得提示信息确认,如:confirm('Test failed,Continue[Y/N]?') reboot #重启远程主机,如:reboot() @task #函数修饰符,标识的函数为fab可调用的,非标记对fab不可见,纯业务逻辑 @runs_once #函数修饰符,标识的函数只会执行一次,不受多台主机影响 @roles() #运行指定的角色组里,通过env.roledefs里的定义
2:from fabric.colors import * print blue(text) print cyan(text) print green(text) print magenta(text) print red(text) print white(text) print yellow(text) 3:
...
用到再补充 ...
基础实例说明
实例1: 本地操作
from fabric.api import * def lsfab(): with lcd('/tmp/'): #本地切换目录 local('ls') #本地执行命令 def host_name(): local('uname -s') #本地执行命令
用-l查看可以执行的命令函数:
~$ fab -f fab_ops.py -l Available commands: host_name lsfab
可以执行上面2个执行函数,执行:
~$ fab -f fab_ops.py host_name [localhost] local: uname -s Darwin Done.
上面2个函数合并,并且对外只显示一个执行入口函数(@task):
from fabric.api import * def lsfab(): with lcd('/tmp/'): local('ls') def host_name(): local('uname -s') @task def go(): lsfab() host_name()
执行:
~$ fab -f fab_ops.py go [localhost] local: ls com.apple.launchd.ESurbfatee com.apple.launchd.ykbSkcZdfZ parallels_crash_dumps [localhost] local: uname -s Darwin Done.
实例2:远程操作,env变量
from fabric.api import * #配置远程服务器 env.hosts = [ '10.211.55.9', '10.211.55.11' ] #端口 env.port = '22' #用户 env.user = 'zjy' #密码,远程服务器密码都一样 env.password = 'zhoujinyi' def lsfab(): with cd('/tmp/'): #远程切换目录 run('ls') #远程命令运行 def host_name(): run('uname -s') @task def go(): lsfab() host_name()
执行看到的信息:执行的函数,命令和命令的输出结果。
~$ fab -f fab_ops.py go [10.211.55.9] Executing task 'go' [10.211.55.9] run: ls [10.211.55.9] out: 1 2 3 [10.211.55.9] out: [10.211.55.9] run: uname -s [10.211.55.9] out: Linux [10.211.55.9] out: [10.211.55.11] Executing task 'go' [10.211.55.11] run: ls [10.211.55.11] out: a b c mongodb-27017.sock [10.211.55.11] out: [10.211.55.11] run: uname -s [10.211.55.11] out: Linux [10.211.55.11] out: Done. Disconnecting from 10.211.55.11... done. Disconnecting from 10.211.55.9... done.
远程机器的密码不一致,怎么配置?这时可以用env.passwords来替换env.password:注意格式:user@ip:pwd
env.passwords = { 'zjy@10.211.55.9:22' : 'zjy', 'zjy@10.211.55.11:22': 'zhoujinyi', }
实例3:如何让不同服务器组执行不同的操作?如DB和WEB服务器各自执行自己的操作。这里需要用env.roledefs来定义角色组,根据不同的roles来使用execute进行不同的操作。
#!/usr/bin/python # -*- encoding: utf-8 -*- from fabric.api import * #定义角色,操作一致的服务器可以放在一组。因为服务器的用户端口不一样,需要在role里指定用户、IP和端口 env.roledefs = { 'dbserver':['zjy@10.211.55.9:22','zjy@10.211.55.11:22'], 'webserver':['zhoujy@192.168.200.25:221'], } #密码,远程服务器密码不一致时使用,格式user@host:port:pwd env.passwords = { 'zjy@10.211.55.9:22' : 'zjy', 'zjy@10.211.55.11:22': 'zhoujinyi', 'zhoujy@192.168.200.25:221':'123456', } @task #入口 @roles('dbserver') #角色修饰符 def get_memory(): run('free -m') @task @roles('webserver') def mkfile_task(): with cd('/home/zhoujy/'): run('touch xxxx.log')
执行效果:执行get_memory函数,在dbserver中的主机上执行,mkfile_touch函数则在webserver中的主机上执行。
通过env.roledefs和env.passwords指定好了用户名、端口和密码,这时上面2个函数合并,并且对外只显示一个执行函数(@task),还要注意的是因为各自的执行函数处于不同的roles下执行的,要放到一个函数里执行,需要添加:execute(),这样可以在一个执行函数里操作多个远程的机器。
... ... @task def go(): execute(get_memory) execute(mkfile_task)
效果:
[zjy@10.211.55.9:22] Executing task 'get_memory' [zjy@10.211.55.9:22] run: free -m [zjy@10.211.55.9:22] out: total used free shared buffers cached [zjy@10.211.55.9:22] out: Mem: 990 749 241 0 17 136 [zjy@10.211.55.9:22] out: -/+ buffers/cache: 595 395 [zjy@10.211.55.9:22] out: Swap: 1021 0 1021 [zjy@10.211.55.9:22] out: [zjy@10.211.55.11:22] Executing task 'get_memory' [zjy@10.211.55.11:22] run: free -m [zjy@10.211.55.11:22] out: total used free shared buffers cached [zjy@10.211.55.11:22] out: Mem: 3949 943 3006 0 13 230 [zjy@10.211.55.11:22] out: -/+ buffers/cache: 699 3249 [zjy@10.211.55.11:22] out: Swap: 1021 0 1021 [zjy@10.211.55.11:22] out: [zhoujy@192.168.200.25:221] Executing task 'mkfile_task' [zhoujy@192.168.200.25:221] run: touch fabric.log Done. Disconnecting from zhoujy@192.168.200.25:221... done. Disconnecting from zjy@10.211.55.11... done. Disconnecting from zjy@10.211.55.9... done.