咱们之前windows跑.net Framework程序的时候,发布,本身乖乖的替换程序;备份,也是本身一个一个的重命名备份;回滚,发布遇到问题的回滚更是不用说了;运维非常怕咱们 这些用windows的啊;css
那全面拥抱linux的一一.net core 时代 ,是如何处理这些个问题的呢?linux
噔噔蹬蹬~请往下看。git
centos:7.2
cpu:1核 2G内存 1M带宽web
Jenkins ver. 2.150.1docker
一台安装jenkins的机器。shell
(本文例子不必定要安装jenkins,但实际项目是要用jenkins的)数据库
咱们目前的应用部署环境是这样划分的(暂定):windows
环境变量:Developmentcentos
开发环境就是咱们平时的开发用的机器,错误、异常尽量多的报出来这种。css、js、页面文件等各类静态资源也不作压缩处理,链接测试库;api
开发环境的部署:开发人员按本身习惯本身部署;
环境变量:Staging
测试环境也就是测试同窗测试用的环境,为了贴合生产环境的多机器部署,咱们测试机器也有多台,目前咱们搭建了jenkins可由测试同窗本身部署;错误信息已作捕捉处理,静态文件一样不压缩,链接测试库;
测试环境的部署:docker+docker-compose部署,咱们在项目里面编写好了Staging.Dockerfile、docker-compose.yml还有对应的测试环境发布的shell脚本,借助jenkins来进行参数化的构建。参数包括程序运行的端口、绑定的ip,consul配置等等。哦对了,咱们目前的构建步骤大概是:
去gitlab拉取最新程序代码;
执行单元测试和集成测试,只有经过单元测试和集成测试才能继续步骤3,不然部署失败终止:
dotnet restore->build->publish,将生成产品打包成一个镜像;
使用docker-compose down 中止、移除上次的构建;
使用docker-compose up 这个强大的命令,构建新的镜像、启动容器;
清除临时镜像,构建完成;
单元测试用dotnet test 命令;
这里咱们还能够看到,配置文件也一并被打包到镜像里面了,修改配置文件也须要从新构建的;
环境变量:Staging
预生产环境是相对于测试环境来讲,不管数据、配置仍是架构都是更加接近生产环境的存在了。通常仍是链接的数据库是预生产环境的数据库(同步了生产环境的数据的),甚至有的使用会直接链接生产环境的库(通常不练、只读帐号等控制);不过咱们公司仍是链接的测试库
而后静态文件压缩啊、什么的这些,生产环境怎么处理,这里也怎么处理;
经过测试环境测试的程序才能够部署到这里,这里测试经过后,才能够部署到生产环境;
预生产环境的部署:由项目负责人或者运维部署,须要比较大权限才能够;
环境变量:Production
生产环境通常应配置为最大限度地提升安全性、性能和应用可靠性,包括但不限于如下举措:
生产环境的部署:运维部署,咱们开发没有权限了;
部署的背景咱们的条件等等大概讲完了,下面咱们说说生产环境咱们怎么设计容器的。
因为生产环境常常须要修改配置、保留日志信息、需考虑程序的备份与回滚等等,咱们不能像上面的测试环境同样,把整个发布的产品打包成一个镜像了,咱们须要作特殊的处理;
熟悉docker的同窗,确定会想到:挂载
对的,咱们就这么处理,咱们用docker -v 处理这头痛的问题;
咱们程序的目录结构是这样的:
backs:放历史版本的程序文件,按备份日期压缩命名;
logs:程序的运行日志文件;
program:当前运行的程序;
logs 和 program 目录,使用 docker -v 挂载;
backs目录截图:
同步经过测试的预生产环境的程序文件;
压缩、备份上一版本的程序文件;
经过更改文件夹名称的方式,当前运行程序替换为最新的;
重启程序;
心跳检测:经过输出部署成功,未经过执行回滚操做。
#!/bin/bash function 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比较简单
FROM microsoft/dotnet:2.1-aspnetcore-runtime AS base WORKDIR /app ARG 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"]
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
回滚其实就是发布的逆操做;
发布是:同步最新程序->备份当前运行程序->替换;
回滚是->找到上一次的备份->删掉的当前运行程序->替换;
#!/bin/bash echo "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!" fi lastFilePath="${backPath}/${lastFile}" echo $lastFilePath if [ -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写的一塌糊涂等等。。欢迎沟通,不理赐教。
晚安~