共用方式為


環境中的 Kubernetes 資源

Azure DevOps 服務 |Azure DevOps Server |Azure DevOps Server 2022 |Azure DevOps Server 2020

本文說明如何在 Azure Pipelines 的 環境 中使用 Kubernetes 資源,您可以將其作為部署目標。 您可以連線到 Azure Kubernetes Service (AKS) 或其他雲端提供者中的公用或私人 Kubernetes 叢集。

環境資源檢視顯示 Kubernetes 資源的狀態,並提供管線的追蹤能力,使其追溯到觸發的提交紀錄。 您也可以建立動態 Kubernetes 環境資源,以在合併之前檢閱提取要求。 如需環境資源的詳細資訊,請參閱 YAML 管線中的資源資源安全性

注意

私人 AKS 叢集不會透過公用 IP 位址公開其 API 伺服器端點,因此您必須連線到叢集的虛擬網路。 您可以在虛擬網路內設定自我裝載代理程式,以存取叢集的虛擬網路或使用 受控 DevOps 集區。 如需詳細資訊,請參閱 連線至私有叢集的選項

Kubernetes環境資源優勢

環境中的 Kubernetes 環境資源和資源檢視有以下幾個優點:

  • 管道可追溯性Kubernetes manifest 部署任務會新增支援流水線追溯性的註解。 您可以看到負責更新命名空間內物件的 Azure DevOps 組織、專案和管線。

    螢幕擷取畫面,顯示 Kubernetes 叢集的管線可追蹤性。

  • 資源健康情況診斷。 工作負載狀態檢視是偵錯新部署所引進的錯誤或迴歸的快速方法。 例如,Pod 狀態資訊可協助您識別問題原因,如未設定imagePullSecrets所導致的ImagePullBackOff錯誤。

    顯示 Kubernetes 部署工作負載狀態檢視的螢幕擷取畫面。

  • 審查應用程序。 檢閱應用程式會將 Git 存放庫中的每個提取要求部署至環境中的動態 Kubernetes 資源,並張貼連結至檢閱應用程式的 GitHub 註解。 檢閱者可以在將變更合併至目標分支並部署至生產環境之前,查看 PR 變更的外觀,以及與其他相依服務搭配使用的方式。

    顯示 GitHub 中檢閱應用程式註解的螢幕擷取畫面。

AKS 資源

AKS 會在您選擇的叢集和命名空間中建立 ServiceAccount ,並將環境中的 Kubernetes 資源對應至指定的命名空間。 如需在環境外部設定 Kubernetes 服務連線的相關資訊,請參閱 Kubernetes 服務連線

對於已啟用 Kubernetes 角色型存取控制 (RBAC) 的叢集,也會建立 RoleBinding ,以將服務帳戶的範圍限制為所選的命名空間。 對於已停用 RBAC 的 Kubernetes 叢集,建立的服務帳戶具有跨命名空間的叢集範圍權限。

若要將 AKS 資源新增至 Azure Pipelines 環境:

  1. [管線>環境] 底下的環境頁面上,選取 [ 新增資源 ],然後選取 [Kubernetes]。

  2. 在下一個畫面上,選取 Azure Kubernetes Service 作為 提供者,然後選取您的 Azure 訂用帳戶、AKS 叢集以及新的或現有的 命名空間。 對於新的命名空間,請輸入命名空間名稱。

  3. 選取 驗證並建立。 新資源會出現在環境的 [資源] 索引標籤上,並顯示文字 [從未部署]。

    顯示新增 Kubernetes 資源的螢幕擷取畫面。

非 AKS 的 Kubernetes 資源

若要將 Kubernetes 資源從非 AKS 叢集對應至命名空間,您必須擁有非 AKS 提供者的現有服務帳戶。

若要將非 AKS Kubernetes 資源新增至 Azure Pipelines 環境:

  1. [管線>環境] 底下的環境頁面上,選取 [ 新增資源 ],然後選取 [Kubernetes]。

  2. 在下一個畫面上,為提供者選取一般提供者(現有服務帳戶)

  3. 叢集認證下,輸入 叢集名稱命名空間伺服器 URL密碼

    • 若要取得伺服器 URL,請在本機 shell 中執行 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

      注意

      如果您執行 get ServiceAccounts 命令時沒有任何結果,請參閱 手動建立 ServiceAccount 的持久性 API 權杖

  4. 選取 驗證並建立

管線中的 Kubernetes 資源

建立要部署至 AKS 的 YAML 管線最簡單的方式是從 部署至 Azure Kubernetes 服務 範本開始。 您不需要撰寫 YAML 程式碼,或手動建立明確的角色繫結。 產生的管線會根據您的組態設定設定並使用變數和其他值。

使用評論應用程式

作業 DeployPullRequest 會將 Git 存放庫中的每個提取要求部署至環境中的動態 Kubernetes 資源。 若要將此作業新增至管線,請選取 [部署至 Azure Kubernetes 服務] 組態表單中的 [啟用提取要求的檢閱應用程式流程] 複選框。

注意

若要將此作業新增至現有管線,請確定支援一般 Kubernetes 環境資源的服務連線已設定為 [使用叢集管理員認證]。 否則,必須為基礎服務帳戶在檢閱應用程式命名空間建立角色綁定。

檢閱應用程式資源在環境的資源清單中標示為檢閱

顯示管線環境清單中的審查環境的螢幕擷取畫面。

範例管線

下列範例管線是以 部署至 Azure Kubernetes Services 範本為基礎。 管線會先建置映像,並將其推送至 Azure Container Registry。

然後,第一個部署作業會針對 main 分支的任何提交執行,並在環境中部署至常規的 Kubernetes 資源。

第二個作業會在建立 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"