• 小团队前端部署演化之路


    前言

    前端部署相对来说其实是一件非常容易的事情,无论是最原始的html页面,还是现在热门的三大框架,最后交付部署的时候,始终会是一些静态文件。

    虽然简单,但是对于不同的团队来说,都会在不同阶段有最适合他们的方式。

    下面老黄聊聊所在团队是怎么演化的。

    老黄把它们划分成了3个阶段,每向下一个阶段都是为了解决上一个阶段带来的不可避免的问题。

    1. 刀耕火种时期
    2. CICD半自动化时期
    3. 半无服务器化时期

    下面依次来看看这三个阶段的内容。

    刀耕火种时期

    在加入团队早期,团队只有两个前端,后面才发展到六七个,团队前端的主要技术栈是vue。

    每次发版的时候,都是前端同学在自己的电脑打包好相应的部署文件之后,发给某个后端同学,由这个后端同学手动放到服务器上面,早期还都是部署在IIS上面的,和部分后端站点放在同一个服务器。

    明眼人应该都可以看的出问题所在,整个部署的流程是比较漫长的,出差的概率也是比较高,毕竟人为参与的环节比较多。

    随着项目逐步增多,那个部署前端站点的同学几乎要奔溃的节奏,每个项目都是一天连续发好几个版本,写接口的思路老是被打断。。。

    对一个初创团队,人员都不充足的情况,其实这一阶段也是必经之路了吧。

    这个时候引入CICD让发布流程略微自动一点点,其实是一个比较合适的时候了,刚好又是解决团队一大痛点的好东西。

    老黄这边是采购了3台突发性能的4c4g的服务器。2台用于搭建jenkins,一台用于部署前端站点。

    可能有人会问为什么要用突发性能的服务器,成本呀成本呀,这个是最实在的原因。

    前端站点有CDN在前面挡着,回源到服务器的很少,这也是为什么敢如此大胆的用突发性能的机器来部署前端站点。

    CICD半自动化时期

    在这个时期其实就是简化部署操作,各自负责各自的项目。在快速的迭代过程中,前端同学负责自己对应项目的版本发布。

    这也是老黄一直在推崇的,自己负责的项目要全权负责,至少该给开发的权限还是要给的。

    为什么说是半自动化呢?因为不敢做到一提交代码就发布到测试环境,再发到生产环境,还是要有人为的点一下这个操作。

    先来简单看看两张图,是怎么人为点一下的。

    测试环境的部署:

    生产环境的部署:

    这里设置的都是参数化的,构建的时候都是看情况填写的。

    拿个例子说明一下。

    测试环境的流水线配置

    pipeline {
        agent {
            node{
                label 'linux'
            }
        } 
        stages {
            
            stage('拉代码') {
                steps {
                    echo '拉取代码.......'
                    git branch: '${branch}', credentialsId: 'code', url: 'xxxxxxxx.git'
                }
            }
             
            stage('打包镜像发布到测试环境') {
                steps {
                    echo '打包镜像.......'
                    sh label: '', script: '''
    
    cp /data/files/项目名xxxx/* ./
    
    ls
    
    ./buildtest.sh ${ver}
    
    '''
                }
            }
        }
    }
    

    生产环境的流水线配置

    pipeline {
        agent {
            node{
                label 'linux'
            }
        } 
        stages {
          
            stage('发布镜像到生产环境') {
                steps {
                    echo '打包镜像.......'
                    sh label: '', script: '''
    
    cp /data/files/项目名xxxx/* ./
    
    ls
    
    ./buildprod.sh ${ip} ${version}
    
    '''
                }
            }
            
            stage('刷新CDN') {
                steps {
                    echo '刷新CDN.......'
                    sh label: '', script: '''
    
    ./refreshcdn.sh
    
    '''
                }
            }
        }
    }
    

    两个环境不一样的地方其实就是执行的脚本文件,以及胜场环境多了一步刷新CDN的操作。

    老黄是给每个不同的项目都编写了对应的脚本文件,每个项目会包含下面的几个文件。

    其中Dockerfile就是用来编译源码和把生成的静态文件放到nginx里面。

    nginx.config 就是nginx的配置文件了。

    run.sh 是用来替换占位符,从而达到一个镜像,通过环境变量的方式去请求不同环境的接口。

    buildtest.sh 主要就是打包好镜像,上传到阿里云容器服务,ssh到测试服务器,拉镜像,起容器。

    tag=`date +%Y%m%d%H%M%S`
    
    docker build -t xxxxxxxxxx:$tag -f Dockerfile .
    
    docker push xxxxxxxxxx:$tag
    
    ssh root@前端服务器IP "
    docker pull xxxxxxxxxx:$tag
    
    docker stop 容器名 
    
    docker rm 容器名
    
    docker run -d -p 8011:80 
    	--name 容器名 
    	--restart=always  
        -e TZ=Asia/Shanghai 
    	-e API_ROOT=https://www.testexample.com 
    	--log-opt max-size=50m 
    	--log-opt max-file=3 
    	xxxxxxxxxx:$tag
    
    
    docker ps -f name=容器名
    
    sleep 3
    
    docker ps -f name=容器名
    
    
    echo '版本号:   xxxxxxxxxx:$tag '
    "
    
    echo "复制此版本号发布到生产环境:   xxxxxxxxxx:$tag"
    

    buildprod.sh 主要就是ssh到生产服务器,拉镜像,起容器。

    ssh root@$ip "
    
    docker pull xxxxxxxxxx/$tag
    
    docker stop 容器名 
    
    docker rm 容器名
    
    docker run -d -p $port:80 
            --name 容器名 
            --restart=always  
    	    -e TZ=Asia/Shanghai 
    	    -e API_ROOT=https://www.prodexample.com 
            --log-opt max-size=50m 
            --log-opt max-file=3 
            $tag
            
    docker ps -f name=容器名
    
    sleep 3
    
    docker ps -f name=容器名
    "
    

    在这一阶段其实一切都是运行正常的,各位前端同学的反应也比较不错。

    这里是以镜像的方式交付部署的,每次生成好镜像后都是push到阿里云的容器镜像服务。

    这里始终是占着服务器资源,除了要自己维护域名端口的绑定之外,还要受限于阿里云单个负载均衡的域名个数。

    前一段时间想在负载均衡里面添加一个新域名的时候,发现了这个无奈的问题。

    买多一两个负载均衡是可以解决眼前这个问题的,但是不是长久之计。

    所以还是决定走前端部署比较地道的一种方案,往无服务器时代的演进了。

    半无服务器化时期

    本来是想叫无服务器化时期的,不过想到jenkins还是自建的,所以在前面加了一个半字。

    这里是借助阿里云的对象存储来完成的。

    这里其实是只对CICD发布的对象调整一下就好了,对前端同学来说是无感知切换的。

    buildtest.sh调整如下:

    tag=`date +%Y%m%d%H%M%S`
    ossbucket="oss的bucket名字"
    artifacts="发布后文件的存放目录"
    ver=""
    
    if [ -n "$1" ]; then
        ver=$1
    else
        echo "Please enter the version param!"
    fi
    
    if [ $ver == 'e' ]; then
        npm install
    	npm run build
    	
    	basepath=$(cd `dirname $0`; pwd)
    	dest=/data/artifacts/$artifacts/$tag
    	test -d "$dest" || mkdir -p "$dest"
    	cp -rf $basepath/dist/* $dest
    	test -d "${dest}_test" || mkdir -p "${dest}_test"
    	cp -rf $basepath/dist/* "${dest}_test"
    
    	find "${dest}_test" -name '*.js' -exec sed -i -e 's,API_ROOT,'"https://www.prodexample.com"',g' {} ;
    
    	if [ "`ls -A ${dest}_test`" = "" ];
    	then
            	echo "${dest} is empty"
    	        exit 1
    	else
            	echo "upload ${dest} to oss ${ossbucket}"
                
    	        /data/tools/./ossutil64 cp -rf "${dest}_test/" "oss://${ossbucket}/" --config-file=/data/tools/.ossutilconfig
    	fi
    
    	echo "复制此版本号发布到生产环境:$tag"
    else
        # rollback
        dest=/data/artifacts/$artifacts/$tag
    
    	if [ "`ls -A ${dest}`" = "" ];
    	then
    	        echo "未能找到对应的版本号 【${tag}】  "
            	exit 1
    	else
    	        test -d "${dest}_test" || mkdir -p "${dest}_test"
            	cp -rf $dest/* "${dest}_test"
    
                find "${dest}_test" -name '*.js' -exec sed -i -e 's,API_ROOT,'"https://www.prodexample.com"',g' {} ;
    
            	echo "upload ${dest}_test to oss ${ossbucket}"
    
    	        /data/tools/./ossutil64 cp -rf "${dest}_test/" "oss://${ossbucket}/" --config-file=/data/tools/.ossutilconfig 
    
            	echo "当前版本号为:$tag"
    	fi
    fi
    

    调整之后,交付只能是用文件的方式了,这里是将每次发布之后的文件保存一份到本地,保留最近2个月,当然,这里也可以保存到OSS的另以个bucket上面,不过现阶段似乎不太迫切。

    发布之后,文件就会被上传到OSS上面了。

    上传之后,还要配置三个地方,才算是真正的完成,这三个配置是一次性的。

    首先是基础设置里面的静态页面,设置一下默认首页

    其次是在传输管理的域名管理里面绑定域名,证书和CDN在这里是选填的。

    最后一步是把域名CNAME到OSS的域名

    到这里就已经是完成了最后的部署了,后面发版本的时候,只需要通过jenkins把编译好的静态文件丢到对象存储就可以了。

    总结

    老黄经历的这三个时期,应该有不少人也会有类似的感觉或经历。

    在遇到痛点难点的时候,想办法解决掉就可以了。

    对于前端站点的部署,最简单直接的办法的还是直接托管到云上面,可以省掉很多不必要的麻烦。

  • 相关阅读:
    android 4.0 中出错 java.lang.UnsupportedOperationException
    怎么确定你的CPU是否支持64位虚拟化
    宽度百分比单位的转换公式
    Test SRM Level Three: LargestCircle, Brute Force
    802.11(wifi)的MAC层功能
    zookeeper集群的python代码测试
    mysqldump 命令的使用
    xp硬盘安装Fedora14 过程记录及心得体会(fedora14 live版本680M 和fedora14 DVD版本3.2G的选择)
    ContentProvider的使用
    基于 Java 2 运行时安全模型的线程协作--转
  • 原文地址:https://www.cnblogs.com/catcher1994/p/13664800.html
Copyright © 2020-2023  润新知