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

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

寫在前面

咱們之前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配置等等。哦對了,咱們目前的構建步驟大概是:

  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寫的一塌糊塗等等。。歡迎溝通,不理賜教。

晚安~

相關文章
相關標籤/搜索