1. 程式人生 > 實用技巧 >.NetCore 配合 Gitlab CI&CD 實踐 - 單體專案

.NetCore 配合 Gitlab CI&CD 實踐 - 單體專案

前言

上一篇博文 .NetCore 配合 Gitlab CI&CD 實踐 - 開篇,主要簡單的介紹了一下 GitLab CI 的持續整合以及持續部署,這篇將通過 GitLab CI 釋出一個 .net core 專案,來帶小夥伴們感受一下自動化的魅力,從此告別手動釋出。

準備工作

建立一個空MVC專案來進行演示:

mkdir hello-world
cd hello-world
dotnet new sln -n HelloWorld
mkdir src
cd src
dotnet new mvc -n GitLabCIDemo
cd ../
dotnet sln add .\src\GitLabCIDemo\GitLabCIDemo.csproj

完成以上建立後,用 vscode 開啟應該是下面這個樣子:

專案上傳至 GitLab

在 gitlab 上新建一個 hello-world 的專案,將本地的專案上傳。這個按照如下提示操作即可:

專案上傳成功後,切一個 dev 分支出來,我這裡的策略是,程式碼提交到 dev 分支是自動釋出到開發環境進行驗證的,生產環境是通過 master 分支打 tag 進行釋出的。

  • 切換到 dev 分支!
  • 切換到 dev 分支!
  • 切換到 dev 分支!

新增相關指令碼

hello-world 資料夾內建立 .build/docker 資料夾,並新增如下指令碼以及Dockerfile:

  • build-image.sh
docker build -f .build/docker/Dockerfile --build-arg PROJECT=$1 --build-arg ASPNETCORE_ENVIRONMENT=$2 -t $3 .
  • build-project.sh
set -e
for arg in "$@"
do
    target=$(pwd)/src/$arg
    dotnet restore -v n $target
    dotnet publish -c Release -o $target/publish $target
done
  • push-image.sh
NEW_TAG="registry.cn-hangzhou.aliyuncs.com/xxx/$1"; // 這裡得用你自己名稱空間哦
docker tag $1 $NEW_TAG
docker push $NEW_TAG
docker rmi $NEW_TAG
  • Dockerfile
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-alpine
ARG PROJECT
ARG ASPNETCORE_ENVIRONMENT
ENV ASPNETCORE_ENVIRONMENT ${ASPNETCORE_ENVIRONMENT}
WORKDIR /app
COPY src/${PROJECT}/publish .
RUN echo "#!/bin/bash \n dotnet ${PROJECT}.dll" > start.sh && chmod +x ./start.sh
ENTRYPOINT ["./start.sh"]

這裡構建映象所使用 3.1-alpine 構建出來的映象體積只有其他映象版本構建出來體積的一半。推薦使用。到此目錄結構就成了現在這樣:

至此準備工作已經差不多了!我們先簡單過一下 CI 的流程:

提交程式碼 --> 編譯 --> 測試 --> 構建映象 --> 釋出

編譯 -- Build

hello-world 目錄下新增 .gitlab-ci.yml 檔案,新增 build 任務:

stages:
  - build

helloworld-build:
  stage: build
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - .build/docker/build-project.sh GitLabCIDemo
  artifacts:
    paths:
      - src/*/bin
      - src/*/publish

這裡起一個容器來跑編譯任務,具體細節可以看 build-project.sh 指令碼,用 artifacts 將釋出出來的資源上傳,給後面的 構建任務使用,不需要重複 build,節約時間。這裡執行會出現如下錯誤:

/bin/bash: line 89: .build/docker/build-project.sh: Permission denied

這是因為指令碼沒有執行許可權,通過 chmod 命令可以解決:

chmod +x build-image.sh build-project.sh push-image.sh

重新提交,觸發 build 任務。開啟 GitLab CI 介面,執行成功,是不是很開心呢?

測試 -- Test

現在專案裡面沒有測試程式碼,那就新建一個吧。在 hello-world 根目錄下:

mkdir test
cd test
dotnet new xunit -n GitLabCIDemo.UnitTests

更新 .gitlab-ci.yml 新增 Test 任務:

stages:
  - build
  - test

helloworld-build:
  stage: build
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - .build/docker/build-project.sh GitLabCIDemo
  artifacts:
    paths:
      - src/*/bin
      - src/*/publish

helloworld-test:
  stage: test
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - dotnet test -c Release
  dependencies:
    - helloworld-build

等待一會,檢視 CI 執行。

構建 Docker 映象 -- Pack

我這裡使用的是阿里雲的映象倉庫,需要現在阿里雲上建立對應的名稱空間以及映象名稱。我這裡給映象名取名為 hello-world,別忘了修改 push-image.sh 中的名稱空間哦!

更新 .gitlab-ci.yml 新增 Pack 任務:

stages:
  - build
  - test
  - pack

helloworld-build:
  stage: build
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - .build/docker/build-project.sh GitLabCIDemo
  artifacts:
    paths:
      - src/*/bin
      - src/*/publish

helloworld-test:
  stage: test
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - dotnet test -c Release
  dependencies:
    - helloworld-build

helloworld-pack-staging:
  stage: pack
  tags:
    - shell
  script:
    - .build/docker/build-image.sh GitLabCIDemo Staging hello-world:beta
    - .build/docker/push-image.sh hello-world:beta
  dependencies:
    - helloworld-build
  only:
    - dev
  • Staging: 用來設定環境變數 ASPNETCORE_ENVIRONMENT,讓 .net core 讀取對應的配置檔案,可以設定Development,Staging,Production 三種,可以在對應的環境設定對應環境變數,使用不同配置。

  • beta: 因為是開發環境,就一直使用同一個 tag 去覆蓋之前的映象,每次 pull 最新的映象就好了,也可以使用 $CI_COMMIT_SHORT_SHA 使用當前 git 提交的 hash 值作為版本號

CI 應該執行的差不多,再去瞧瞧唄! 又是全綠,真是開心!額,全綠,怪怪的...

開啟阿里雲映象容器服務,檢視一下剛剛上傳的容器映象吧!

部署 -- Deploy

這裡我圖方便就使用 docker-compose 來做演示了,通常部署環境都是使用叢集來部署的,當然單機部署也不是不無可能的,我內網用 k3s 搭建的一個叢集,為啥不用 k8s,因為要求資源配置比較高,k3s 剛好夠用。但是部署到 k3s 需要寫挺多的配置的檔案,可以單獨寫一篇博文介紹。

作為自動化最後一步,無論你是用 k8s,k3s,docker swarm......,都是拉取對應的映象,進行部署。思路是一樣的,只是部署方式略有不同。這裡通過 docker-compose 來發布 hello-world 應用咯。

在部署的 Linux 伺服器上建立資料夾 /deploy ,在目錄下新增 docker-compose.yml 檔案,新增如下內容:

version: "3.8"
services:
  hello-world:
    image: registry.cn-hangzhou.aliyuncs.com/jd-rd/hello-world:beta
    container_name: hello-world
    restart: always
    ports: 
      - 5013:80
    networks:
      - basic_service  

networks:
  basic_service:

更新 .gitlab-ci.yml,新增部署任務:

stages:
  - build
  - test
  - pack
  - deploy

helloworld-build:
  stage: build
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - .build/docker/build-project.sh GitLabCIDemo
  artifacts:
    paths:
      - src/*/bin
      - src/*/publish

helloworld-test:
  stage: test
  tags:
    - docker
  image: mcr.microsoft.com/dotnet/core/sdk:3.1
  script:
    - dotnet test -c Release
  dependencies:
    - helloworld-build

helloworld-pack-staging:
  stage: pack
  tags:
    - shell
  script:
    - .build/docker/build-image.sh GitLabCIDemo Staging hello-world:beta
    - .build/docker/push-image.sh hello-world:beta
  dependencies:
    - helloworld-build
  only:
    - dev

deploy-staging:
  stage: deploy
  tags:
    - staging
  script:
    - cd /deploy && docker-compose pull && docker-compose up --force-recreate -d && docker ps
  only:
    - dev

等待整個CI跑完,檢視 CI 執行結果

通過伺服器IP + 5013 訪問應用了,就可以看到服務更新

修改一下 Index.cshtmlWelcome 修改為 Hello Devops ! ,重新提交一下,稍等片刻,重新訪問即可看到變化了。

至此一個簡單的 CI 流程已經走完了,各位看官可以根據自己的需求,繼續探索。

題外話

如果將指令碼都放在專案裡面的話,將來涉及到指令碼變更,需要每個專案都給改過去,這是十分痛苦的事情。這裡推薦小夥伴可以通過 git submodule 子模組的方式進行引用,將公共的指令碼都給提取出來,專案通過子模組來載入指令碼專案,將來指令碼變更,每個專案只需要更新一下子模組就好。

總結

通過以上一個小案例已經帶小夥伴瞭解了一圈 GitLab-CI 如何來發佈一個 .net core 應用,感受了一下 GitLab-ci 的魅力。但是以上方案還是有瑕疵的,對於單體應用來說,沒有太大問題,但並不適合微服務專案。在微服務專案中,如果多個服務散落在多個倉庫中,需要多個專案程式碼改動其實是很不方便的,所以現在很多的微服務專案都採用 Mono 倉庫風格及將所有的服務都放在一個倉庫裡面,倉庫體積雖然大,但是改動起來更方便。本篇就先到這裡了,有關於 GitLab-CI 對於 Mono 倉庫風格專案 CI&CD 探索實踐,且聽下回分解。