自动化运维管理fabric
自动化日常管理任务和部署">如何使用fabric 自动化日常管理任务和部署
自动化,批量化是作为管理员,或者运维人员必须面临的问题。自动化和批量化也有很多方式,可以用单一工具也可以自己写shell脚本,甚至可以开发出来一套完备的任务管理系统。其实我们大多时候可以在一台主机上面通过ssh来控制所有机器,来完成我们的任务工作。是否有这样的工具来支持我们呢?
fabric 常用接口
fabric是对ssh的一个集成工具,对我们而言只需要使用相应的接口,来高效的完成工作,我们常用到的功能基本是 : 本地或者远端执行命令, 分发文件,收集文件,还有一些权限相关的操作。 这些fabric都给我们提供了对应的接口。
如下所示:
run (fabric.operations.run) sudo (fabric.operations.sudo) local (fabric.operations.local) get (fabric.operations.get) put (fabric.operations.put) prompt (fabric.operations.prompt) reboot (fabric.operations.reboot)
fabric 还提供了上下文管理器
接口部分提供了命令运行的方式,不过都无法保持上下文关系,为了解决这个问题,fabric的context manager 就派上了用场:
cd (fabric.context_managers.cd) lcd (fabric.context_managers.lcd) path (fabric.context_managers.path) settings (fabric.context_managers.settings) prefix (fabric.context_managers.prefix)
fabric 安装
easy_install fabric
fabric 编程模型介绍
由于fabric是基于python的,所以写fabric脚本就是写python脚本,你可以像写python脚本一样,可以依赖其他模块或者其他工具来完成工作。Fabric 脚本,通过fab工具运行fabric python脚本。fab工具默认执行fabfile.py ,也可以通过-f 参数指定 脚本文件名。fabric优势多多,简单,方便,日志输出清晰,命令
中可以使用AWK 命令 下面我们看一个 hello world 程序。
from fabric.api import * def helloworld(who='world'): print "Hello {0}!".format(who) def helloworld1(you='world',me='ruiaylin'): print "Hello {0}! i am {1} ! ".format(you,me)
执行命令(其中参数的传递直接跟在任务后跟变量名和参数):
➜ fabric fab -f helloword.py helloworld Hello world! Done. ➜ fabric fab -f helloword.py helloworld1:you='ruichao',me='ruiaylin' Hello ruichao! i am ruiaylin ! Done.
fabric主要接口方法
我们已经看了一个简单例子下面我们来看一下fabric的主要接口。
run (fabric.operations.run)
Fabric 中使用最多的就是 run 方法了。run是用来在一台或者多台远程主机上面执行shell 命令。
- 方法的返回值是可以通过变量来进行捕获
- 可以通过变量的.failed 和 .succeeded 来检查命令是否执行成功
- 还有一个很赞的就是 run 方法中执行命令的时候,可以支持awk 很给力
使用方法:
# creat a directory run(" mkdir /tmp/testdir/ -p ") # check process result = run("ps -ef |grep mysqld|grep -v safe |grep -v grep | wc -l " #Check if command result.failed
sudo (fabric.operations.sudo)
使用 sudo 命令执行对顶的命令。使用方法与run 类似。
local (fabric.operations.local)
local 命令是执行本机的命令或者脚本.使用方法和run 还有sudo类似,但是有一个区别
就是: 捕获结果的时候,是通过指定 capture=False 或者capture=True来确定。来看
实例:
# example like this : def helloworld(who='world'): print "Hello {0}!".format(who) yy = local(" pwd ", capture=False) print 'start : yy = ' , yy , ' : :: ',yy.succeeded zz = local(" pwd ", capture=True) print 'start : zz = ' , zz , ' : :: ',zz.succeeded #result : ➜ fabric fab -f helloword.py helloworld -H 10.211.55.3 -u root [10.211.55.3] Executing task 'helloworld' Hello world! [localhost] local: pwd /Users/ruiaylin/Documents/workpython/fabric start : yy = : :: True [localhost] local: pwd start : zz = /Users/ruiaylin/Documents/workpython/fabric : :: True
get (fabric.operations.get)
get 方法是从远程主机 copy file 到本地,功能跟scp一样。可以从远程主机下载
备份,或者日志文件等等。
- 通过参数 remote_path 指定远程文件的路径
- 通过参数 local_path 指定远程文件的路径
使用方法如下:
# Download some logs get(remote_path="/tmp/xxx.log", local_path="/tmp/xxx.log") # Download a database back-up get("/backup/db.gz", "./db.gz")
put (fabric.operations.put)
某些需要上传和分发文件的时候,put命令就派上了用场,使用方式类似 get。也同样可以
通过.failed .succeeded进行命令是否执行成功的判断。
- local_path - 本地路径
- remote_path - 远程路径
- mode - 文件属性
如下例子:
upload = put("requirements.txt", "requirements.txt", mode=0664)
并行执行
目前官方来看 1.X 版本的fabric 并行执行的时候不是thread safe的。如果需要并行执行task。需要在方法上面使用注解 @parallel 为了防止管控机器上面过多的并发任务可以通过 @parallel(pool_size=5)来设置. 并行的执行输出都会输出到一个终端上面,比较混乱。最好是写到日志,以task为维度。跟下面的代码类似。
MySQL 安装实例
安装步骤如下
- 获取主机ip
- check主机可达性
- 检查linux平台详情
- 是否有运行的mysql实例
- 如果有获取对应的端口
- 检查是否和要安装的端口冲突
- 处理mysql用户以及属组
- 处理安装相关目录和权限
- copy 安装包到目标机
- 解压处理,将主要软件工具软连接到path路径中
- 生成对应标准配置文件并分发到目标机对应目录
- 初始化数据库
- 启动数据库
- 基本步骤安装完毕
基本脚本如下:
script 1 sub task :
from fabric.api import * from fabric.colors import green,red,blue,cyan,yellow import os , sys import socket import datetime import logging import logging.handlers #get logger for logging def initLoggerWithRotate(): logname=''.join(env.host_string.split('.'))+'.log' logFileName="logs/%s"%logname logger = logging.getLogger("fabric") formater = logging.Formatter("%(asctime)s %(name)s %(levelname)s %(message)s","%Y-%m-%d %H:%M:%S") file_handler = logging.handlers.RotatingFileHandler(logFileName, maxBytes=104857600, backupCount=5) file_handler.setFormatter(formater) stream_handler = logging.StreamHandler(sys.stderr) logger.addHandler(file_handler) logger.addHandler(stream_handler) logger.setLevel(logging.INFO) return logger #mkdir def runmkdir(dir): run(''' mkdir -p %s '''%dir) #stp 1 check host def checkhost(logger): host = env.host_string s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) flag_c = 0 try: s.connect((host, 22)) flag_c = 1 logger.info( green( ' --> host %s can be reachable ' %host ) ) except socket.error as e: logger.warning( yellow( ' --> Error on connect %s' %e ) ) s.close() return flag_c #stp 2 check alive instance on target host def checkmysqlinstance(logger): try: wc = run(''' ps -ef |grep mysqld|grep -v safe | grep -v grep | wc -l ''') if int(wc) > 0 : logger.warning(yellow( ' --> %sinstance exist on the target host '%wc )) portraw = run(''' ps -ef |grep mysqld|grep -v safe |grep -v grep |awk ' {for(i=1;i<=NF;i++){if($i ~/--port/ ){print $i}}}' |awk -F '=' '{print $2}' ''') ports = [x.strip() for x in portraw.split() ] logger.warning( yellow( ' --> existing instance port : [ %s ] '%( ','.join( ports )))) if port in ports: logger.error( red( ' --> Install port %s exist , install failed '%port)) logger.error( red( ' <<<exit>>>>> task on host %s stop & exit() '%thost)) sys.exit() except Exception, e: logger.warning(yellow( ' --> checkmysqlinstance() exception : %s '%e )) raise e #stp 3 initdir for installation def createUser(logger,user='mysql',group='dba'): try: if int(run('grep "^mysql" /etc/passwd|wc -l')) == 0 : run('groupadd dba ') run('useradd -c "mysql software owner" -g dba -G dba mysql') run('mkdir -p /home/mysql ; chown -R mysql.dba /home/mysql ') logger.info(cyan( ' --> create user [ mysql ] in group [ dba ] success ' )) else : logger.info(yellow ( ' --> user [ mysql ] in group [ dba ] exist & skip ' )) except Exception, e: logger.warning(yellow( ' --> createUser() exception : %s '%e )) raise e #stp 4 initail directory for mysql def initdir(logger,port=3306): try : logger.info( green( ' --> begin to create dirs for installation ')) datadir='/data/' logdir ='/log/' mandir = 'mysql%s'%port subddir ='/data/mysql%s/{data,log,run,tmp}'%(port) subldir ='/log/mysql%s/{binlog,iblog}'%(port) #data ck1 = run(' df -vh | grep /data | wc -l ') if ck1 == 0 : logger.error(green(' --> no /data/ partition exist' ) ) #sys.exit() if int( run(' ls / | grep /data | wc -l ')) == 0 or int( run(' ls /data/ | grep -w %s | wc -l '%mandir) ) == 0 : runmkdir(subddir) logger.info(green(' --> /data/*** create Ok ' ) ) else : logger.info(green(' --> /data/mysql%s exsit '%port )) logger.info(green(' --> pls,handle it and restart this task ')) sys.exit() #log ck2 = run(' df -vh | grep /log/ | wc -l ') if int( run(' df -vh | grep /log/ | wc -l ') ) == 0 and int( run(' ls / | grep -w log | wc -l ') ) == 0: logger.warning( yellow(' --> no /log/ partition exist') ) logger.warning( yellow(' --> create link for /log/ --> /data/log/') ) runmkdir('/data/log') run('ln -s /data/log /log ') runmkdir(subldir) logger.info(green(' --> /log/*** create Ok ' ) ) else : if int(run(' ls /log/ | grep -w %s | wc -l '%mandir)) == 0: runmkdir(subldir) logger.info(green(' --> /log/*** create Ok ' ) ) else : logger.info(yellow(' --> /log/mysql%s exsit '%port )) logger.error(red(' --> pls,handle it and restart this task ' )) sys.exit() #change runmkdir('/data/tmp') logger.info(green(' --> change dirs owner&privs start')) run('chown -R mysql:dba /data/*') run('chown -R mysql:dba /log') logger.info(green(' --> change dirs owner&privs done')) except Exception, e: logger.warning(yellow( ' --> initdir() exception : %s '%e )) raise e #stp 5 put mysql install package def copymysql(logger,version='5.7'): try: dits = { 'ubuntu':'mysql-server_5.6.21-1ubuntu12.04_amd64.deb-bundle.tar', 'centos':'mysql-server.tar.gz' } issue = run ('cat /etc/issue') ss = issue.lower() logger.info( green( ' %s '%ss)) if int ( run( ' ls /usr/local/ | grep mysql | wc -l ') ) > 0 : logger.info( yellow( ' --> mysql software installed , skip ' )) return plats = dits.keys() for x in plats: if ss.find(x) != -1: logger.info( green( ' --> the target host platform is %s'% x ) ) put( local_path="configs/%s"%dits[x],remote_path="/tmp/%s"%dits[x] ) logger.info( green( ' --> tar the ball to prop dir ')) run( 'tar zxvf /tmp/%s -C /usr/local/ '%dits[x] ) run( 'ln -s /usr/local/%s /usr/local/mysql '%dits[x][:-7] ) break except Exception, e: logger.warning(yellow( ' --> copymysql() exception : %s '%e )) raise e #gen my.cnf file def getnewServerId(logger,port): host = env.host_string print 'getnewServerId : ',host pics = host.split('.') a=int(pics[0]) b=int(pics[1]) c=int(pics[2]) d=int(pics[3]) suf = int(port) % 256 server_id = b * 256 * 256 * 256 + c * 256 * 256 + d * 256 + suf logger.info( cyan( ' --> gen server_id done , %s %s is %s '%( host , port , server_id) ) ) return server_id def genmycnf(logger,port=3306,itype='h'): host = env.host_string bps={ "a":"48|32|3100|3000", "b":"62|40|4600|4500", 'c':'94|64|7600|7500', 'd':'94|32|3100|3000', 'e':'125|75|10100|10000', 'f':'188|120|15100|15000', 'g':'188|60|7600|7500', 'h':'1|256M|800|750' } try: myfile=''.join(host.split('.'))+'.cnf' cpmycnf="""cp configs/my.cnf tmp/%s """%myfile local( 'rm -f tmp/%s'%myfile ) local("cp configs/my.cnf tmp/%s "%myfile ) sid=getnewServerId(logger,port) keys=bps.keys() bpxs=bps[itype] mem,bpsize,maxc,maxuc=bpxs.split('|') if bpsize[-1] != "M": bpsize = bpsize +'g' chrgcmd=""" sed -i -e "s/3306/%s/g" -e "s/server_id=10000/server_id=%s/g" -e "s/=32g/=%s/g" -e "s/max_connections=3100/max_connections=%s/g" -e "s/max_user_connections=3000/max_user_connections=%s/g" tmp/%s """ local( chrgcmd%(port,sid,bpsize,maxc,maxuc,myfile) ) logger.info( green( ' --> gen my.cnf success ') ) logger.info( green( ' --> copy my.cnf to dist host ') ) put( local_path="tmp/%s"%myfile, remote_path="/data/mysql%s/my.cnf"%(port) ) except Exception, e: logger.warning(yellow( ' --> genmycnf() exception : %s '%traceback.format_exc() ) ) raise e
script 2 whole task :
import inst_utils from inst_utils import * def install_mysql(port): logger = initLoggerWithRotate() thost = env.host_string try: logger.info(green( 'stp 1 get the host %s '%thost )) #check host reachable rs1 = checkhost(logger ) if int(rs1)== 0 : logger.info(red( 'stp 2 check the host is reachable failed ' )) logger.info(green( 'stp 2 check the host is reachable OK ' )) plat_type = run(''' uname -o ''') if plat_type != 'GNU/Linux' : logger.warning(yellow('stp 3 target platform is not GNU/Linux & exit() ')) sys.exit() logger.info(green('stp 3 target platform is GNU/Linux')) #check target host exsist mysql instance logger.info(green( 'stp 4 checkmysqlinstance ' )) checkmysqlinstance(logger) #create MySQL user logger.info( green( 'stp 5 createUser ' )) createUser(logger) put(local_path="configs/bash_profile", remote_path="/home/mysql/.bash_profile") #checking dir logger.info( green( 'stp 6 initdir ' )) initdir(logger,port) #copy file logger.info( green( 'stp 7 copymysql ' )) copymysql(logger) logger.info( green( 'stp 8 genmycnf ') ) genmycnf(logger,port,'h') except Exception, e: print 'main : exception : ' , e
本文由主机测评网发布,不代表主机测评网立场,转载联系作者并注明出处:https://zhuji.jb51.net/yunwei/8328.html