写在前面
我们以前windows跑.net Framework程序的时候发布自己乖乖的替换程序备份也是自己一个一个的重命名备份回滚发布遇到问题的回滚更是不用说了运维很是怕我们 这些用windows的啊
那全面拥抱linux的一一.net core 时代 是如何处理这些个问题的呢
噔噔蹬蹬~请往下看。
运行环境
centos7.2
cpu:1核 2G内存 1M带宽
一台安装jenkins的机器。
本文例子不一定要安装jenkins但实际项目是要用jenkins的
背景
我们目前的应用部署环境是这样划分的(暂定)
开发环境
环境变量Development
开发环境就是我们平时的开发用的机器错误、异常尽可能多的报出来这种。css、js、页面文件等各种静态资源也不做压缩处理连接测试库
开发环境的部署开发人员按自己习惯自己部署
测试环境
环境变量Staging
测试环境也就是测试同学测试用的环境为了贴合生产环境的多机器部署我们测试机器也有多台目前我们搭建了jenkins可由测试同学自己部署错误信息已做捕捉处理静态文件同样不压缩连接测试库
测试环境的部署docker+docker-compose部署我们在项目里面编写好了Staging.Dockerfile、docker-compose.yml还有对应的测试环境发布的shell脚本借助jenkins来进行参数化的构建。参数包括程序运行的端口、绑定的ipconsul配置等等。哦对了我们目前的构建步骤大概是
去gitlab拉取最新程序代码
执行单元测试和集成测试只有通过单元测试和集成测试才能继续步骤3否则部署失败终止
dotnet restore->build->publish将生成产品打包成一个镜像
使用docker-compose down 停止、移除上次的构建
使用docker-compose up 这个强大的命令构建新的镜像、启动容器
清除临时镜像构建完成
单元测试用dotnet test 命令
这里我们还可以看到配置文件也一并被打包到镜像里面了修改配置文件也需要重新构建的
预生产环境
环境变量Staging
预生产环境是相对于测试环境来说无论数据、配置还是架构都是更加接近生产环境的存在了。一般还是连接的数据库是预生产环境的数据库(同步了生产环境的数据的)甚至有的使用会直接连接生产环境的库(一般不练、只读账号等控制)不过我们公司还是连接的测试库
然后静态文件压缩啊、什么的这些生产环境怎么处理这里也怎么处理
通过测试环境测试的程序才可以部署到这里这里测试通过后才可以部署到生产环境
预生产环境的部署由项目负责人或者运维部署需要比较大权限才可以
生产环境
环境变量Production
生产环境一般应配置为最大限度地提高安全性、性能和应用可靠性包括但不限于以下举措
全面启用分布式缓存
客户端资源被捆绑和缩小并可能从 CDN (网络分发)提供。
必须禁用诊断错误页。
启用友好错误页、一致的错误响应。
启用生产记录和监视。
生产环境的部署运维部署我们开发没有权限了
部署的背景我们的条件等等大概讲完了下面我们说说生产环境我们怎么设计容器的。
生产环境的容器设计
由于生产环境经常需要修改配置、保留日志信息、需考虑程序的备份与回滚等等我们不能像上面的测试环境一样把整个发布的产品打包成一个镜像了我们需要做特殊的处理
熟悉docker的同学肯定会想到挂载
对的我们就这么处理我们用docker -v 处理这头痛的问题
程序的目录结构
我们程序的目录结构是这样的
backs:放历史版本的程序文件按备份日期压缩命名
logs:程序的运行日志文件
program:当前运行的程序
logs 和 program 目录使用 docker -v 挂载
backs目录截图:
发布
发布步骤
同步通过测试的预生产环境的程序文件
压缩、备份上一版本的程序文件
通过更改文件夹名称的方式当前运行程序替换为最新的
重启程序
心跳检测通过输出部署成功未通过执行回滚操作。
发布脚本(Production.Publish.sh)
#!/bin/bashfunction success() { echo -e "\033[32m $1 \033[0m" } function error() { echo -e "\033[31m\033[01m $1 \033[0m" } echo "publish beging。。。。。。" remotePath=$1 healthCheckUrl=$2 defaulPaht= $3; bashPath=${defaulPaht:=`pwd`} if [ ! $remotePath ]; then echo "warn:remotePath should't be empty!" exit fi if [ ! $bashPath ]; then error "error:bashPath should't be empty!" exit fi echo "bashpath is ${bashPath}" programPath="${bashPath}/program" logPath="${bashPath}/logs" backPath="${bashPath}/backs" publisTemp="${bashPath}/publisTemp" mkdir -p $programPath mkdir -p $logPath mkdir -p $backPath mkdir -p $publisTemp#remote git or scp#这里同步预生产环境的程序文件这里写死了ip只是示例scp也只是示例#大家可以采用更安全更有效率的同步文件方式scp -r root@139.199.196.67:${remotePath}"/.*" ${publisTemp} if [ $? ]; then echo "info:copy successful!" #压缩、备份当前运行程序到backs文件夹 backFileName=`date +%Y%m%d%H%M%S`".tar.gz" `cd ${programPath} && tar -zcPf ${backPath}/${backFileName} *` #replace #替换程序 if [ $? ]; then mv $programPath ${programPath}"Old" mv $publisTemp ${programPath} rm -r ${programPath}"Old" #publis fail then Production.Rollback if [ $healthCheckUrl ]; then curl $healthCheckUrl if [ $? -ne 0 ]; then error "error:public failed" #心跳检测失败执行回滚 if [ -f "Production.Rollback.sh" ];then echo "************************************ exec Rollbacking...... ************************************" ./Production.Rollback.sh ${backPath} else error "error:Production.Rollback.sh is not existing"; fi exit fi fi success "publish Successful" else error "error:file tar failed" fi else error "error:remote files copy failed,Maybe you should checkout your ssh auth!" fi
Dockerfile
Dockerfile比较简单
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS baseWORKDIR /appARG RUN_PORT=${RUN_PORT:-""} ARG CONSUL_TO_NETCOREHOST=${CONSUL_TO_NETCOREHOST:-""} ARG ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT:-""} ENV RUN_PORT=${RUN_PORT} CONSUL_TO_NETCOREHOST=${CONSUL_TO_NETCOREHOST} ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT}ENTRYPOINT ["dotnet", "Member.WebApi.dll"]
docker-compose
version: '3.4'services: member.webapi: image: memberwebapi${RUN_PORT} build: context: . dockerfile: ${ASPNETCORE_ENVIRONMENT}.Dockerfile network_mode: "host" restart: always environment: - RUN_PORT=${RUN_PORT} - ASPNETCORE_ENVIRONMENT=${ASPNETCORE_ENVIRONMENT} - CONSUL_TO_NETCOREHOST=${CONSUL_TO_NETCOREHOST} command: - "--port" - "${RUN_PORT}" #就是这里挂载 volumes: - ../program/:/app/ - ../logs/:/app/logs
回滚
回滚其实就是发布的逆操作
发布是:同步最新程序->备份当前运行程序->替换
回滚是->找到上一次的备份->删掉的当前运行程序->替换
Production.Rollback.sh
#!/bin/bashecho "rollback beging。。。。。。"defaulPaht= $1; bashPath=${defaulPaht:=`pwd`}programPath="${bashPath}/program"backPath="${bashPath}/backs"lastFile=`cd ${backPath} &&ls -t |head -n1|awk '{print $0}'`if [ ! $lastFile ];then echo "error:none backup program"filastFilePath="${backPath}/${lastFile}"echo $lastFilePathif [ -f $lastFilePath ];then echo "rollback program:${lastFilePath}" programOldPath="${programPath}Old" mkdir -p ${programOldPath} tar zxvf ${lastFilePath} -C ${programOldPath} #replace if [ $? ]; then rm -r ${programPath} mv ${programOldPath} ${programPath} echo "rollback Successful" else echo "error:backup program is not existing!" fi else echo "error:backup program is not existing!"fi
最后贴一个运行截图
总结
毫不夸张地说Jenkins + Dockor 让.net 完全从一个刀耕火种的原始人一下子穿越到了全自动化的现代
文章的思路可以借鉴脚本改改也可以用但需理解思路
有的同学可能会问为什么生产环境的部署不能像测试环境一样直接拉取master的代码构建我这里的回答是涉及到配置的权限问题、devops的学习到位问题。历史原因等我们暂定这样后面实践我乐于分享
本文的实践都有很大的局限性比如有现成的工具、有更强大的插件等等可以更简单的去解决这个问题之类的我可能还不知道比如我的shell写的一塌糊涂等等。。欢迎沟通不理赐教。
晚安~
作者乔达摩 (嘿~)
出处https://www.cnblogs.com/xiaxiaolu/p/10468612.html