嗨,老铁,欢迎来到我的博客!

如果觉得我的内容还不错的话,可以关注下我在 segmentfault.com 上的直播。我主要从事 PHP 和 Java 方面的开发,《深入 PHP 内核》作者之一。

直播中我将毫无保留的分享我这六年的全部工作经验和踩坑的故事,以及会穿插着一些面试中的 考点难点加分点

周梦康 发表于 2015-06-14 15415 次浏览 标签 : shell

这种发布方式太 out 了,现在使用的方式是 git 发布,具体参考我的视频分享:https://segmentfault.com/l/1500000009978736


之前的上线流程很简单粗暴如图:

代码上线流程以及版本发布小结

这简直是灾难性质的,上传 SVN,在测试服务器上看看正在调试的接口没问题,直接 sync 到线上服务器。代码无法回滚,只能覆盖。而客户端的同学需要稳当的 api 作为调试,最初的做法,他们需要新数据,我们就需要上线代码。这很坑爹,也许某人某段代码正写了一半,又正好提交。被另外一个人上线了,那么就线上出了严重 BUG。对此我们很头疼,所以做了如下规划:

首先建立三个版本库

  1. 开发服务版本库(对应图片中 dev,假设为 http://211.155.84.144/topit_dev)

  2. 外测服务版本库(对应图中 beta,假设为 http://211.155.84.144/topit_beta)

  3. 线上服务版本库(对应图片中 online,假设为 http://211.155.84.144/topit_online)

可能只分上面三个层级还是不够细,但是考虑到公司的实际情况,这是一个折中方案,后期实际证明稳定性得到了很大的保障。

然后做了一个根据版本配置指定 api 地址的管理后台,该 api 用于 app 在启动之初和启动之后轮询请求询问当前 app 应该请求的api 地址多少。如图所示

 

实际操作流程如下:

  1. 项目起步,规定好该版本的 build 和 version 之后(比如 build=3.2.1&version=400,实际还可以分得更新比如是 android 还是 ios,具体到哪个渠道,这里举例说明就不细分了),后台设置该版本的 api 地址为 dev。

  2. 每个人先将自己的代码直接 sftp 上传到自己的测试 vhost 指定的目录中,进行调试。

  3. 调试通过后,将代码提交到 dev 版本库,然后钩子触发更新到 dev 目录。而当前 dev 目录则是我们内部调试的 api 后端服务的根目录,客户端同学在开发的时候就调用该 api。

  4. 开发完毕,内部测试通过,将 dev 目录的文件 rsync 同步到 beta 目录,过滤了 dev 目录的 svn信息

  5. 将 beta 目录提交 svn

  6. 再执行 beta 代码远程同步脚本,将 beta 目录的代码同步到多台 beta 测试服务器上。

  7. 然后根据当前的外部版本号和内部版本,在后台将其 api 请求地址和图片上传地址修改为 beta 服务器相关的地址(图片简写为1台服务器)

  8. 然后将 app 交给专业第三方测试公司帮我们测试

  9. 测试通过后,对于 bug 我们则再走一遍前面的 dev 到 beta 的步骤,然后,我们通过在进入 app 首屏给2000到3000个用户强制弹窗让其更新到指定版本。进行灰度发布。

  10. 灰度发布发现 bug,修复 bug 后再走一遍上面的流程,然后把 beta 目录的代码同步到 online 目录,同样过滤掉 svn 信息

  11. 在 online 目录做版本提交到 online svn 版本库

  12. 然后再执行 online 目录代码远程同步脚本,将 online 目录的代码同步到所有线上服务器上。

  13. 然后根据当前的外部版本号和内部版本,在后台将其 api 请求地址和图片上传地址修改为线上服务器相关的地址

  14. 最后直接全站提示更新到指定版本。

如果突遇线上有紧急 bug 需要修复,如果预估时间比较长,我们可以直接将该版本号下的 api 请求退回到 beta 服务器上,然后在 online 目录修改完毕,提交 svn,同步代码之后再重新指向线上服务。

如果遇到某个紧急需求,需要马上上线的,我们只能通过单独 cp dev 下的某一个文件到 online 目录,然后做好版本控制,紧急上线。实际工作中,这种需求非常常见。做提交信息的填写就显得格外重要了。

未来需要做的 api 健康状态周期性监测,服务器周期性请求每个 api,然后和规定的正确数据进行对比,如果有问题则发出报警信息,以免每次都要等到用户反馈我们才知道有问题。还是由于版本迭代太快,数据结构实时调整是常有的事,开发成本和维护成本比较高,我们都只能暂时搁浅了。

今天我又把代码上线流程做了些优化

#!/bin/sh

######################## config ########################

# 升级日志
publish_log_file="/update/log/path/publish.log"

# 需要邮件通知的人
master=(
    i@zhoumengkang.com
    mengkang@topit.me
    zhoumengkang@php.net
)

# 更新服务器列表
remote_hosts=(
    192.168.1.14
    192.168.1.10
    192.168.1.17
    192.168.1.13
    192.168.1.14
    192.168.1.13
    192.168.1.26  # 图片上传服务器
    192.168.1.17  # 用于 static.mengkang.net 图片访问
)
######################## config ########################

function_svn_diff(){
    svn_diff_size=`sudo svn diff|wc -c`;
    
    if((svn_diff_size>0));then
        echo -e "\e[10;31m以下文件修改了,但还未提交\e[0m"
        echo -e "\e[10;31m============================================================\e[0m"
        sudo svn diff|grep "Index:"|awk '{print $2}'
        echo -e "\e[10;31m============================================================\e[0m"
        echo -e "\e[10;31m请先进行 svn 代码提交再执行上线操作\e[0m"
        exit;
    fi
}

function_svn_need_add(){

    echo -e "\e[10;31m以下文件还未加入版本库\e[0m"
    echo -e "\e[10;31m============================================================\e[0m"
    sudo svn st|grep "?"|grep "\.php"|grep -v "site2.0/back"|awk '{print $2}'
    echo -e "\e[10;31m============================================================\e[0m"
    echo -e "\e[10;31m忽略这些文件直接上线? \e[0m\e[10;32m yes \e[0m / \e[10;31m no \e[0m"
    
    read comfirm
    
    if [ "$comfirm" != "yes" ]; then
        echo -e "\e[0m\e[10;32m上线取消\e[0m"
        exit
    fi
}


function_puslish_init(){
    for i in "${!remote_hosts[@]}";do
        if(($i == 0)); then
            function_rsync_online ${remote_hosts[$i]} | tee $publish_log_file;

            # 先看有没有更新文件,如果没有更新则退出,没有更新则只有下面四行,如果有更新则会有更新的文件列表
            # sending incremental file list

            # sent 147892 bytes  received 639 bytes  99020.67 bytes/sec
            # total size is 707645226  speedup is 4764.29
            num=`cat $publish_log_file|wc -l`
            if(($num<5)); then
                echo -e "\e[0m\e[10;32m暂无更新\e[0m";
                exit;
            fi
        else
            function_rsync_online ${remote_hosts[$i]}
        fi
    done
}

# 分发
function_rsync_online(){
    if [[ $1 ]]; then
        export RSYNC_PASSWORD=rsync
        /usr/bin/rsync -avz --delete --exclude=".*" /path/of/code/ rsync@$1::topit_online/
    fi
}

function_publish_quit(){
    # online 目录版本
    head_log=`sudo svn log -r head|grep -v "\-\-"|grep -v ^$`
    publish_log=`cat $publish_log_file`
    # 类似于 r175 | xiaofei | 2015-07-08 15:40:24 +0800 (Wed, 08 Jul 2015) | 1 line 活动规则显示 bug 修复
    echo $head_log;

    for x in ${master[@]};do
        echo -e "$head_log\n---------------------------------------\n$publish_log\n---------------------------------------\n上线人: $USER"|mail -s "topit上线通知" $x
        echo -e "已邮件通知\e[0m\e[10;32m $x\e[0m";
    done
}

cd /path/of/code/;

function_svn_diff;
function_svn_need_add;
function_puslish_init;
function_publish_quit;

脚本地址https://github.com/zhoumengkang/notes/blob/master/shell/update_to_online.sh

  1. 提交时,修改的文件必须提交,以防出问题不方便回滚

  2. 没有加入版本库的文件提示最好添加到版本号,可以忽略

  3. 版本发布完毕之后给管理员发送邮件通知


分享到

评论列表

如果填写邮箱了,当我我回复您的时候会给您邮箱发送消息提醒,方便交流
提交 可以使用`xxxx`来插入简短的代码碎片
1楼 樊成 2017-02-27 16:29:53

楼主真不错 写的东西很实用 很有帮助 原来你也是湖北人啊 老乡!

回复
2楼 路人甲 2017-05-23 20:02:59

请问博主你的这个博客是自己写的吗,还是哪里有实现啊?

回复
3楼 康哥 2017-07-09 15:59:16

回复路人甲: 自己随便写的

回复