咱們之前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寫的一塌糊塗等等。。歡迎溝通,不理賜教。
晚安~