实在是没有系统学习找工具,只能自己造,代替部分人工操作,实现提交代码后测试环境拉取测试,发布版本后正式环境拉取编译 发布。
@[toc]
- | - |
---|---|
代码环境 | .Net Core 3.1 |
版本管理器 | Gitea(Docker)搭建 |
操作系统 | Linux(以下服务器均为 Centos 7) |
正式服务器IP | .15 |
镜像服务器IP (作为正式服务镜像用于测试) | .38 |
测试服务器IP | .43 |
代码版本服务器IP | .44(就是Gitea所在服务) |
测试服务器中有一个脚本,从git上拉取最新代码(配置git过程略),然后将发布的代码覆盖,并启动服务。
这里我在VS中将项目发布,并一同提交,脚本直接拉取发布的文件夹进行本地覆盖,不在服务器上二次编译,但是 正式环境需要二次编译以保证编译通过才能发布。
该脚本在/home/gitpull.sh 下
注意 dev 为测试用代码分支
echo mainpath=/home/MES #git路径 主程序路径 cd $mainpath echo ----流水线开始获取代码---- #reset是重置 强制拉取的目的 git reset --hard origin/dev git pull cd $mainpath project=/home/MES/02_Source/MES/MES/bin/Release/netcoreapp3.1/publish #项目路径 需要发布的路径 deploy=/home/MESpublish #发布后路径 dllname=MES.dll #应用名称 echo ------执行结束命令----- cd $deploy ./ShutDown.sh echo ------复制发布的文件----- cp -rf $project $deploy echo ------执行start---- ./Start.sh echo ------结束------
ShutDown.sh 代码 用于停止.net core 项目
port=80 #项目端口号 #根据端口号查询对应的pid pid=$(netstat -nlp | grep -w :$port | awk '{print $7}' | awk -F"/" '{ print $1 }'); #杀掉对应的进程,如果pid不存在,则不执行 if [ -n "$pid" ]; then kill -9 $pid; fi
Start.sh 代码 用于启动项目
#!/bin/sh #启动MVC #先到目录下 否则报错 cd /home/MESpublish/publish #不显示日志 nohup dotnet HD.MES.dll >/dev/null 2>&1& ~
如果不cd到发布路径虽然会启动项目,但是访问会报错!原因未知
在发布后手动执行这个脚本,就可以愉快的测试了
这里的钩子就是当Git触发动作时向指定的Web服务推送一段JSON,动作包括 拉取 推送 发布 分支 等,JSON中包含项目信息 提交人 版本信息 等。
这里我主要配置了发布钩子
保存后发送的内容
可以看到我的 测试服务器上有一个服务8070 ,是一个自己写的WebAPI服务,核心代码如下:
该服务主要接收发布的事件,触发sh脚本(/home/MESReleases/pullPublish.sh)
using Microsoft.AspNetCore.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using System; using System.Diagnostics; using System.Linq; using System.Threading.Tasks; namespace GitWebApiTest.Controllers { [Route("api/[controller]")] [ApiController] public class GiteaController : ControllerBase { [HttpPost] public ActionResult<string> Post(dynamic _data) { dynamic data = JsonConvert.DeserializeObject(Convert.ToString(_data)); Task.Run(() => { string path = data["repository"]["name"].ToString(); if (path == "项目名称") { try { //Console.WriteLine(data); var tag_name = data["release"]["tag_name"].ToString(); JArray assets = JArray.FromObject(data["release"]["assets"]); var urls = assets.AsJEnumerable().Select(x => x).ToArray() .Select(x => $"{x["browser_download_url"]}|{x["name"]}" ); var prerelease = data["release"]["prerelease"].ToString() == "True" ? "1" : "0"; //Console.WriteLine(string.Join(",", urls)); if (prerelease == "true") { return; }//拦截预览版 稳定版才执行 //创建一个ProcessStartInfo对象 使用系统shell 指定命令和参数 设置标准输出 var sh = $"/home/MESReleases/pullPublish.sh {tag_name} {prerelease} {string.Join(",", urls)}"; Console.WriteLine(sh); var psi = new ProcessStartInfo("sh", sh) { RedirectStandardOutput = true }; //启动 var proc = Process.Start(psi); if (proc == null) { Console.WriteLine("Can not exec."); } else { Console.WriteLine("-------------Start read standard output--------------"); //开始读取 using (var sr = proc.StandardOutput) { while (!sr.EndOfStream) { Console.WriteLine(sr.ReadLine()); } if (!proc.HasExited) { proc.Kill(); } } } } catch (Exception ex) { } } }); //} return "OK"; } } }
pullPublish.sh 脚本 用于将发布后的源码下载,解压,编译,打包(压缩),发送到正式服务器的指定目录,这样我在发布时点击保存,正式服务器就有包了
代码较多, 这里进行拆解
4.1 判断参数
脚本接收三个参数:
if [ 2 -gt $# ] then echo "缺少参数:第1个参数是版本号,第2个参数 1 预览版 0 稳定版" exit; fi
4.2 创建发布目录和log目录
也可以不赋权限
mainpath=/home/MESReleases/$1 if [ ! -d $mainpath ];then mkdir $mainpath chmod 777 $mainpath fi Logpath=/home/MESReleases/log`date '+%Y%m%d'`.log echo " " >> $Logpath echo "———————$1————————–" >> $Logpath
4.3 下载到刚才建立的文件夹
之间将版本号 $1 拼接到下载的地址
使用 wget 进行下载 -P 表示指定目录
#下载 wgeturl=http://192.168.123.44:9000/……/archive/$1.tar.gz echo "开始下载" $wgeturl >> $Logpath echo "开始下载" $wgeturl wget -N $wgeturl -P $mainpath
下载文件超过1G会很慢,改为通过Git命令获取源码,git会自动检测更新项不用每次都下载 代码如下
在指定目录下载源码,执行一次就行
cd /home/MESReleases/Source/ git init git config --local core.sparsecheckout true git remote add origin http://192.168.123.44:9000/XXXX #只获取指定目录 即代码所在目录 echo '/02_Source/' >> .git/info/sparse-checkout git pull origin master
将下载代码替换为获取
//到源码目录下 cd /home/MESReleases/Source/ #重置 git fetch #拉取 git reset --hard origin/master git pull #如果有先删除 if [ -f $1/02_Source ]; then rm -rf $1/02_Source fi #复制 注意-r的使用,没有提示 cp 略过目录 cp -r 02_Source $1/02_Source #此代码会让代码获取速度提示一半,并且留存了版本代码,但是只会获取最新的代码,对于发布最新代码也可以
4.4 解压
--exclude 是跳过文件的意思 --strip-components 是跳级的意思
#解压 echo "开始解压到" $mainpath >> $Logpath echo "开始解压到" $mainpath tar -zxf $mainpath/$1.tar.gz --exclude=/hd_mes/01_设计书说明文档 --exclude=/hd_mes/03_其他资料 -C $mainpath hd_mes/02_Source/MES/ --strip-components 1
4.5 编译发布
-nowarn 表示不弹出编号为XXX的提示 -o 发布到指定目录
echo "开始发布" $project >> $Logpath echo '开始发布' $project project=$mainpath/02_Source/…….csproj publish="$mainpath/publish" if [ ! -d $publish ];then mkdir $publish chmod 777 $publish fi #增加本地变量,指定执行目录,dotnet在后台执行时会失去运行上下文导致报错 export DOTNET_CLI_HOME=/home dotnet publish $project -c Release -o $publish --self-contained false -nowarn:msb3202,nu1503,cs1591,cs0168,cs1998,cs4014,cs0219,cs0472,MSB3277,CS8632,CS0108,CS0162,CS8321,CS1570,CS1587 echo "发布成功" >> $Logpath echo '发布成功'
4.6 打包压缩
注意这里也是 cd 之后再压缩,否则会按路径压缩
echo "开始打包" >> $Logpath echo '开始打包' file=$1.tar.gz cd $mainpath tar czf $mainpath/$file ./publish echo "打包完成" >> $Logpath echo '打包完成'
4.7 发送文件
rsync -a 和 scp 的效果是一样的,发送到指定服务器的指定目录
向服务器发送 需要两个服务器设置免密
mainserver=root@192.168.2.15 imageserver=root@192.168.123.38 if [ $2 -eq 0 ];then echo "发送" $mainpath/$file >> $Logpath echo '发送' $mainpath/$file ssh $mainserver "mkdir $mainpath" ssh $imageserver "mkdir $mainpath" rsync -a $mainpath/$file $mainserver:$mainpath scp $mainpath/$file $imageserver:$mainpath fi
4.8 附件的下载与发送
echo "得到附件" $3 >> $Logpath if [ -n "$3" ];then assetpath=$mainpath/assets if [ ! -d $assetpath ];then mkdir $assetpath chmod 777 $assetpath fi assets=$3 assets=${assets//,/ } for element in $assets do asseturl=`echo $element | cut -d '|' -f 1` assetname=`echo $element | cut -d '|' -f 2` echo "下载附件" $asseturl "|" $assetname >> $Logpath wget -N $asseturl -O $assetpath/$assetname -P $assetpath done ssh $mainserver "mkdir $mainpath" ssh $mainserver "mkdir $assetpath" ssh $imageserver "mkdir $mainpath" ssh $imageserver "mkdir $assetpath" echo "发送文件" $assetpath >> $Logpath scp -r $assetpath $mainserver:$mainpath scp -r $assetpath $imageserver:$mainpath fi
更新需要经历:
得到当前版本我直接在项目中 增加了API 获取版本
version=$( curl -s http://localhost/api/Version| awk '{print $0}')
具体脚本解释参照上面
#启动 #!/bin/bash if [ 1 -gt $# ] then echo "缺少参数:第1个参数是版本号" exit; fi mainpath=/home/MESReleases/$1 if [ ! -f $mainpath/$1.tar.gz ];then echo "没有版本文件 $mainpath/$1.tar.gz 退出" exit; fi Logpath=/home/MESReleases/log`date '+%Y%m%d'`.log echo " " >> $Logpath echo "———————发布 $1————————–" >> $Logpath version=$( curl -s http://localhost/api/Version| awk '{print $0}') echo "得到版本信息 $version" >> $Logpath echo "得到版本信息 $version" echo "备份 $version" >> $Logpath echo "备份 $version" /home/MESBackup.sh $version echo "停止 $version" >> $Logpath echo "停止 $version" /home/MESpublish/Shutdown.sh echo "更新文件 $1" >> $Logpath echo "更新文件 $1" tar -zxf $mainpath/$1.tar.gz --exclude=publish/log --exclude=publish/appsettings.json -C /home/MESpublish/ echo "启动 $1" >> $Logpath echo "启动 $1"
之后会结合自动测试命令,让发布更敏捷
dotnet test --configuration release --logger:"trx;LogFilePrefix=testResults" -v normal -noconlog
本文作者:没想好
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!