環境 - Kubernetes リソース

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

Kubernetes リソース ビューでは、リソースにマップされている名前空間内のオブジェクトの状態が表示されます。 このリソース ビューでは、パイプラインの追跡可能性もオーバーレイされるため、Kubernetes オブジェクトからパイプラインまで、そしてコミットまで戻ることができます。

Kubernetes リソースを使用して、デプロイの環境内の Kubernetes クラスターをターゲットにします。 パイプラインを使用して、他のクラウド プロバイダーから Azure Kubernetes Service (AKS) およびクラスターにデプロイします。

Kubernetes リソースはパブリック クラスターまたはプライベート クラスターで使用できます。 リソースのしくみの詳細については、YAML のリソースリソースを使用したセキュリティに関するページを参照してください。

概要

環境内で Kubernetes リソース ビューを使用する利点を次に示します。

  • パイプラインの追跡可能性 - デプロイに使用される Kubernetes マニフェスト タスクにより、リソース ビューでのパイプラインの追跡可能性を示す注釈が追加されます。 パイプラインの追跡可能性は、名前空間内のオブジェクトに対して行われた更新を担当する、元の Azure DevOps 組織、プロジェクト、パイプラインを特定するのに役立ちます。

    Pipeline traceability

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

    ImagePullBackOff

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

Azure Kubernetes Service を使用する

Azure Kubernetes Service (AKS) を使用すると、選択したクラスターと名前空間に ServiceAccount が作成されます。 Kubernetes RBAC 対応クラスターの場合、作成されたサービス アカウントのスコープを選択した名前空間に制限するために、RoleBinding も作成されます。 Kubernetes RBAC が無効なクラスターの場合、作成された ServiceAccount にはクラスター全体 (名前空間全体) の権限が与えられます。

AKS Kubernetes リソースを追加する

  1. 環境の詳細ページで、[リソースの追加] を選択し、[Kubernetes] を選択します。

  2. [プロバイダー] ドロップダウンで、[Azure Kubernetes Service] を選択します。

  3. Azure サブスクリプション、クラスター、名前空間 (新規または既存) を選択します。

  4. [検証と作成] を選択して Kubernetes リソースを作成します。

  5. 環境のクラスターが表示されることを確認します。 クラスターにコードをまだデプロイしていない場合は、「これまで配置したことがない」というテキストが表示されます。

    Add a Kubernetes cluster.

既存のサービス アカウントを使用する

Azure Kubernetes Service は、環境内の Kubernetes リソースを名前空間にマップします。

環境外での Kubernetes サービス接続の設定の詳細については、「サービス接続」の「Kubernetes サービス接続」セクションを参照してください。

ヒント

汎用プロバイダー (既存のサービス アカウント) を使用して、Kubernetes リソースを非 AKS クラスターの名前空間にマップします。

AKS 以外の Kubernetes リソースを追加する

  1. 環境の詳細ページで、[リソースの追加] を選択し、[Kubernetes] を選択します。

  2. プロバイダーとして [汎用プロバイダー (既存のサービス アカウント)] を選択します。

  3. クラスター名と名前空間の値を追加します。

  4. サーバー URL を追加します。 URL は、次のコマンドを使用して取得できます。

    kubectl config view --minify -o 'jsonpath={.clusters[0].cluster.server}'
    
  5. シークレット オブジェクトを取得します。

    Kubernetes 1.22 以降

    service-account-name は、自分のアカウント名に置き換えてください。

    kubectl get secret -n <namespace>  -o jsonpath='{.items[?(@.metadata.annotations.kubernetes\.io/service-account\.name==\"service-account-name\")]}'
    

    何も取得しない場合は、「ServiceAccount の有効期間が長い API トークンを手動で作成する」を参照してください。

    Kubernetes 1.22 以下:

    1. サービス アカウントのシークレット名を検索する
    kubectl get serviceAccounts <service-account-name> -n <namespace> -o 'jsonpath={.secrets[*].name}'
    
    1. <service-account-secret-name> をこのコマンドの前のコマンドの値に置き換えます
    kubectl get secret <service-account-secret-name> -n <namespace> -o json
    
  6. 前のステップの出力を使用してシークレット オブジェクトを取得します。

    kubectl get secret <service-account-secret-name> -n <namespace> -o json
    
  7. JSON 形式でフェッチされたシークレット オブジェクトをコピーして [シークレット] フィールドに貼り付けます。

  8. [検証と作成] を選択して Kubernetes リソースを作成します。

パイプラインで Kubernetes リソースを参照する

Azure Kubernetes Service を使用して YAML パイプラインを構築する場合、パイプラインを構成する最も簡単な方法は、テンプレートを使用することです。 リポジトリに接続し、次の 2 つの Kubernetes Service オプションのいずれかを選択します。

テンプレートを使用すると、最初から YAML コードを記述したり、明示的なロール バインドを手動で作成したりすることなく、レビュー アプリを設定できます。

Kubernetes template options.

レビュー アプリを設定する

次の例では、PR 以外のブランチに対して最初のデプロイ ジョブを実行し、環境で通常の Kubernetes リソースに対してデプロイを実行します。 2 番目のジョブは PR ブランチに対してのみ実行され、オンデマンドで生成されたレビュー アプリ リソース (Kubernetes クラスター内の名前空間) に対してデプロイされます。 環境のリソース一覧ビューでは、リソースには "レビュー" というラベルが付けられます。 パイプラインで使用する変数を定義します。 [Azure Kubernetes Services へのデプロイ] テンプレートを使用すると、これらの変数が定義されます。

# Build and push image to Azure Container Registry; Deploy to Azure Kubernetes Service
trigger:
- main

resources:
- repo: self

variables:

  # Container registry service connection established during pipeline creation
  dockerRegistryServiceConnection: '12345' # Docker service connection identifier
  envName: 'myEnv' # name of your environment
  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: 
      name: $(envName).$(resourceName)
      resourceType: Kubernetes 
    strategy:
      runOnce:
        deploy:
          steps:
          - task: KubernetesManifest@0
            displayName: Create imagePullSecret
            inputs:
              action: createSecret
              secretName: $(imagePullSecret)
              dockerRegistryEndpoint: $(dockerRegistryServiceConnection)

          - task: KubernetesManifest@0
            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: 
      name: $(envName).$(resourceName)
      resourceType: Kubernetes
    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@0
            displayName: Create imagePullSecret
            inputs:
              action: createSecret
              secretName: $(imagePullSecret)
              namespace: $(k8sNamespaceForPR)
              dockerRegistryEndpoint: $(dockerRegistryServiceConnection)

          - task: KubernetesManifest@0
            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}'

          # Getting 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.<br><br>[Learn More](https://aka.ms/testwithreviewapps) about how to test and provide feedback for the app."
              fi
              echo "##vso[task.setvariable variable=GITHUB_COMMENT]$message"

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

次のステップ