次の方法で共有


環境での Kubernetes リソース

Azure DevOps Services |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020

この記事では、デプロイでターゲットにできる Azure Pipelines 環境 での Kubernetes リソースの使用について説明します。 Azure Kubernetes Service (AKS) またはその他のクラウド プロバイダーで、パブリックまたはプライベートの Kubernetes クラスターに接続できます。

環境リソース ビューでは、Kubernetes リソースの状態が表示され、パイプラインに対する追跡可能性が提供され、トリガーされるコミットに戻ります。 また、動的な Kubernetes 環境リソースを作成して、マージ前にプル要求を確認することもできます。 環境リソースの詳細については、「 YAML パイプラインのリソース 」と「 リソースのセキュリティ」を参照してください。

Note

プライベート AKS クラスターでは、パブリック IP アドレスを介して API サーバー エンドポイントが公開されないため、クラスターの仮想ネットワークに接続する必要があります。 クラスターの仮想ネットワークにアクセスしたり、 マネージド DevOps プールを使用したりできる仮想ネットワーク内にセルフホステッド エージェントを設定できます。 詳細については、「 プライベート クラスターに接続するためのオプション」を参照してください。

Kubernetes 環境リソースの利点

環境の Kubernetes 環境リソースとリソース ビューには、次の利点があります。

  • パイプラインの追跡可能性Kubernetes マニフェスト配置タスクは、パイプラインの追跡可能性をサポートする注釈を追加します。 名前空間内のオブジェクトの更新を担当する Azure DevOps の組織、プロジェクト、パイプラインを確認できます。

    Kubernetes クラスターのパイプラインの追跡可能性を示すスクリーンショット。

  • リソース正常性診断。 ワークロードの状態ビューは、新しいデプロイによって発生した間違いや回帰をすばやくデバッグする方法です。 たとえば、ポッドの状態情報は、未構成の imagePullSecrets など、 ImagePullBackOff エラーの原因を特定するのに役立ちます。

    Kubernetes デプロイのワークロードの状態ビューを示すスクリーンショット。

  • アプリを確認します。 レビュー アプリは、Git リポジトリから環境内の動的な Kubernetes リソースにすべてのプル要求をデプロイし、レビュー アプリにリンクする GitHub コメントを投稿します。 レビュー担当者は、変更がターゲット ブランチにマージされて運用環境にデプロイされる前に、PR の変更がどのように表示され、他の依存サービスと連携するかを確認できます。

    GitHub の [アプリのレビュー] コメントを示すスクリーンショット。

AKS リソース

AKS は、選択したクラスターと名前空間に ServiceAccount を作成し、環境内の Kubernetes リソースを指定された名前空間にマップします。 環境の外部で Kubernetes サービス接続を設定する方法については、 Kubernetes サービス接続に関する説明を参照してください。

Kubernetes ロールベースのアクセス制御 (RBAC) が有効なクラスターの場合、RoleBinding も作成され、サービス アカウントのスコープを選択した名前空間に制限します。 Kubernetes RBAC が無効なクラスターの場合、作成されたサービス アカウントには、名前空間全体にわたるクラスター全体の特権があります。

AKS リソースを Azure Pipelines 環境に追加するには:

  1. 環境の [ Pipelines>Environments] の下にある [ リソースの追加 ] を選択し、[ Kubernetes] を選択します。

  2. 次の画面で、プロバイダーAzure Kubernetes Service を選択し、Azure サブスクリプション、AKS クラスター、および新規または既存の名前空間を選択します。 新しい名前空間の場合は、名前空間名を入力します。

  3. [検証して作成]を選択します。 環境の [ リソース ] タブに新しいリソースが表示され、" デプロイしない" というテキストが表示されます。

    追加された Kubernetes リソースを示すスクリーンショット。

AKS 以外の Kubernetes リソース

非 AKS クラスターから名前空間に Kubernetes リソースをマップするには、AKS 以外のプロバイダーの既存のサービス アカウントが必要です。

AKS 以外の Kubernetes リソースを Azure Pipelines 環境に追加するには:

  1. 環境の [ Pipelines>Environments] の下にある [ リソースの追加 ] を選択し、[ Kubernetes] を選択します。

  2. 次の画面で、プロバイダーとして一般的なプロバイダー (既存のサービスアカウント)を選択します。

  3. [クラスター資格情報] に、クラスター名名前空間サーバー URL、シークレットを入力します。

    • サーバー URL を取得するには、ローカル シェルで kubectl config view --minify -o jsonpath={.clusters[0].cluster.server} を実行します。

    • シークレットを取得するには:

      1. kubectl get serviceAccounts <service-account-name> -n <namespace> -o=jsonpath={.secrets[*].name}を実行してサービス アカウント シークレット名を取得します。
      2. 上記のコマンドの出力を使用して、 kubectl get secret <service-account-secret-name> -n <namespace> -o json を実行します。

      Note

      get ServiceAccounts コマンドから結果が得つからない場合は、「ServiceAccount の有効期間が長い API トークンを手動で作成する」を参照してください。

  4. [検証して作成]を選択します。

パイプライン内の Kubernetes リソース

AKS にデプロイする YAML パイプラインを作成する最も簡単な方法は、 Azure Kubernetes Services へのデプロイ テンプレートから開始することです。 YAML コードを記述したり、明示的なロール バインドを手動で作成したりする必要はありません。 生成されたパイプラインは、構成設定に基づいて変数とその他の値を設定し、使用します。

レビュー アプリを使用する

DeployPullRequest ジョブは、Git リポジトリから環境内の動的な Kubernetes リソースにすべてのプル要求をデプロイします。 このジョブをパイプラインに追加するには、[Azure Kubernetes Services へのデプロイ] 構成フォームの [プル要求のアプリ フローの確認を有効にする] チェック ボックスをオンにします。

Note

このジョブを既存のパイプラインに追加するには、通常の Kubernetes 環境リソースをバックアップするサービス接続が [ クラスター管理者資格情報を使用する] に設定されていることを確認します。 それ以外の場合は、基になるサービス アカウントのレビュー アプリ名前空間へのロール バインドを作成する必要があります。

レビュー アプリのリソースは、環境のリソース一覧に [レビュー] というラベルが付けられます。

パイプライン環境の一覧におけるレビュー環境を示すスクリーンショット。

パイプラインの例

次のパイプラインの例は、 Azure Kubernetes Services へのデプロイ テンプレートに 基づいています。 パイプラインは、最初にイメージをビルドして Azure Container Registry にプッシュします。

最初のデプロイ ジョブは、 main ブランチへのコミットに対して実行され、環境内の通常の Kubernetes リソースに対してデプロイされます。

2番目のジョブは、PRが作成または更新されmainブランチに送られると実行され、クラスター内で必要に応じて作成される動的レビューアプリリソースに対してデプロイされます。

# Deploy to Azure Kubernetes Service
# Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service
# https://docs.microsoft.com/azure/devops/pipelines/languages/docker

trigger:
- main

resources:
- repo: self

variables:

  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: '12345' # Docker service connection identifier
  imageRepository: 'name-of-image-repository' # name of image repository
  containerRegistry: 'mycontainer.azurecr.io' # path to container registry
  dockerfilePath: '**/Dockerfile'
  tag: '$(Build.BuildId)'
  imagePullSecret: 'my-app-secret' # image pull secret

  # Agent VM image name
  vmImageName: 'ubuntu-latest'

  # Name of the new namespace being created to deploy the PR changes.
  k8sNamespaceForPR: 'review-app-$(System.PullRequest.PullRequestId)'

stages:
- stage: Build
  displayName: Build stage
  jobs:
  - job: Build
    displayName: Build
    pool:
      vmImage: $(vmImageName)
    steps:
    - task: Docker@2
      displayName: Build and push an image to container registry
      inputs:
        command: buildAndPush
        repository: $(imageRepository)
        dockerfile: $(dockerfilePath)
        containerRegistry: $(dockerRegistryServiceConnection)
        tags: |
          $(tag)

    - upload: manifests
      artifact: manifests

- stage: Production
  displayName: Deploy stage
  dependsOn: Build

  jobs:
  - deployment: Production
    condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/pull/')))
    displayName: Production
    pool:
      vmImage: $(vmImageName)
    environment: 'myenvironmentname.myresourcename'
    strategy:
      runOnce:
        deploy:
          steps:
          - task: KubernetesManifest@1
            displayName: Create imagePullSecret
            inputs:
              action: createSecret
              secretName: $(imagePullSecret)
              dockerRegistryEndpoint: $(dockerRegistryServiceConnection)

          - task: KubernetesManifest@1
            displayName: Deploy to Kubernetes cluster
            inputs:
              action: deploy
              manifests: |
                $(Pipeline.Workspace)/manifests/deployment.yml
                $(Pipeline.Workspace)/manifests/service.yml
              imagePullSecrets: |
                $(imagePullSecret)
              containers: |
                $(containerRegistry)/$(imageRepository):$(tag)

  - deployment: DeployPullRequest
    displayName: Deploy Pull request
    condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/pull/'))
    pool:
      vmImage: $(vmImageName)

    environment: 'myenvironmentname.$(k8sNamespaceForPR)'
    strategy:
      runOnce:
        deploy:
          steps:
          - reviewApp: default

          - task: Kubernetes@1
            displayName: 'Create a new namespace for the pull request'
            inputs:
              command: apply
              useConfigurationFile: true
              inline: '{ "kind": "Namespace", "apiVersion": "v1", "metadata": { "name": "$(k8sNamespaceForPR)" }}'

          - task: KubernetesManifest@1
            displayName: Create imagePullSecret
            inputs:
              action: createSecret
              secretName: $(imagePullSecret)
              namespace: $(k8sNamespaceForPR)
              dockerRegistryEndpoint: $(dockerRegistryServiceConnection)

          - task: KubernetesManifest@1
            displayName: Deploy to the new namespace in the Kubernetes cluster
            inputs:
              action: deploy
              namespace: $(k8sNamespaceForPR)
              manifests: |
                $(Pipeline.Workspace)/manifests/deployment.yml
                $(Pipeline.Workspace)/manifests/service.yml
              imagePullSecrets: |
                $(imagePullSecret)
              containers: |
                $(containerRegistry)/$(imageRepository):$(tag)

          - task: Kubernetes@1
            name: get
            displayName: 'Get services in the new namespace'
            continueOnError: true
            inputs:
              command: get
              namespace: $(k8sNamespaceForPR)
              arguments: svc
              outputFormat: jsonpath='http://{.items[0].status.loadBalancer.ingress[0].ip}:{.items[0].spec.ports[0].port}'

          # Get the IP of the deployed service and writing it to a variable for posting comment
          - script: |
              url="$(get.KubectlOutput)"
              message="Your review app has been deployed"
              if [ ! -z "$url" -a "$url" != "http://:" ]
              then
                message="${message} and is available at $url."
              fi
              echo "##vso[task.setvariable variable=GITHUB_COMMENT]$message"