.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.cshtml
將 Welcome
修改為 Hello Devops !
,重新提交一下,稍等片刻,重新訪問即可看到變化了。
至此一個簡單的 CI 流程已經走完了,各位看官可以根據自己的需求,繼續探索。
題外話
如果將指令碼都放在專案裡面的話,將來涉及到指令碼變更,需要每個專案都給改過去,這是十分痛苦的事情。這裡推薦小夥伴可以通過 git submodule
子模組的方式進行引用,將公共的指令碼都給提取出來,專案通過子模組來載入指令碼專案,將來指令碼變更,每個專案只需要更新一下子模組就好。
總結
通過以上一個小案例已經帶小夥伴瞭解了一圈 GitLab-CI
如何來發佈一個 .net core
應用,感受了一下 GitLab-ci
的魅力。但是以上方案還是有瑕疵的,對於單體應用來說,沒有太大問題,但並不適合微服務專案。在微服務專案中,如果多個服務散落在多個倉庫中,需要多個專案程式碼改動其實是很不方便的,所以現在很多的微服務專案都採用 Mono
倉庫風格及將所有的服務都放在一個倉庫裡面,倉庫體積雖然大,但是改動起來更方便。本篇就先到這裡了,有關於 GitLab-CI
對於 Mono
倉庫風格專案 CI&CD
探索實踐,且聽下回分解。