.NetCore 配合 Gitlab CI&CD 實踐 – 單體項目
- 2020 年 8 月 6 日
- 筆記
- 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
探索實踐,且聽下回分解。