使用 GitHub Actions 工作流程,將 .NET 應用程式部署至 Google Kubernetes Engine

本教學課程說明如何使用 GitHub Actions 工作流程,將使用 .NET 的 ASP.NET Model-View-Controller (MVC) 網頁應用程式部署到 Google Kubernetes Engine (GKE)。

本教學課程適用於具備 Microsoft .NET、GitHub Actions 和 GKE 基本知識的開發人員和 DevOps 工程師。您也需要 GitHub 帳戶才能執行本教學課程。

目標

將使用 .NET 6.0 且在 Linux 上執行的 ASP.NET Core 網頁應用程式,部署至 Google Kubernetes Engine

下圖顯示 GitHub Actions 工作流程,用於將 ASP.NET MVC 網頁應用程式部署至 Google Kubernetes Engine (GKE)。

GitHub Actions 工作流程的概念圖

本教學課程說明如何完成下列工作,達成目標:

  • 建立 GitHub 存放區
  • 設定驗證機制
  • 部署 GKE 叢集和 Artifact Registry 存放區
  • 建立 GitHub Actions 工作流程

費用

在本文件中,您會使用下列 Google Cloud的計費元件:

如要根據預測用量估算費用,請使用 Pricing Calculator

初次使用 Google Cloud 的使用者可能符合免費試用期資格。

完成本文所述工作後,您可以刪除建立的資源,避免繼續計費,詳情請參閱「清除所用資源」一節。

事前準備

  1. 登入 Google Cloud 帳戶。如果您是 Google Cloud新手,歡迎 建立帳戶,親自評估產品在實際工作環境中的成效。新客戶還能獲得價值 $300 美元的免費抵免額,可用於執行、測試及部署工作負載。
  2. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  3. Verify that billing is enabled for your Google Cloud project.

  4. Enable the Artifact Registry and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

  5. In the Google Cloud console, on the project selector page, select or create a Google Cloud project.

    Roles required to select or create a project

    • Select a project: Selecting a project doesn't require a specific IAM role—you can select any project that you've been granted a role on.
    • Create a project: To create a project, you need the Project Creator role (roles/resourcemanager.projectCreator), which contains the resourcemanager.projects.create permission. Learn how to grant roles.

    Go to project selector

  6. Verify that billing is enabled for your Google Cloud project.

  7. Enable the Artifact Registry and Google Kubernetes Engine APIs.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the APIs

建立 GitHub 存放區

在 GitHub 帳戶中建立 dotnet-docs-samples 存放區的分支。由於我們是使用 GitHub Actions 建構,因此這個步驟是必要的。

  1. 前往 dotnet-docs-samples GitHub 存放區。
  2. 按一下「Fork」(分叉)
  3. 在「Create a new fork」(建立新分支) 頁面中,設定下列項目:

    • 擁有者 - 你的 GitHub 帳戶
    • 存放區名稱 - dotnet-docs-samples
  4. 按一下「建立分叉」

設定驗證機制

準備 Google Cloud 專案,讓 GitHub Actions 能夠驗證並存取 Google Cloud 專案中的資源。

建立 workload identity federation pool 和提供者

如要允許 GitHub Actions 驗證 Google Cloud 並部署至 GKE,請使用工作負載身分聯盟。使用 workload identity federation,您就不必為 GitHub Actions 工作負載儲存及管理服務帳戶金鑰

使用 Workload Identity 聯盟時,需要工作負載身分集區和提供者。 建議您使用專案管理 workload identity pool 和提供者。 在本教學課程中,為簡化操作,請在與 GKE 叢集相同的專案中建立集區和提供者:

  1. 開啟 Google Cloud 控制台。

  2. 在 Google Cloud 控制台中啟用 Cloud Shell。

    啟用 Cloud Shell

    Google Cloud 主控台底部會開啟一個 Cloud Shell 工作階段,並顯示指令列提示。Cloud Shell 是已安裝 Google Cloud CLI 的殼層環境,並已針對您目前的專案設定好相關值。工作階段可能要幾秒鐘的時間才能初始化。

  3. 建立新的 workload identity pool:

    gcloud iam workload-identity-pools create github-actions \
        --location="global" \
        --description="GitHub Actions tutorial" \
        --display-name="GitHub Actions"
    
  4. 將 GitHub Actions 新增為 workload identity pool 提供者:

    gcloud iam workload-identity-pools providers create-oidc github-actions-oidc \
        --location="global" \
        --workload-identity-pool=github-actions \
        --issuer-uri="https://token.actions.githubusercontent.com/" \
        --attribute-mapping="google.subject=assertion.sub" \
        --attribute-condition="assertion.repository_owner=='ORGANIZATION'"
    

    ORGANIZATION 替換為 GitHub 機構名稱。

建立服務帳戶

  1. 在 Cloud Shell 中建立服務帳戶,供 GitHub Actions 用於發布 Docker 映像檔及部署至 GKE:

    SERVICE_ACCOUNT=$(gcloud iam service-accounts create github-actions-workflow \
      --display-name "GitHub Actions workflow" \
      --format "value(email)")
    
  2. Artifact Registry 寫入者角色 (roles/artifactregistry.writer) 授予服務帳戶,允許 GitHub 動作推送到 Artifact Registry:

    gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
      --member serviceAccount:$SERVICE_ACCOUNT \
      --role roles/artifactregistry.writer
    
  3. Google Kubernetes Engine 開發人員角色 (roles/container.developer) 授予服務帳戶,允許 GitHub 動作推送至 Artifact Registry:

    gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
      --member serviceAccount:$SERVICE_ACCOUNT \
      --role roles/container.developer
    

允許 GitHub Actions 工作流程使用服務帳戶

允許 GitHub Actions 工作流程模擬及使用服務帳戶:

  1. 初始化環境變數,其中包含 GitHub Actions 工作流程使用的主體。主體類似於使用者名稱,可唯一識別 GitHub 存放區和分支:

    SUBJECT=repo:OWNER/dotnet-docs-samples:ref:refs/heads/main
    

    OWNER 替換成 GitHub 使用者名稱。

  2. 授予主體權限,模擬服務帳戶:

    PROJECT_NUMBER=$(gcloud projects describe $(gcloud config get-value core/project) --format='value(projectNumber)')
    
    gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT \
      --role=roles/iam.workloadIdentityUser \
      --member="principal://iam.googleapis.com/projects/$PROJECT_NUMBER/locations/global/workloadIdentityPools/github-actions/subject/$SUBJECT"
    

部署 GKE 叢集和 Artifact Registry 存放區

  1. 建立 Docker 映像檔的存放區:

    gcloud artifacts repositories create clouddemo \
      --repository-format=docker \
      --location=us-central1
    
  2. 允許 Compute Engine 預設服務帳戶存取存放區:

    gcloud projects add-iam-policy-binding $(gcloud config get-value core/project) \
      --member=serviceAccount:$PROJECT_NUMBER-compute@developer.gserviceaccount.com \
      --role=roles/artifactregistry.reader
    
  3. 建立叢集:

    gcloud container clusters create clouddemo-linux \
      --enable-ip-alias \
      --zone us-central1-a
    

    這個指令可能需要幾分鐘才能完成。

  4. 取得叢集的專案名稱和專案編號:

    echo "Project ID: $(gcloud config get-value core/project)"
    echo "Project Number: $(gcloud projects describe $(gcloud config get-value core/project) --format=value\(projectNumber\))"
    

    稍後會用到這些值。

建立 GitHub Actions 工作流程

您現在可以使用 GitHub Actions 設定持續整合。每當有修訂版本推送至 Git 存放區,GitHub Actions 工作流程就會建構程式碼,並將建構成果封裝至 Docker 容器中,接著將容器發布至 Artifact Registry。

存放區已包含下列 Dockerfile:

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

FROM mcr.microsoft.com/dotnet/aspnet:6.0
EXPOSE 8080

#------------------------------------------------------------------------------
# Copy publishing artifacts.
#------------------------------------------------------------------------------

WORKDIR /app
COPY CloudDemo.MvcCore/bin/Release/net6.0/publish/ /app/

ENV ASPNETCORE_URLS=http://0.0.0.0:8080

#------------------------------------------------------------------------------
# Run application in Kestrel.
#------------------------------------------------------------------------------

ENTRYPOINT ["dotnet", "CloudDemo.MvcCore.dll"]

存放區也包含 Kubernetes 資訊清單:

#
# Copyright 2020 Google LLC
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
# 
#   http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
#

apiVersion: v1
kind: Service
metadata:
  name: clouddemo-netcore
spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: clouddemo-netcore
  type: NodePort

---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: clouddemo-netcore
spec:
  defaultBackend:
    service:
      name: clouddemo-netcore
      port:
        number: 80

---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: clouddemo-netcore
spec:
  replicas: 2
  selector:
    matchLabels:
      app: clouddemo-netcore
  template:
    metadata:
      labels:
        app: clouddemo-netcore
    spec:
      containers:
      - name: clouddemo-netcore
        image: CLOUDDEMO_IMAGE
        ports:
          - containerPort: 8080
        livenessProbe:      # Used by deployment controller
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 5
          periodSeconds: 5
        readinessProbe:     # Used by Ingress/GCLB
          httpGet:
            path: /health
            port: 8080
          initialDelaySeconds: 3
          periodSeconds: 5
        resources:
          limits:
            memory: 1024Mi
          requests:
            memory: 256Mi

建立 GitHub Actions 工作流程,執行下列操作:

  • 使用 workload identity federation 和您先前建立的服務帳戶,向 Google Cloud 進行驗證。
  • 建構 Docker 映像檔並部署至 Artifact Registry。
  • 將 Docker 映像檔部署至 GKE。

如要建立 GitHub Actions 工作流程,請按照下列步驟操作:

  1. GitHub 中,前往存放區的分支。dotnet-docs-samples
  2. 依序點選「新增檔案」 >「建立新檔案」
  3. 在「Name your file」(為檔案命名) 文字欄位中,輸入下列名稱:

    .github/workflows/deploy-gke.yaml
    
  4. 將下列程式碼複製到檔案中:

    name: Build and Deploy to GKE
    
    on:
      push:
        branches:
          - main
    
    env:
      PROJECT_ID: PROJECT_ID
      PROJECT_NUMBER: PROJECT_NUMBER
    
      CLUSTER: clouddemo-linux
      CLUSTER_ZONE: us-central1-a
    
      REPOSITORY: clouddemo
      REPOSITORY_REGION: us-central1
    
      IMAGE: clouddemo
    
    jobs:
      build:
        runs-on: ubuntu-latest
        permissions:
          id-token: write
          contents: read
    
        steps:
        - name: Checkout
          uses: actions/checkout@v3
    
        #
        # Authenticate to Google Cloud using workload identity federation
        #
        - id: 'auth'
          name: 'Obtain access token by using workload identity federation'
          uses: 'google-github-actions/auth@v0'
          with:
            create_credentials_file: true
            token_format: access_token
            workload_identity_provider: projects/${{ env.PROJECT_NUMBER }}/locations/global/workloadIdentityPools/github-actions/providers/github-actions-oidc
            service_account: github-actions-workflow@${{ env.PROJECT_ID }}.iam.gserviceaccount.com
    
        - name: Connect to Artifact Registry
          run: |-
            echo ${{ steps.auth.outputs.access_token }} | docker login -u oauth2accesstoken --password-stdin https://${{ env.REPOSITORY_REGION }}-docker.pkg.dev
    
        - name: Connect to GKE
          uses: google-github-actions/get-gke-credentials@v0
          with:
            cluster_name: ${{ env.CLUSTER }}
            location: ${{ env.CLUSTER_ZONE }}
    
        #
        # Build the .NET code
        #
        - name: Build solution
          run: |-
            dotnet publish applications/clouddemo/netcore/CloudDemo.MvcCore.sln \
                --configuration Release \
                --framework net6.0
    
        #
        # Build the Docker image and push it to Artifact Registry
        #
        - name: Create image tag
          run: echo "IMAGE_TAG=${{ env.REPOSITORY_REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.REPOSITORY }}/${{ env.IMAGE }}:$GITHUB_SHA" >> $GITHUB_ENV
    
        - name: Lock image version in deployment.yaml
          run: sed -i 's|CLOUDDEMO_IMAGE|${{ env.IMAGE_TAG }}|g' applications/clouddemo/netcore/deployment.yaml
    
        - name: Build Docker image
          run: docker build --tag "${{ env.IMAGE_TAG }}" applications/clouddemo/netcore
    
        - name: Publish Docker image to Google Artifact Registry
          run: docker push "${{ env.IMAGE_TAG }}"
    
        #
        # Deploy to GKE
        #
        - name: Deploy to GKE
          run: kubectl apply -f applications/clouddemo/netcore/deployment.yaml
        

    替換下列值:

    • PROJECT_ID:包含 GKE 叢集的專案 ID。
    • PROJECT_NUMBER:含有 GKE 叢集的專案專案編號。
  5. 在「修訂新檔案」部分中,輸入修訂訊息 (例如 Add workflow),然後按一下「修訂新檔案」

  6. 在選單中按一下「動作」,然後等待工作流程完成。

    工作流程可能需要幾分鐘才能完成。

  7. 在 Google Cloud 控制台中,重新整理「Services & Ingress」(服務與輸入) 頁面。

    前往「Services & Ingress」(服務與 Ingress)

  8. 前往「Ingress」分頁。

  9. 找到 clouddemo 叢集的輸入服務,然後等待其狀態變成「Ok」。這可能需要幾分鐘的時間。

  10. 開啟同一列「前端」欄中的連結。負載平衡器需要幾分鐘才能使用,因此 CloudDemo 應用程式一開始可能無法載入。負載平衡器準備就緒後,您會看到 CloudDemo 應用程式及自訂名稱,這次應用程式是在實際工作環境叢集中執行。

清除所用資源

完成教學課程後,您可以清除所建立的資源,這樣資源就不會繼續使用配額,也不會產生費用。下列各節將說明如何刪除或關閉這些資源。

刪除 GitHub 存放區

如要刪除 GitHub 存放區,請參閱「刪除存放區」。刪除存放區會導致所有原始碼變更遺失。

刪除專案

如要避免付費,最簡單的方法就是刪除您為了本教學課程而建立的專案。

    刪除 Google Cloud 專案:

    gcloud projects delete PROJECT_ID

後續步驟