基于Fabric的发布脚本

简单介绍

项目是属于Java项目,生产环境是在阿里云,前端有一个负载均衡,后端2台线上服务器。如果后端服务器较多,原理是一样的。首先,将编译后的包放到所有线上环境,然后移除负载均衡中其中一台服务器,对该服务器对应的服务进行停止,更新线上包,然后启动,测试,最后把服务器添加到负载均衡中。再执行剩余的机器,这样上线不会影响到所有的机器,业务可以不间断提供服务。注:该脚本有参考别人的思想

#coding:utf-8
#
from fabric.api import *
from fabric.utils import abort
from fabric.api import env, local, roles, hosts
from fabric.utils import abort
from fabric.operations import sudo, run, put
from fabric.context_managers import cd, settings
from fabric.tasks import execute
from fabric.contrib.files import exists
from fabric import context_managers
import time
import json
import urllib


env.host_one = ['a.a.a.a']
env.host_remaining = ['b.b.b.b']
env.host_tmp = ['']
env.host_all = env.host_one + env.host_remaining

env.user = 'admin'
env.password = ''

env.app_name = 'myproject'
env.app_port = '9006'
env.app_status_cmd = 'http://localhost:%s/v1/status' %env.app_port

env.java_home = '/usr/local/java/jdk1.8.0_181'
env.app_home = '/home/admin/deploy/%s' %env.app_name
env.local_app_home = '/home/admin/build/repo_gogs/%s' %env.app_name
env.app_sh = '%s/sh' %env.local_app_home
#env.pid_file = '%s/pid' %env.app_home
#env.app_log = '%s/logs' %env.app_home
#env.app_out = '%s/%s.out.log' %(env.app_log,env.app_name)
#env.java_opt = '-Xms2048m -Xmx2048m -XX:MaxDirectMemorySize=128m -Xmn1024m -XX:SurvivorRatio=10 -XX:+PrintGCDetails -XX:MetaspaceSize=72m -Xloggc:%s/gc.log -XX:+PrintGCDateStamps -XX:-OmitStackTraceInFastThrow' % env.app_log

env.Penv = 'ali'
#env.RELEASE_TARGET = 'biezz@192.168.174.138:/home/biezz/release'
env.build_dir = '/home/admin/build/repo_gogs/%s/build/distributions' %env.app_name
env.release_dir = '/home/admin/release'
env.release_branch = 'release'

env.slb_ids = ['lb-bp12wgm8lwhaaaaaaaaaa']  #阿里云实例ID
env.slb_host = 'http://192.168.3.55:8086'   #实例操作接口,这个需要根据具体的实际情况来,这里是调用自己写的接口,亦可参考阿里云负载均衡api
#env.slb_host = 'http://slb.aliyuncs.com'
#env.access_key = 'TMP.AQGXgOn8WuetlM_SgLHmSbGOcGOlA4QkSjyeBDOBmHN2S13Ltn6bOvfco1n9ADAtAhUA7CjYA9nfadPGQAljN33YwG0AX2YCFBKPzcxoiT2WjOC9COgjw1laXhr0'
#env.backend_server = 'i-bp1aqu5t6zc4olokrxg5'

env.stop_wait_time = 15
env.status_check_interval = 5
env.status_check_times = 20

env.notify_api = 'http://10.171.232.204:8086/sendWeixinNotify?' #通知接口

def rnotify(msg=''):
    print msg
    param = {'auth':'evilognuf', 'agentid':10, 'message': (env.app_name + '===>' + msg)}
    local('curl \'%s\'' % (env.notify_api + urllib.urlencode(param)))
    #local('curl ' %(urllib.url))

#@hosts(env.host_tmp)
#def test():
#    " just for test "
#    rnotify('begin testDate')
#    pass

def first():
    rnotify('first begin ...')
    execute(pull)
    execute(build)
    execute(release)
    execute(deploy_one)
    rnotify('first end ...')

def left():
    """deploy to remaining nodes"""
    rnotify('left begin ...')
    execute(deploy_remaining)
    rnotify('left end ...')

def pull():
    with lcd(env.local_app_home):
        local("git fetch")
        local('git reset --hard  remotes/origin/%s' %env.release_branch)

def build():
    with lcd(env.local_app_home):
        local('gradle -Penv=%s clean distTar' %env.Penv)

@hosts(env.host_one)
def release():
    with lcd(env.app_home):
        #local('scp build/distributions/*.tar %s' %env.RELEASE_TARGET)
        pass
    run('mkdir -p ' + env.release_dir)
    put(env.build_dir + '/*',env.release_dir)

def deploy_one(host=''):
    if not host:
        host = env.host_one[0]
    env.hosts = [host]
    execute(offline,innerIp=host)
    execute(restart)
    execute(check_status)
    execute(online,innerIp=host)

def deploy_remaining():
    """run deploy_one on remaining nodes"""
    for host in env.host_remaining:
        execute(deploy_one, host)

def check_status():
    """check app status"""
    ok = ''
    times = 1
    with settings(warn_only = True):
        while times < env.status_check_times:
            ok = run(env.app_status_cmd)
            #ok = 'ok'
            if ok == 'reloading':
                return True
            times = times + 1
            print('status != ok. wait for %s seconds to check again ' % str(env.status_check_interval))
            time.sleep(env.status_check_interval)
    abort('check status failed after %s retires!' % str(times))

def offline(innerIp=''):
    slb_remove(innerIp)
    print('wait for %s seconds before stop' % str(env.stop_wait_time))
    time.sleep(env.stop_wait_time)

def online(innerIp=''):
    slb_add(innerIp)

def restart(zipfilename='', rollback=False):
    #run('mkdir -p %s' %env.app_home)
    #put(env.app_sh + '/*',env.app_home)
    with cd('/home/admin/deploy/%s' %env.app_name):
        #run('chmod +x deploy.sh env.sh restart.sh start.sh stop.sh')
        if not zipfilename:
            if rollback:
                zipfilename = run('ls -t %s |head -2|tail -1' % env.release_dir)
            else:
                zipfilename = run('ls -t %s |head -1' % env.release_dir)
        if not zipfilename:
            abort('no tar found! can not restart! rollback: %s' % str(rollback))
        run('cp %s/%s ./' %(env.release_dir,zipfilename))
        run('./deploy.sh ' + zipfilename)
        run('sh stop.sh',pty=False)
        run('sh start.sh',pty=False)

def slb_add(innerIps=''):
    slb_action('AddBackendServer', innerIps)

def slb_remove(innerIps=''):
    slb_action('RemoveBackendServer', innerIps)

def slb_action(action='', innerIps=''):
    for id in env.slb_ids:
        response = run("curl '%s/slb/%s?auth=evilognuf&LoadBalancerId=%s&innerIps=%s'" % (env.slb_host, action, id, innerIps))
        #response = 'ok'
        if response != "ok":
            abort("response not OK: %s" % response)
    pass