10分鐘實現dotnet程序在linux下的自動部署

背景

一直以來,程序署都是非常麻煩且無聊的事情,在公司一般都會有 devops 方案,整個 cicd 過程涉及的工具還是挺多的,搭建起來比較麻煩。那麼對於一些自己的小型項目,又不想搭建一套這樣的環境,怎麼辦呢。。。前段時間嘗試了一下 阿里雲效 pipeline + gitee + ecs ,還是挺方便的,主要是免費^ ^,服務器也可以用自建的或者其他的,下面就分享一下如何使用

代碼準備

隨便準備個demo項目,並提交到 gitee

## 創建aspnetcore web項目
dotnet new web -o aspnetcoredemo

image-20220702161750722

服務器環境

首先去服務器安裝下 dotnet 運行時,我這裡是用centos。

參考官方文檔 在 CentOS 上安裝 .NET – .NET | Microsoft Docs

## 安裝 .NET 之前,請運行以下命令,將 Microsoft 包簽名密鑰添加到受信任密鑰列表,並添加 Microsoft 包存儲庫。 打開終端並運行以下命令:
sudo rpm -Uvh //packages.microsoft.com/config/centos/7/packages-microsoft-prod.rpm

## 通過 ASP.NET Core 運行時,可以運行使用 .NET 開發且未提供運行時的應用。 以下命令將安裝 ASP.NET Core 運行時,這是與 .NET 最兼容的運行時。 在終端中,運行以下命令:
sudo yum install aspnetcore-runtime-6.0

安裝完成:

image-20220702161204296

自動部署

進入雲效平台流水線

image-20220702162400781

選擇 .NET Core 流水線模板,創建

image-20220702162529035

配置流水線

第一步是配置流水線源

選擇代碼源:碼雲(當然你也可以選別的,github,自建git之類的)

授權一下,然後選擇你的代碼倉庫,默認分支名。下面的工作目錄隨便寫一個,比如:demo

image-20220702162850643

第二步配置構建

image-20220702163537784

image-20220702170309759

主要是執行命令,和打包路徑 注意下,其他的選項默認就行

## cd到項目目錄
cd aspnetcoredemo

## 還原項目
dotnet restore
## 發佈項目
dotnet publish -c Release -o out

第三步配置部署

主機組我這裡選 阿里雲 ecs (你也可以選其他非阿里雲的主機,要裝插件)

image-20220702163915595

添加服務器連接,授權創建即可

image-20220702164445753

選擇主機,下一步,保存(我這裡就一台機器,也可以多台機器部署)

image-20220702164642489

部署腳本:

image-20220702170929035

## 創建目錄
mkdir -p /home/admin/aspnetcoredemo/

## 解壓文件到 /home/admin/aspnetcoredemo/ 目錄
tar zxvf /home/admin/aspnetcoredemo/package.tgz -C /home/admin/aspnetcoredemo/

## 執行部署腳本
sh /home/admin/aspnetcoredemo/deploy.sh restart

部署腳本

這個 deploy.sh 加到項目代碼中,這個腳本的大概內容就是 殺死進程->重新啟動程序->健康檢查->部署完成

內容如下:

#!/bin/bash

# 修改APP_NAME為雲效上的應用名
APP_NAME=aspnetcoredemo


PROG_NAME=$0
ACTION=$1
APP_START_TIMEOUT=20    # 等待應用啟動的時間
APP_PORT=5000          # 應用端口
HEALTH_CHECK_URL=//127.0.0.1:${APP_PORT}/HealthChecks  # 應用健康檢查URL
HEALTH_CHECK_FILE_DIR=/home/admin/status   # 腳本會在這個目錄下生成nginx-status文件
APP_HOME=/home/admin/${APP_NAME} # 從package.tgz中解壓出來的dll放到這個目錄下
DLL_NAME=${APP_HOME}/${APP_NAME}.dll # dll的名字
DLL_OUT=${APP_HOME}/logs/start.log  #應用的啟動日誌

# 創建出相關目錄
mkdir -p ${HEALTH_CHECK_FILE_DIR}
mkdir -p ${APP_HOME}
mkdir -p ${APP_HOME}/logs
usage() {
    echo "Usage: $PROG_NAME {start|stop|restart}"
    exit 2
}

health_check() {
    exptime=0
    echo "checking ${HEALTH_CHECK_URL}"
    while true
        do
            status_code=`/usr/bin/curl -L -o /dev/null --connect-timeout 5 -s -w %{http_code}  ${HEALTH_CHECK_URL}`
            if [ "$?" != "0" ]; then
               echo -n -e "\rapplication not started"
            else
                echo "code is $status_code"
                if [ "$status_code" == "200" ];then
                    break
                fi
            fi
            sleep 1
            ((exptime++))

            echo -e "\rWait app to pass health check: $exptime..."

            if [ $exptime -gt ${APP_START_TIMEOUT} ]; then
                echo 'app start failed'
               exit 1
            fi
        done
    echo "check ${HEALTH_CHECK_URL} success"
}
start_application() {
    echo "starting dotnet process"
    # chmod +x ${DLL_NAME}
    # chmod +x ${APP_HOME}/appsettings.json
    # nohup dotnet ${DLL_NAME} Urls=//*:${APP_PORT} > ${DLL_OUT} 2>&1 &
    cd ${APP_HOME}
    nohup dotnet ${APP_NAME}.dll Urls=//*:${APP_PORT} > ${DLL_OUT} 2>&1 &
    echo "started dotnet process"
}

stop_application() {
   checkdotnetpid=`ps -ef | grep dotnet | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'`
   
   if [[ ! $checkdotnetpid ]];then
      echo -e "\rno dotnet process"
      return
   fi

   echo "stop dotnet process"
   times=60
   for e in $(seq 60)
   do
        sleep 1
        COSTTIME=$(($times - $e ))
        checkdotnetpid=`ps -ef | grep dotnet | grep ${APP_NAME} | grep -v grep |grep -v 'deploy.sh'| awk '{print$2}'`
        if [[ $checkdotnetpid ]];then
            kill -9 $checkdotnetpid
            echo -e  "\r        -- stopping dotnet lasts `expr $COSTTIME` seconds."
        else
            echo -e "\rdotnet process has exited"
            break;
        fi
   done
   echo ""
}
start() {
    start_application
    health_check
}
stop() {
    stop_application
}
case "$ACTION" in
    start)
        start
    ;;
    stop)
        stop
    ;;
    restart)
        stop
        start
    ;;
    *)
        usage
    ;;
esac

image-20220702171223342

記得複製到輸出目錄:

image-20220702171421380

增加一個 HealthChecks 接口用於部署腳本的健康檢查:
image-20220702172152560

手動構建

流水線 點擊運行,如果前面配置沒有問題的話,可以看到構建部署成功。

image-20220702172815932

訪問一下,ok:

image-20220702173039889

自動構建

下面通過 webhook 配置,實現提交代碼,自動構建部署

流水線,選擇觸發配置,打開 webhook 觸發:

image-20220702173719962

將這個 webhook 地址複製,配置到你的 gitee 倉庫中,保存:

image-20220702173814426

接下來隨便修改下代碼,測試下:

image-20220702173951884

提交代碼後自動觸發了流水線構建部署:

image-20220702174111077

ok:

image-20220702175351961

結束

Happy coding …