Gitlab Registries

2023-06-02 12:00:32

在專案開發和部署過程中,我們常常需要一套私有倉庫,比如 Code RepositoryPackage RepositoryDocker Registry 等。

  • Code Repository:在 github 或 gitlab 或 gitee 等平臺上建立私有專案;或搭建原生程式碼伺服器,一般常用 gitlab 開源版本搭建。
  • Package Registry:以 nuget 為例,官方 nuget.org 是不提供私有空間的,因此我們常用 baget(只支援 nuget)、nexus(支援多種型別)搭建私有 Package Registry。
  • Docker Registry:私有 Docker 映象倉庫,常用於本地構建、遠端部署場景,可使用 registry 搭建。

其實,如果你使用 Gitlab 受控程式碼,那麼要知道它同時也提供了 Package 和 Docker 倉儲服務。就個人而言,Gitlab 涵蓋了博主大部分專案的 CI/CD 主環節,不需要額外對接第三方服務。

Package Registry

下面以 nuget source 為例,在 gitlab.com 上搭建 Package Registry:

  1. 新建一個空專案或使用現有專案(專案中包含什麼無關緊要),得到它的 Project ID,我們的 nuget source 就是 https://gitlab.com/api/v4/projects/{Project_ID}/packages/nuget/index.json。

  2. 建立該專案或該專案所屬 groupDeploy Token,得到相應的使用者名稱和密碼,用於登入並管理 nuget source。

  3. 在 gitlab.com 中開啟原始碼專案(該專案將打包 .nupkg 檔案並行布到 nuget source,不一定要是前兩步中的專案)的 CI/CD 選項,新增兩個變數—— CI_PKG_DEPLOY_USERCI_PKG_DEPLOY_PASSWORD ——分別對應第 2 步的使用者名稱和密碼。當然變數名可以隨意取。

  4. 建立 gitlab-runner (假設以 docker 方式,下同)並編寫 .gitlab-ci.yml 到原始碼專案中。注意其中用到第 3 步新增的變數。

image: mcr.microsoft.com/dotnet/sdk:6.0 # 預設每次 runner 執行時都會重新拉取映象,可在 config.toml 中設定 pull_policy = "if-not-present",本地沒有時再拉取

stages:
  - deploy

deploy domain:
  stage: deploy
  script:
    - dotnet build -c Release xxx/xxx.csproj  # 微軟官網說 dotnet pack(不帶 --no-build) 會先自動 build,實則不然,所以加了這句
    - dotnet pack --no-build -c Release Domain/Domain.csproj
    - dotnet nuget add source "${CI_API_V4_URL}/projects/123456/packages/nuget/index.json" --name gitlab --username $CI_PKG_DEPLOY_USER --password $CI_PKG_DEPLOY_PASSWORD --store-password-in-clear-text # .net 平臺暫不支援該場景下的密碼加密,所以設定為明文傳輸
    - dotnet nuget push "xxx/bin/Release/*.nupkg" --source gitlab
  rules:  # 至少從 Gitlab 16.0 起,`only` and `except` are not being actively developed. `rules` is the preferred keyword to control when to add jobs to pipelines.
    - if: $CI_COMMIT_BRANCH == "master"
      changes: 
        - "xxx/**/*"    
  environment: production  # 這個設定主要用於歸類,關係不大
  tags: # job 一定要指定 tags,不是說留空就會執行預設全部 runners。
    - demo

注意其中指令碼因未涉及到 docker 指令,所以此處不需要 Docker-in-Docker(參看gitlab-runner 中的 Docker-in-Docker)。

  1. 提交原始碼專案,觸發執行 pipeline

  2. 新增 nuget source

dotnet nuget add/update source gitlab -s https://gitlab.com/api/v4/projects/123456/packages/nuget/index.json -u deploy_name -p deploy_token

其中引數 -u deploy_name -p deploy_token 同樣是之前建立的 Deploy Token

現在,就能在新的 nuget source 上找到剛釋出的 xxx.version.nupkg。

ps:You can store different package types in one GitLab project。

nuget.config

有時需要在指令碼中指定 nuget source,比如 dotnet restore "demo/demo.csproj" --configfile "nuget.config"。如果涉及到使用者名稱密碼認證,那麼需要 nuget.config 提供相關資訊,如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
	<packageSources>
		<add key="nuget" value="https://api.nuget.org/v3/index.json" />
		<add key="gitlab" value="https://gitlab.com/api/v4/projects/123456/packages/nuget/index.json" />
	</packageSources>
	<packageSourceCredentials>
		<gitlab>
			<add key="Username" value="xxxxxx" />
                        <!-- password,加密密碼僅在 Windows 上受支援,並且僅當在同一臺計算機上使用並且通過與原始加密相同的使用者進行解密;所以我們一般只能使用 ClearTextPassword,建議採用環境變數的方式提高安全性 -->
			<add key="ClearTextPassword" value="xxxxxx or %env_name%" />
		</gitlab>
	</packageSourceCredentials>
</configuration>

Docker Registry

一般來說,生成的映象儲存在對應的專案中即可,不必像 Package Registry 一樣考慮存放位置。下面以博主實際專案中的 .gitlab-ci.yml 為例介紹 Docker Registry 的使用。

variables:
 # 定義映象名稱和 tag,這裡使用 $CI_REGISTRY_IMAGE 和 $CI_COMMIT_REF_NAME 兩個預定義變數表示,形如 registry.gitlab.com/group/project:master
 IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_NAME

# 定義兩個 job
stages:
 # 生成映象然後釋出到 Docker Registry
 - build then push docker image
 # 從 Docker Registry 拉取映象並建立容器
 - pull docker image to deploy

build:
 stage: build then push docker image
 # Docker in Docker。官方建議顯式指定相同版本號,以免版本不一致導致的相容性問題。
 image: docker:20.10.16
 services:
  - docker:20.10.16-dind
 script: 
  # 1. 登入到 Docker Registry。如果專案程式碼是由 gitlab 託管,那麼照搬該句即可,句中的變數會自動賦值,必定登入成功
  - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
  # 2. 生成映象
  - docker build -f Project/Dockerfile -t $IMAGE_TAG .
  # 3. 推播映象。自動推播至映象名中的 Docker Registry 地址。
  - docker push $IMAGE_TAG
 after_script:
  # 4. 刪除本地映象
  - docker rmi $IMAGE_TAG
 tags:
  - demo

deploy:
 stage: pull docker image to deploy
 image: ubuntu:latest
 before_script: # ssh 金鑰設定,事先在待部署的伺服器上安裝公鑰,臨時容器(這裡是 ubuntu)中設定私鑰(具體設定指令碼此處略過不表)
 script:
  # 登入伺服器並執行相關指令,注意先刪除舊容器和映象
  - ssh root@SERVER_IP "docker stop demo; docker rm demo; docker rmi $IMAGE_TAG; docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY; docker pull $IMAGE_TAG; docker run -d --name demo -p 443:443 -p 80:80 -e ASPNETCORE_ENVIRONMENT=Production -e ASPNETCORE_URLS="https://+;http://+" $IMAGE_TAG; docker logout"
 tags:
  - demo