Asp.net Core 使用Jenkins + Dockor 實現持續集成、自動化部署(四):發布與回滾


“deploy”的图片搜索ç"“æžœ

寫在前面

我們以前windows跑.net Framework程序的時候,發布,自己乖乖的替換程序;備份,也是自己一個一個的重命名備份;回滾,發布遇到問題的回滾更是不用說了;運維很是怕我們 這些用windows的啊;

那全面擁抱linux的一一.net core 時代 ,是如何處理這些個問題的呢?

噔噔蹬蹬~請往下看。

運行環境

centos:7.2
cpu:1核 2G內存 1M帶寬

Jenkins ver. 2.150.1

一台安裝jenkins的機器。

(本文例子不一定要安裝jenkins,但實際項目是要用jenkins的)

背景

我們目前的應用部署環境是這樣划分的(暫定):

開發環境

環境變量:Development

開發環境就是我們平時的開發用的機器,錯誤、異常盡可能多的報出來這種。css、js、頁面文件等各種靜態資源也不做壓縮處理,連接測試庫;

開發環境的部署:開發人員按自己習慣自己部署;

測試環境

環境變量:Staging

測試環境也就是測試同學測試用的環境,為了貼合生產環境的多機器部署,我們測試機器也有多台,目前我們搭建了jenkins可由測試同學自己部署;錯誤信息已做捕捉處理,靜態文件同樣不壓縮,連接測試庫;

測試環境的部署:docker+docker-compose部署,我們在項目里面編寫好了Staging.Dockerfile、docker-compose.yml還有對應的測試環境發布的shell腳本,借助jenkins來進行參數化的構建。參數包括程序運行的端口、綁定的ip,consul配置等等。哦對了,我們目前的構建步驟大概是:

  1. 去gitlab拉取最新程序代碼;

  2. 執行單元測試和集成測試,只有通過單元測試和集成測試才能繼續步驟3,否則部署失敗終止

  3. dotnet restore->build->publish,將生成產品打包成一個鏡像;

  4. 使用docker-compose down 停止、移除上次的構建;

  5. 使用docker-compose up 這個強大的命令,構建新的鏡像、啟動容器;

  6. 清除臨時鏡像,構建完成;

單元測試用dotnet test 命令;

這里我們還可以看到,配置文件也一並被打包到鏡像里面了,修改配置文件也需要重新構建的;

預生產環境

環境變量:Staging

預生產環境是相對於測試環境來說,無論數據、配置還是架構都是更加接近生產環境的存在了。一般還是連接的數據庫是預生產環境的數據庫(同步了生產環境的數據的),甚至有的使用會直接連接生產環境的庫(一般不練、只讀賬號等控制);不過我們公司還是連接的測試庫img

然后靜態文件壓縮啊、什么的這些,生產環境怎么處理,這里也怎么處理;

通過測試環境測試的程序才可以部署到這里,這里測試通過后,才可以部署到生產環境;

預生產環境的部署:由項目負責人或者運維部署,需要比較大權限才可以;

生產環境

環境變量:Production

生產環境一般應配置為最大限度地提高安全性、性能和應用可靠性,包括但不限於以下舉措:

  1. 全面啟用分布式緩存
  2. 客戶端資源被捆綁和縮小,並可能從 CDN (網絡分發)提供。
  3. 必須禁用診斷錯誤頁。
  4. 啟用友好錯誤頁、一致的錯誤響應。
  5. 啟用生產記錄和監視。

生產環境的部署:運維部署,我們開發沒有權限了;

部署的背景我們的條件等等大概講完了,下面我們說說生產環境我們怎么設計容器的。

生產環境的容器設計

由於生產環境經常需要修改配置、保留日志信息、需考慮程序的備份與回滾等等,我們不能像上面的測試環境一樣,把整個發布的產品打包成一個鏡像了,我們需要做特殊的處理;

熟悉docker的同學,肯定會想到:掛載

對的,我們就這么處理,我們用docker -v 處理這頭痛的問題;

程序的目錄結構

1551588236442

我們程序的目錄結構是這樣的:

backs:放歷史版本的程序文件,按備份日期壓縮命名;

logs:程序的運行日志文件;

program:當前運行的程序;

logs 和 program 目錄,使用 docker -v 掛載;

backs目錄截圖:

1551591640526

發布

發布步驟

  1. 同步通過測試的預生產環境的程序文件;

  2. 壓縮、備份上一版本的程序文件;

  3. 通過更改文件夾名稱的方式,當前運行程序替換為最新的;

  4. 重啟程序;

  5. 心跳檢測:通過輸出部署成功,未通過執行回滾操作。

發布腳本(Production.Publish.sh)

#!/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

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"]

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/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



最后貼一個運行截圖:

1551590930566

總結

毫不誇張地說,Jenkins + Dockor 讓.net 完全從一個刀耕火種的原始人一下子穿越到了全自動化的現代;

文章的思路可以借鑒,腳本改改也可以用,但需理解思路;

有的同學可能會問,為什么生產環境的部署,不能像測試環境一樣直接拉取master的代碼構建,我這里的回答是涉及到配置的權限問題、devops的學習到位問題。歷史原因等,我們暫定這樣,后面實踐,我樂於分享;

本文的實踐都有很大的局限性,比如有現成的工具、有更強大的插件等等可以更簡單的去解決這個問題之類的,我可能還不知道;比如我的shell寫的一塌糊塗等等。。歡迎溝通,不理賜教。

晚安~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM