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 の組織、プロジェクト、パイプラインを確認できます。
リソース正常性診断。 ワークロードの状態ビューは、新しいデプロイによって発生した間違いや回帰をすばやくデバッグする方法です。 たとえば、ポッドの状態情報は、未構成の
imagePullSecretsなど、ImagePullBackOffエラーの原因を特定するのに役立ちます。
アプリを確認します。 レビュー アプリは、Git リポジトリから環境内の動的な Kubernetes リソースにすべてのプル要求をデプロイし、レビュー アプリにリンクする GitHub コメントを投稿します。 レビュー担当者は、変更がターゲット ブランチにマージされて運用環境にデプロイされる前に、PR の変更がどのように表示され、他の依存サービスと連携するかを確認できます。
AKS リソース
AKS は、選択したクラスターと名前空間に ServiceAccount を作成し、環境内の Kubernetes リソースを指定された名前空間にマップします。 環境の外部で Kubernetes サービス接続を設定する方法については、 Kubernetes サービス接続に関する説明を参照してください。
Kubernetes ロールベースのアクセス制御 (RBAC) が有効なクラスターの場合、RoleBinding も作成され、サービス アカウントのスコープを選択した名前空間に制限します。 Kubernetes RBAC が無効なクラスターの場合、作成されたサービス アカウントには、名前空間全体にわたるクラスター全体の特権があります。
AKS リソースを Azure Pipelines 環境に追加するには:
環境の [ Pipelines>Environments] の下にある [ リソースの追加 ] を選択し、[ Kubernetes] を選択します。
次の画面で、プロバイダーの Azure Kubernetes Service を選択し、Azure サブスクリプション、AKS クラスター、および新規または既存の名前空間を選択します。 新しい名前空間の場合は、名前空間名を入力します。
[検証して作成]を選択します。 環境の [ リソース ] タブに新しいリソースが表示され、" デプロイしない" というテキストが表示されます。
AKS 以外の Kubernetes リソース
非 AKS クラスターから名前空間に Kubernetes リソースをマップするには、AKS 以外のプロバイダーの既存のサービス アカウントが必要です。
AKS 以外の Kubernetes リソースを Azure Pipelines 環境に追加するには:
環境の [ Pipelines>Environments] の下にある [ リソースの追加 ] を選択し、[ Kubernetes] を選択します。
次の画面で、プロバイダーとして一般的なプロバイダー (既存のサービスアカウント)を選択します。
[クラスター資格情報] に、クラスター名、名前空間、サーバー URL、シークレットを入力します。
サーバー URL を取得するには、ローカル シェルで
kubectl config view --minify -o jsonpath={.clusters[0].cluster.server}を実行します。シークレットを取得するには:
-
kubectl get serviceAccounts <service-account-name> -n <namespace> -o=jsonpath={.secrets[*].name}を実行してサービス アカウント シークレット名を取得します。 - 上記のコマンドの出力を使用して、
kubectl get secret <service-account-secret-name> -n <namespace> -o jsonを実行します。
Note
get ServiceAccountsコマンドから結果が得つからない場合は、「ServiceAccount の有効期間が長い API トークンを手動で作成する」を参照してください。-
[検証して作成]を選択します。
パイプライン内の 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"