1. 程式人生 > >【乾貨】.NetCore Gitlab-CI/CD實踐和排坑指南

【乾貨】.NetCore Gitlab-CI/CD實踐和排坑指南

引言

         看過前文的博友可能注意到我是把 部署dll檔案拷貝到生產機器,之後在生產機器上使用docker-compose即時建立映象, 並沒有完成CI/CD, 只是在原來傳統部署方式下 將部署檔案容器化。

         經過長時間實操驗證,終於完成基於Gitlab的CI/CD實踐,本次實踐的坑位很多, 實操的過程儘量接近 最佳實踐(不做hack, 不做騷操作),記錄下來也方便自己加深理解。

        第一部分: Gitlab CI/CD 原理 和 Gitlab Runner 安裝(這裡使用shell執行器)

        第二部分: Gitlab CI/CD 實踐:

  •      巨集觀專案架構圖
  •      解決方案開發目錄
  •     .gitlab-ci.yml 檔案
  •      專案部署目錄

第一部分:gitlab CICD原理

       ① Gitlab CI/CD架構:

 

  • Gitlab CI/CD  儲存【定義的構建】和【構建狀態】的api應用程式, 提供友好的介面管理專案構建,  構建過程由 .gitlab-ci.yml 檔案定義,而這個檔案一般置於程式碼倉庫的根目錄。
  • Gitlab Runner  執行構建過程的應用程式,可與gitlab Server 形成分散式部署, 如上圖所示, 其通過api 與gitlab Server互動

   

  ② Gitlab CI/CD 配置介面 & Gitlab Runner 安裝

           Gitlab CICD的介面配置許可權取決於你在gitlab server 中的角色,我的角色是maintainer, 足夠建立自定義的runner。

            本次演示的是建立自定義Runner,gitlab runner安裝完畢,很明顯現在需要與gitlab專案建立聯絡,這就是向gitlab runner註冊專案的過程。

      註冊時需要關注的兩個配置是:

  •     tags  可理解為與這個Runner有關的Pipeline任務, 在.gitlab-ci.yml  要用到
  •     runner  executor:可理解為執行的初始環境,這裡使用shell方式

      註冊過程和結果請參考下圖:

 

第二部分:基於docker-compose的Gitlab-CI  實踐

     ①  專案架構圖

      

       我們的目標是在部署機器上使用docker-compose拉取Gitlab CI生成的ReceiverAPP, webAPP遠端映象,快速產生容器。 

  •      對每一次提交或合併都會執行 build 任務, 形成Continous Intergation

  •       對git: tag會執行build_Image任務,上述兩個任務都成功,會自動執行 deploy_staging任務,這樣就能形成基於git:tag的部署版本管理(部署出錯,也能很快回滾到上次的部署tag)

本處使用Gitlab Runner 伺服器作為staging部署機器; 原則上不允許隨意部署Prod, 常規讓開發人員手動登陸到 Prod機器上執行部署命令,以下GitLab-CI 也沒有完成Prod的自動部署過程,自行補上登陸終端的指令碼即可。

  ②  開發目錄

   .gitlab-ci.yml 需要放置在倉庫根目錄下,以下.gitlab-CI.yml 檔案定義了src目錄下 EqidManager , EqidReceiver 兩個專案的構建過程, 寫.gitlab-ci.yml 的過程就是 將平日裡使用docker打包映象併發布的行為 指令碼化。

├── container
   ── app/Dockerfile
── receiver/Dockerfile
├── docker-compose.dcproj 
├── docker-compose.override.yml
├── docker-compose.yml
├── .dockerignore
├── .env
├── Eqid-Manager.sln
├── .git
├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── NuGet.Config
├── src
── EqidManager
── EqidReceiver
└── test
── EqidProxyServer.Tests


   

  ③ .gitlab-ci.yml 檔案

       對比開發目錄,我們定義了  build-->build_image-->deploy 三個任務, 某些任務還包括不同分支Job, 更多Gitlab-CI的資料

 1 stages:
 2   - build
 3   - build_image
 4   - deploy
 5 
 6 variables:         
 7 # CI_DEBUG_TRACE: "true"                                         # 增加除錯追蹤
 8   deploy_path: "/home/xxxx/eqidmanager"
 9 
10 before_script:
11   - "docker info"
12 
13 build:
14   stage: build
15   script: 
16     - "for d in $(ls src);do echo $d;prog=$(pwd)/src/$d/$d.csproj; dotnet build $prog; done"
17   tags:                                                 # 這裡必須是字串陣列
18     - another-tag
19 
20 build_image:EqidManager:
21   stage: build_image
22   script:
23     - dotnet publish src/EqidManager/EqidManager.csproj  -c release -o ../../container/app/publish/    
24     - docker build --pull  -t $CI_REGISTRY_USER/eqidmanager:$CI_COMMIT_REF_NAME  container/app
25     - docker login -u $CI_REGISTRY_USER  -p $CI_REGISTRY_PASSWORD      
26     - docker push $CI_REGISTRY_USER/eqidmanager:$CI_COMMIT_REF_NAME     
27   tags:    
28     - another-tag
29   only:                                 # 構建策略
30     - tags
31 
32 build_image:EqidReceiver:
33   stage: build_image
34   script:
35     - dotnet publish src/EqidReceiver/EqidReceiver.csproj  -c release -o ../../container/receiver/publish
36     - docker build -t $CI_REGISTRY_USER/eqidreceiver:$CI_COMMIT_REF_NAME container/receiver
37     - docker login -u $CI_REGISTRY_USER  -p $CI_REGISTRY_PASSWORD
38     - docker push $CI_REGISTRY_USER/eqidreceiver:$CI_COMMIT_REF_NAME
39   tags: 
40     - my-tag
41   only:
42     - tags
43 
44 deploy:staging:
45   stage: deploy
46   script:
47     - cd $deploy_path
48     - export TAG=$CI_COMMIT_REF_NAME                # 引入本次CI的tag名稱,覆蓋.env 檔案預設配置
49     - "docker-compose build"                        # 根據docker-compose命令的用法, 會自動merge docker-compose.yml和override檔案
50     - "docker-compose up -d" 
51   tags: 
52     - my-tag
53 
54 deploy:prod:
55   stage: deploy
56   script:
57     - # TODO 需要寫指令碼登陸到Prod機器上
58     - export TAG=$CI_COMMIT_REF_NAME        
59     - cd $deploy_path
60     - "docker-compose  build"
61     - "docker-compose  up -d" 
62   tags:
63     - my-tag
64   when: manual

 這裡有些知識點和 坑位需要指出:

第8行: 預先定義的環境變數,該變數定義gitlab CD的部署目錄

第16行: 對src開發目錄下兩個程式執行dotnet build命令

第17行: tags定義具備該tags的Runner可以執行該任務, 注意這裡的tags必須是字串陣列

第23-26行:常規構建映象並推送到映象倉庫的過程,用到3個CI變數

   - 金鑰環境變數CI_REGISTRY_USER、CI_REGISTRY_PASSWORD ,可在GitLab-CI 介面配置

     - 預定義環境變數CI_COMMIT_REF_NAME, 該變數標記構建專案的分支或tag名稱,與下方的only 形成呼應

     注意變數可被重寫,重寫有優先順序 http://www.ttlsa.com/auto/gitlab-cicd-variables-zh-document/

第29行; only定義此Job只在git:tags時執行,也就是說切出tag,才會構建映象

第47行: Gialab-ci pipeline每個stage都會重新拉取git原始碼執行pipeline任務,我們不能在gitlab Runner的工作目錄下部署專案,這也是上面我們定義 deploy_path CI變數的原因

第48行:注入本次Gitlab CI 標籤名, 實際上是覆蓋了.env同名環境變數

第49行:若存在docker-compose.yml、docker-compose.override.yml 兩個檔案,docker-compose命令會自動merge這2個檔案, 使用docker-compose config命令檢視merge 之後的結果。

 

  ④ Continous Deploy

 在staging機器的deploy_path目錄下建立了如下部署檔案:

├── appsettings.secrets.json
├── docker-compose.override.yml
├── docker-compose.yml
├── .env
├── EqidManager.db
├── nginx
│   ├── Dockerfile
│   └── nginx.conf
└── receiver.secrets.json
  • appsetting.secrets.json 和 receiver.secrets.json 會在dccker-compose.yml 中被掛載, 這也是一種原則: 金鑰檔案不要進入git的程式碼管理

  • docker-compose.override.yml 定義基礎的容器服務內容,docker-compose.yml 定義相對易變的容器服務內容,docker-compose 命令在執行時會自動merge

  • dockee-compose命令會使用同級目錄下的.env 檔案, 這個檔案儲存相對固定的環境變數:

----- .env 檔案----
TAG=master           # 該TAG變數會在CI:deploy_staging指令碼中被覆蓋 docker_host=172.16.1.1 COMPOSE_PROJECT_NAME=EqidManager DOCKER_REGISTRY=***

 這樣staging部署環境也準備完畢,依據.gitlab-ci.yml 檔案定義的 deploy_staging指令碼:

 跳轉到部署目錄---> 應用本次gitlab-ci 的git:tag----> 執行docker-compose 命令拉取指定tag映象並部署。

作者:JulianHuang

碼甲拙見,如有問題請下方留言大膽斧正;碼字+Visio製圖,均為原創,看官請不吝好評+關注,  ~。。~

本文歡迎轉載,請轉載頁面明顯位置註明原作者及原文連結。

  &nbs