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

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

### 前言 上一篇博文 [.NetCore 配合 Gitlab CI&CD 實踐 - 開篇](https://gridea.run/post/netcore%E9%85%8Dgitlabci_cd%E5%AE%9E%E8%B7%B5-%E5%BC%80%E7%AF%87/),主要簡單的介紹了一下 `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 開啟應該是下面這個樣子: ![image.png](https://i.loli.net/2020/08/05/X3eZDcpJKCywWdB.png) **專案上傳至 GitLab** 在 gitlab 上新建一個 `hello-world` 的專案,將本地的專案上傳。這個按照如下提示操作即可: ![image.png](https://i.loli.net/2020/08/05/CzomNwcBLGZpbRO.png) 專案上傳成功後,切一個 dev 分支出來,我這裡的策略是,程式碼提交到 dev 分支是自動釋出到開發環境進行驗證的,生產環境是通過 master 分支打 tag 進行釋出的。 * 切換到 dev 分支! * 切換到 dev 分支! * 切換到 dev 分支! **新增相關指令碼** 在 `hello-world` 資料夾內建立 `.build/docker` 資料夾,並新增如下指令碼以及`Dockerfile`: * build-image.sh ```shell docker build -f .build/docker/Dockerfile --build-arg PROJECT=$1 --build-arg ASPNETCORE_ENVIRONMENT=$2 -t $3 . ``` * build-project.sh ```shell 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 ```shell NEW_TAG="registry.cn-hangzhou.aliyuncs.com/xxx/$1"; // 這裡得用你自己名稱空間哦 docker tag $1 $NEW_TAG docker push $NEW_TAG docker rmi $NEW_TAG ``` * Dockerfile ```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` 構建出來的映象體積只有其他映象版本構建出來體積的一半。推薦使用。到此目錄結構就成了現在這樣: ![image.png](https://i.loli.net/2020/08/06/S6GthqUaOZrN19T.png) 至此準備工作已經差不多了!我們先簡單過一下 CI 的流程: 提交程式碼 --> 編譯 --> 測試 --> 構建映象 --> 釋出 ### 編譯 -- Build 在 `hello-world` 目錄下新增 `.gitlab-ci.yml` 檔案,新增 `build` 任務: ```yaml 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,節約時間。這裡執行會出現如下錯誤: ```shell /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 介面,執行成功,是不是很開心呢? ![image.png](https://i.loli.net/2020/08/06/mZbsMlArQRp8hFi.png) ### 測試 -- Test 現在專案裡面沒有測試程式碼,那就新建一個吧。在 `hello-world` 根目錄下: ``` mkdir test cd test dotnet new xunit -n GitLabCIDemo.UnitTests ``` 更新 `.gitlab-ci.yml` 新增 Test 任務: ```yaml 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 執行。 ![image.png](https://i.loli.net/2020/08/06/wRVcJ9I4FdEWUGO.png) ### 構建 Docker 映象 -- Pack 我這裡使用的是阿里雲的映象倉庫,需要現在阿里雲上建立對應的名稱空間以及映象名稱。我這裡給映象名取名為 `hello-world`,別忘了修改 `push-image.sh` 中的名稱空間哦! ![image.png](https://i.loli.net/2020/08/06/Qqvc6rGRMpViews.png) 更新 `.gitlab-ci.yml` 新增 Pack 任務: ```yaml 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 應該執行的差不多,再去瞧瞧唄! 又是全綠,真是開心!額,全綠,怪怪的... ![image.png](https://i.loli.net/2020/08/06/J5HT7rGWt24vw6M.png) 開啟阿里雲映象容器服務,檢視一下剛剛上傳的容器映象吧! ![image.png](https://i.loli.net/2020/08/06/vjzTqAB378NH2Jh.png) ### 部署 -- 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 執行結果 ![image.png](https://i.loli.net/2020/08/06/WOyHbhBGfqKiE7l.png) 通過伺服器IP + 5013 訪問應用了,就可以看到服務更新 ![image.png](https://i.loli.net/2020/08/06/6PvYdEaZerSnMjb.png) 修改一下 `Index.cshtml` 將 `Welcome` 修改為 `Hello Devops !` ,重新提交一下,稍等片刻,重新訪問即可看到變化了。 ![image.png](https://i.loli.net/2020/08/06/94dZqRzUbMAtPeG.png) 至此一個簡單的 CI 流程已經走完了,各位看官可以根據自己的需求,繼續探索。 ### 題外話 如果將指令碼都放在專案裡面的話,將來涉及到指令碼變更,需要每個專案都給改過去,這是十分痛苦的事情。這裡推薦小夥伴可以通過 `git submodule` 子模組的方式進行引用,將公共的指令碼都給提取出來,專案通過子模組來載入指令碼專案,將來指令碼變更,每個專案只需要更新一下子模組就好。 ### 總結 通過以上一個小案例已經帶小夥伴瞭解了一圈 `GitLab-CI` 如何來發佈一個 `.net core` 應用,感受了一下 `GitLab-ci` 的魅力。但是以上方案還是有瑕疵的,對於單體應用來說,沒有太大問題,但並不適合微服務專案。在微服務專案中,如果多個服務散落在多個倉庫中,需要多個專案程式碼改動其實是很不方便的,所以現在很多的微服務專案都採用 `Mono` 倉庫風格及將所有的服務都放在一個倉庫裡面,倉庫體積雖然大,但是改動起來更方便。本篇就先到這裡了,有關於 `GitLab-CI` 對於 `Mono` 倉庫風格專案 `CI&CD` 探索實踐,且聽下回分解。