.Net Core 3.1 MVC CD/CD 到 K8S 實作

前言

本篇實作部署 .Net Core 3.1 MVC 專案 到 Kubernetes cluster

CI/CD 流程為
.Net Core 3.1 MVC 專案 可參考w4560000/OctopusProject_Core_Sample
=> Github
=> Azure Devops Pipeline (Build & Push DockerImage to Google Artifact Registry)
=> Octopus Deploy(從 Google Artifact Registry 取 DockerImage 部署至 Kubernetes cluster)

開發工具: VS 2019

建立 .Net Core 3.1 專案

dotnet new sln -o OctopusProject_Core_Sample
dotnet new mvc -f netcoreapp3.1 -o OctopusProject_Core_Sample/OctopusProject_Core_Sample
dotnet sln OctopusProject_Core_Sample/OctopusProject_Core_Sample.sln add OctopusProject_Core_Sample/OctopusProject_Core_Sample/OctopusProject_Core_Sample.csproj

建立 Git 版控

推至 Github

或者直接 Clone 專案也可以 Github w4560000 - OctopusProject_Core_Sample

建立 Octopus Server API Key (若已建立過 可略過)

可參考 此篇 w4560000 - ASP.NET MVC CI/CD 實作 建立 Octopus Server API Key 步驟

設定 Google Artifact Registry

啟用服務

gcloud services enable artifactregistry.googleapis.com

建立 repository

gcloud artifacts repositories create web-repo --repository-format=docker --location=asia-east1 --description="Docker repository

查看一下 repository 確認是否建立成功

gcloud artifacts repositories list

# 輸出
REPOSITORY  FORMAT  DESCRIPTION        LOCATION    LABELS  ENCRYPTION          CREATE_TIME          UPDATE_TIME          SIZE (MB)
web-repo    DOCKER  Docker repository  asia-east1          Google-managed key  2022-05-28T23:26:59  2022-05-28T23:26:59  0

建立 GCP ServiceAccount

建立給 Azure Devops 寫入 Google Artifact Registry 權限的服務帳戶

# 建立 service-accounts
gcloud iam service-accounts create [Name]

# 綁定 Artifact Registry 寫入者權限
gcloud projects add-iam-policy-binding [PROJECT_ID] --member="serviceAccount:[Name]@[PROJECT_ID].iam.gserviceaccount.com" --role="roles/artifactregistry.writer"

# 下載 .json檔 憑證至本地端 
gcloud iam service-accounts keys create [KEY_PATH] --iam-account=[NAME]@[PROJECT_ID].iam.gserviceaccount.com

ex:
gcloud iam service-accounts create azure-pipelines-publisher
gcloud projects add-iam-policy-binding [PROJECT_ID] --member="serviceAccount:azure-pipelines-publisher@[PROJECT_ID].iam.gserviceaccount.com" --role="roles/artifactregistry.writer"
gcloud iam service-accounts keys create D:\Lab\azure-pipelines-publisher-file.json --iam-account=azure-pipelines-publisher@[PROJECT_ID].iam.gserviceaccount.com  

建立給 Octopus Server 讀取 Google Artifact Registry 權限的服務帳戶

# 建立 service-accounts
gcloud iam service-accounts create [Name]

# 綁定 Artifact Registry 讀取者權限
gcloud projects add-iam-policy-binding [PROJECT_ID] --member="serviceAccount:[Name]@[PROJECT_ID].iam.gserviceaccount.com" --role="roles/artifactregistry.reader"

# 下載 .json檔 憑證至本地端 
gcloud iam service-accounts keys create [KEY_PATH] --iam-account=[NAME]@[PROJECT_ID].iam.gserviceaccount.com

ex:
gcloud iam service-accounts create octopus-server
gcloud projects add-iam-policy-binding [PROJECT_ID] --member="serviceAccount:octopus-server@[PROJECT_ID].iam.gserviceaccount.com" --role="roles/artifactregistry.reader,roles/storage.objectViewer"
gcloud iam service-accounts keys create D:\Lab\octopus-server-file.json --iam-account=octopus-server@[PROJECT_ID].iam.gserviceaccount.com  

建立 Octopus Server External Feeds

Feed Type = Docker Container Registry
URL = https://[location]-docker.pkg.dev
Credentials 上傳剛剛建立好的 GCP 服務帳戶 octopus-server 憑證

測試一下 連線是否正常即可

Azure Devops 新增 Google Artifact Registry Service connections

選擇 Docker Registry

Docker Registry = https://[location]-docker.pkg.dev/[GCP ProjectID]
Docker ID = _json_key
Docker Password = 剛剛下載的 azure-pipelines-publisher .json檔內容

設定 Azure Devops Pipeline

先建立 Pipeline Variable - GCP_ProjectID

建立 Pipeline

選擇 Github

選擇儲存庫

選擇預設的 ASP.NET Core (.NET Framework) Pipeline

調整 azure-pipelines.yml

name: $(Date:yyyyMMdd)$(Rev:.r)

trigger:
- qc
- develop

variables:
- group: GCP

pool:
  vmImage: 'ubuntu-latest'

steps:
  - task: Bash@3
    displayName: Transform Image Name
    inputs:
      targetType: inline
      script: |
        projectName=$(echo $(Build.Repository.Name)| cut -d'/' -f 2)
        echo "##vso[task.setvariable variable=projectName]$projectName";
        echo $projectName
        imageName=$(echo "$projectName" | awk '{print tolower($0)}');
        echo "##vso[task.setvariable variable=imageName]$imageName";
        echo $imageName
  
  - task: Docker@2
    displayName: Build an image
    inputs:
      containerRegistry: 'gar'
      repository: '$(GCP_ProjectID)/web-repo/$(imageName)'
      command: 'build'
      Dockerfile: '**/Dockerfile'
      tags: '$(Build.BuildNumber)'
      arguments: '--build-arg ProjectName=$(projectName)'
      addPipelineData: false
      addBaseImageData: false
  
  - task: Docker@2
    displayName: Push an image
    inputs:
      containerRegistry: 'gar'
      repository: '$(GCP_ProjectID)/web-repo/$(imageName)'
      command: 'push'
      tags: '$(Build.BuildNumber)'
      addPipelineData: false
      addBaseImageData: false

  - task: Bash@3
    displayName: Generate ReleaseNotes
    inputs:
      targetType: inline
      script: |
        git log -1 > ReleaseNotes.txt
  
  - task: OctopusPack@4
    displayName: Prepare appsettings Octopus Package
    inputs:
      PackageId: $(imageName)
      PackageFormat: 'Zip'
      PackageVersion: $(Build.BuildNumber)
      Include: 'appsettings*.json'
  
  - task: OctopusPush@4
    displayName: Push Octopus Package
    inputs:
      OctoConnectedServiceName: 'octopus'
      Space: 'Spaces-1'
      Package: $(imageName).$(Build.BuildNumber).zip
      Replace: 'false'
  
  - task: OctopusCreateRelease@4
    displayName: Create Octopus Release
    inputs:
      OctoConnectedServiceName: 'octopus'
      Space: 'Spaces-1'
      ProjectGroup: 'Web-K8S'
      ProjectName: '$(projectName)'
      ReleaseNumber: '$(Build.BuildNumber)'
      Channel: $(Build.SourceBranchName)
      AdditionalArguments: '--releaseNoteFile=ReleaseNotes.txt'

設定 Octopus K8S 專案

參考 w4560000 - Octopus Deploy 設定 Deploy K8S 專案

設定完成後 測試結果

已部署至 develop 環境

到 k8s 機器上確認服務

kubectl get all -n web

# 輸出
NAME                                              READY   STATUS    RESTARTS   AGE
pod/octopusproject-core-sample-85c868cb7c-7zpps   1/1     Running   0          10m

NAME                                 TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
service/octopusproject-core-sample   ClusterIP   10.110.158.18   <none>        80/TCP    10m

NAME                                         READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/octopusproject-core-sample   1/1     1            1           21m

NAME                                                    DESIRED   CURRENT   READY   AGE
replicaset.apps/octopusproject-core-sample-85c868cb7c   1         1         1       10m

確認 ingress

kubectl get ing -n web

# 輸出
NAME          CLASS   HOSTS                                       ADDRESS      PORTS   AGE
web-ingress   nginx   octopuscoresampledevelop.leozheng0512.com   10.240.0.1   80      37m

先在機器上自行設定 host 測試

vim /etc/hosts

新增
10.240.0.1 octopuscoresampledevelop.leozheng0512.com

測試 API 功能

curl http://octopuscoresampledevelop.leozheng0512.com/Home/GetEnv

# 輸出
"develop"

轉載請註明來源,若有任何錯誤或表達不清楚的地方,歡迎在下方評論區留言,也可以來信至 leozheng0621@gmail.com
如果文章對您有幫助,歡迎斗內(donate),請我喝杯咖啡

斗內💰

×

歡迎斗內

github