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 にデプロイします。

次の図は、ASP.NET MVC ウェブ アプリケーションを Google Kubernetes Engine(GKE)にデプロイする GitHub Actions ワークフローを示しています。

GitHub Actions ワークフローの概念図

このチュートリアルでは、目的を達成するために次のタスクを行う方法について説明します。

  • GitHub リポジトリの作成
  • 認証を構成する
  • GKE クラスタと Artifact Registry リポジトリをデプロイする
  • GitHub Actions ワークフローを作成する

費用

このドキュメントでは、Google Cloud の次の課金対象のコンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを生成できます。 新しい Google Cloud ユーザーは無料トライアルをご利用いただける場合があります。

このドキュメントに記載されているタスクの完了後、作成したリソースを削除すると、それ以上の請求は発生しません。詳細については、クリーンアップをご覧ください。

始める前に

  1. Sign in to your Google Cloud account. If you're new to Google Cloud, create an account to evaluate how our products perform in real-world scenarios. New customers also get $300 in free credits to run, test, and deploy workloads.
  2. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  3. Google Cloud プロジェクトで課金が有効になっていることを確認します

  4. Artifact Registry and Google Kubernetes Engine API を有効にします。

    API を有効にする

  5. Google Cloud Console の [プロジェクト セレクタ] ページで、Google Cloud プロジェクトを選択または作成します。

    プロジェクト セレクタに移動

  6. Google Cloud プロジェクトで課金が有効になっていることを確認します

  7. Artifact Registry and Google Kubernetes Engine API を有効にします。

    API を有効にする

GitHub リポジトリの作成

GitHub アカウントに dotnet-docs-samples リポジトリのフォークを作成します。GitHub Actions でビルドしているので、この手順が必要です。

  1. dotnet-docs-samples GitHub リポジトリに移動します。
  2. [Fork] をクリックします。
  3. [新しいフォークの作成] ページで、次のように設定します。

    • オーナー - GitHub アカウント
    • リポジトリ名 - dotnet-docs-samples
  4. [フォークの作成] をクリックします。

認証を構成する

GitHub Actions が Google Cloud プロジェクトのリソースを認証してアクセスできるように、Google Cloud プロジェクトを準備します。

Workload Identity 連携のプールとプロバイダを作成する

GitHub Actions が Google Cloud を認証して GKE にデプロイするのを許可するには、Workload Identity 連携を使用します。Workload Identity 連携を使用することで、GitHub Actions ワークロードのサービス アカウント キーを保存および管理する必要がなくなります。

Workload Identity 連携を使用するには、Workload Identity プールとプロバイダが必要です。専用のプロジェクトを使用して Workload Identity プールとプロバイダを管理することをおすすめします。このチュートリアルでは、わかりやすくするために、GKE クラスタと同じプロジェクトにプールとプロバイダを作成します。

  1. Google Cloud コンソールを開きます。

  2. Google Cloud コンソールで、「Cloud Shell をアクティブにする」をクリックします。

    Cloud Shell をアクティブにする

    Google Cloud コンソールの下部で Cloud Shell セッションが開始し、コマンドライン プロンプトが表示されます。Cloud Shell はシェル環境です。Google Cloud CLI がすでにインストールされており、現在のプロジェクトの値もすでに設定されています。セッションが初期化されるまで数秒かかることがあります。

  3. 新しい Workload Identity プールを作成します。

    gcloud iam workload-identity-pools create github-actions \
        --location="global" \
        --description="GitHub Actions tutorial" \
        --display-name="GitHub Actions"
    
  4. GitHub Actions を Workload Identity プールのプロバイダとして追加します。

    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"
    

サービス アカウントを作成する

  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 に push できるようにします。

    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 に push できるようにします。

    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 を使用して継続的インテグレーションを設定できるようになりました。commit によって Git リポジトリへの push を行うたびに、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 連携と前の手順で作成したサービス アカウントを使用して、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. [Commit new file] セクションで commit メッセージ(Add workflow など)を入力し、[Commit new file] をクリックします。

  6. メニューで [Actions] をクリックし、ワークフローの完了を待ちます。

    ワークフローの完了には数分かかることがあります。

  7. Google Cloud コンソールで、[Services と Ingress] ページを更新します。

    [Service と Ingress] に移動

  8. [Ingress] タブに移動します。

  9. clouddemo クラスタの Ingress サービスを確認して、そのステータスが [OK] に切り替わるのを待ちます。これには数分かかることがあります。

  10. 同じ行の [フロントエンド] 列にあるリンクを開きます。ロードバランサが利用可能になるまで数分かかるため、最初は CloudDemo アプリが読み込まれない場合があります。ロードバランサの準備が整うと、カスタム タイトルが付いた CloudDemo アプリが表示されます。ただし、今回は本番環境クラスタで実行されます。

クリーンアップ

チュートリアルが終了したら、作成したリソースをクリーンアップして、割り当ての使用を停止し、課金されないようにできます。以下のセクションで、リソースを削除または無効にする方法を説明します。

GitHub リポジトリの削除

GitHub リポジトリを削除するには、リポジトリの削除をご覧ください。リポジトリを削除すると、すべてのソースコードの変更が失われます。

プロジェクトの削除

課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

    Delete a Google Cloud project:

    gcloud projects delete PROJECT_ID

次のステップ