golang jenkins部署及slb平滑上线方案

栏目: Go · 发布时间: 5年前

内容简介:前言:平滑上线的问题

前言:

换了份新工作,又是一个新的开始。正题开始, 最近在折腾golang的部署及平滑上线,写了几年的golang项目了,按道理来说很简单平常的事情,但在我们这有些小麻烦了

平滑上线的问题

先说下平滑上线的问题,阿里云的slb想来大家应该都用过。aliyun slb跟nginx upstream最大的区别在于不支持next_upstream方法。nginx next_upstream的参数控制当某节点不可用时,nginx会调度到下一个可用节点,不停尝试直到访问成功或者next_upstream_timeout超时中断。

换句话说,nginx upstream默认不加插件是被动检测api可用的过程,而像阿里云的slb是主动探测,这个跟haproxy是一样的,检测完了后,才会刷新可用节点列表。

如果slb的检测间隔是5s,某节点当前是可用的,距离下次探测之前节点突然不可用,那么这段时间窗口期内,slb还是会把请求转发到该节点,那么请求肯定是异常了。 当然你可以把检测间隔调成1s,顶多就失败1s。

如何在现有的条件下,进行平滑上线启动,优雅上线,尽量减少异常? 因为是个新业务,后面会频繁上下线,如果不解决该问题会导致丢失任务,虽然有多方的重试,不会真的丢失数据,但时不时的微信告警让人厌烦。所以,我们要做的只是 尽量减少失败 罢了 !!!

以前怎么解决平滑上线?

直接操作阿里云的slb api,删停节点,后面的请求自然就不走被删停的节点,我们就可以升级该节点了(当然,你的服务本身也要做好优雅退出,不能kill就退出)。如果不选择用slb api删除节点,而是把权重配置为0,那么新请求新连接就不会去该节点,但是老请求还是会过来,直到连接的关闭,所以单纯配置权重不是很稳。

那么现在怎么玩?

上海的ops不会给提供slb的api。我想到的方法很简单,我们知道阿里云的slb需要节点提供一个/ping接口,主要http code是2xx就可用。那么我们可以这样,升级一个服务之前,先触发一个信号,把/ping的返回状态重置异常,然后等待slb的探测间隔的时间,这个期间slb会下发一波探测,你的/ping不可用,自然就标记为异常,下次不会再转发,这时候你就可以升级了。升级后,ping为正常的200。

下面是控制服务的 shell 脚本,这提取了stop部门。逻辑很简单,先发送sigusr2信号,等待5秒,然后再去kill信号,如果20秒内还没有优雅退出,就强制kill -9干掉。

// xiaorui.cc
 
...
 
function stop()
{
    check_pid
    running=$?
    if [[ $running -eq 0 ]];then
        echo_info "$PROJECT is not running, don't need stop"
        return
    fi
 
    pid=`cat $PIDFILE`
    if [[ "$pid" -gt 0 ]]; then
        echo_info "$PROJECT will close ping api..."
        kill -USR2 $pid   # 关闭ping接口
        sleep 5
        kill $pid
        echo_info "$PROJECT will stop srv..."
    else
        echo_panic "not found ${PROJECT} pid"
        return
    fi
 
    c=0
    while true
    do
        if [ $c -gt 20 ];then
            echo_info "ensure force kill -9"
            kill -9 $pid >> $STDOUT 2>&1
            break
        fi
    	echo_info "get status since $c seconds"
        check_pid
        running=$?
        if [ $running -gt 0 ];then
            sleep 1
            let c++
            continue
       ....
}
 
...

下面是 Golang的监听信号及修改 /ping 返回的逻辑。代码很简单,就是注册sigusr2信号及回调方法。回调方法就是修改一个对象,表示是否要关停ping接口。如果关停,返回非200状态。

// xiaorui.cc
 
// kill -USR2 ${pid}
func ClosePingAPI() {
	c := make(chan os.Signal, 1)
	signal.Notify(c, syscall.SIGUSR2)
	go func() {
		for range c {
			router.ClosePingAPI()
			tool.Log.Info("recv signal sigusr2 for close ping api")
		}
	}()
}
 
func (r Router) ping(q *gin.Context) {
	if PingStatus {
		q.JSON(http.StatusOK, types.Common{Code: 0, Message: "success"})
	} else {
		q.JSON(http.StatusNotImplemented, types.Common{Code: -1, Message: "active ping api is already closed"})
	}
}
 
func ClosePingAPI() {
	PingStatus = false
}

jenkins上线部署问题

说下,我以前公司golang上线打包方式的三种方式。

一种:

基础架构组件,使用rpm打包,推送到yum仓库,然后进行部署。

第二种:

使用 docker 容器打包,继而推送到docker私有仓库,然后进行部署。

第三种:

根据你的项目的不同,如果你是golang的项目,他会帮你构建GOPATH路径,很方便就可以完成打包上线。

由于网络区域问题,暂时不能使用docker的方法上线。 rpm打包适合基础组件,我这类偏业务的系统肯定不能用rpm了。那么就剩下第三种了,问题来了。。。

大家的golang项目中的import路径多是全路径, 第三方的包我们可以通过dep扔到vendor目录里。但是jenkins的部署逻辑是这样,你先在页面选择项目及分支,jenkins会异步的把你的git代码pull到jenkins机器的一个目录里,比如 /data/jenkins/。你的项目名是 featrue_gateway,那么在jenkins目录就是 /data/jenkins/ featrue_gateway 。你怎么指定GOPATH来build代码?

以前公司的运维们针对golang项目在一个路径排列,比如你的项目是 http://git.xiaorui.cc/machine/featrue_gateway,  那么 在编译机也就是jenkins里路径是这样的 /data/jenkins/go/src/git.xiaorui.cc/machine/featrue_gateway, 对于我们来说,只需要相对路径的指定gopath就可以了。

// xiaorui.cc
 
import (
    "git.xiaorui.cc/machine/featrue_gateway/libs/pidfile"
    "git.xiaorui.cc/machine/featrue_gateway/libs/primary_ctl"
    "git.xiaorui.cc/machine/featrue_gateway/libs/connect_pool"
    .... 
)

就这个问题跟上海的ops来回扯了好几次。后来想想,为毛非要依赖他的路径?干脆我在当前路径下,设立一组路径,./tmp/go/src/git.xiaorui.cc/machine/feature_gateway/…,我makefile只需要gopath到当前路径的tmp就可以了。

// xiaorui.cc
 
rm -rf tmp
tmp_path=tmp/src/git.xiaorui.cc/feature-gateway/machine
mkdir -p $tmp_path
cp -rf `ls . | grep -E -v "^(tmp)$"` $tmp_path
 
cp -rf scripts/deploy/control.sh  ${PROJECT_PATH}/
cp -rf scripts/deploy/init.sh     ${PROJECT_PATH}/
cp -rf scripts/deploy/feature_gateway_logrotate.conf ${PROJECT_PATH}/
 
# real build
export GOPATH=`pwd`/tmp; go build -ldflags "-X main.BuildTime=${BUILD_TIME}" -o ${PROJECT_PATH}/feature_gateway cmd/feature_gateway.go

总结:

遇到的这两个问题,看起来是由于运维同学支持不给力导致的,但细想下大家都有难处,运维也有自己的职责规范,所以互相谅解吧。这样也促进我们去思考更多的解题思路。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Spark SQL内核剖析

Spark SQL内核剖析

朱锋、张韶全、黄明 / 电子工业出版社 / 2018-8 / 69.00元

Spark SQL 是 Spark 技术体系中较有影响力的应用(Killer application),也是 SQL-on-Hadoop 解决方案 中举足轻重的产品。《Spark SQL内核剖析》由 11 章构成,从源码层面深入介绍 Spark SQL 内部实现机制,以及在实际业务场 景中的开发实践,其中包括 SQL 编译实现、逻辑计划的生成与优化、物理计划的生成与优化、Aggregation 算......一起来看看 《Spark SQL内核剖析》 这本书的介绍吧!

html转js在线工具
html转js在线工具

html转js在线工具

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具