Note

Access to this page requires authorization. You can try signing in or .

Access to this page requires authorization. You can try .

Kubernetes resources in environments

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

This article describes using Kubernetes resources in Azure Pipelines environments that you can target with deployments. You can connect to public or private Kubernetes clusters in Azure Kubernetes Service (AKS) or other cloud providers.

Environment resource views show Kubernetes resource status and provide traceability to the pipeline and back to the triggering commit. You can also create dynamic Kubernetes environment resources to review pull requests before merge. For more information about environment resources, see Resources in YAML pipelines and Resource security.

Note

A private AKS cluster doesn't expose its API server endpoint through a public IP address, so you must connect to the cluster's virtual network. You can set up a self-hosted agent within a virtual network that can access the cluster's virtual network or use Managed DevOps Pools. For more information, see Options for connecting to a private cluster.

Kubernetes environment resource advantages

Kubernetes environment resources and resource views in environments provide the following benefits:

AKS resources

AKS creates a ServiceAccount in your chosen cluster and namespace, and maps Kubernetes resources in your environment to the specified namespace. For information about setting up a Kubernetes service connection outside of an environment, see Kubernetes service connection.

For a Kubernetes role-based access control (RBAC)-enabled cluster, RoleBinding is also created to limit the scope of the service account to the chosen namespace. For a Kubernetes RBAC-disabled cluster, the created service account has cluster-wide privileges across namespaces.

To add an AKS resource to an Azure Pipelines environment:

  1. On the environment's page under Pipelines > Environments, select Add resource and then select Kubernetes.

  2. On the next screen, select Azure Kubernetes Service for the Provider, and then select your Azure subscription, AKS Cluster, and new or existing Namespace. For a new namespace, enter the namespace name.

  3. Select Validate and create. The new resource appears on the environment's Resources tab with the text Never deployed.

    👁 Screenshot that shows an added Kubernetes resource.

Non-AKS Kubernetes resources

To map a Kubernetes resource from a non-AKS cluster to a namespace, you need to have an existing service account for the non-AKS provider.

To add a non-AKS Kubernetes resource to an Azure Pipelines environment:

  1. On the environment's page under Pipelines > Environments, select Add resource and then select Kubernetes.

  2. On the next screen, select Generic provider (existing service account) for the Provider.

  3. Under Cluster credentials, enter the Cluster name, Namespace, Server URL, and Secret.

    • To get the server URL, run kubectl config view --minify -o jsonpath={.clusters[0].cluster.server} in your local shell.

    • To get the secret:

      1. Get service account secret names by running kubectl get serviceAccounts <service-account-name> -n <namespace> -o=jsonpath={.secrets[*].name}.
      2. Run kubectl get secret <service-account-secret-name> -n <namespace> -o json using the output of the preceding command.

      Note

      If you get no results from the get ServiceAccounts command, see Manually create a long-lived API token for a ServiceAccount.

  4. Select Validate and create.

Kubernetes resources in pipelines

The easiest way to create a YAML pipeline to deploy to AKS is to start with the Deploy to Azure Kubernetes Services template. You don't have to write YAML code or manually create explicit role bindings. The generated pipeline sets and uses variables and other values based on your configuration settings.

Use the review app

The DeployPullRequest job deploys every pull request from your Git repository to a dynamic Kubernetes resource in the environment. To add this job to the pipeline, select the check box for Enable Review App flow for Pull Requests in the Deploy to Azure Kubernetes Services configuration form.

Note

To add this job to an existing pipeline, make sure the service connection backing the regular Kubernetes environment resource is set to Use cluster admin credentials. Otherwise, role bindings must be created for the underlying service account to the review app namespace.

Review app resources are labeled Review in the environment's Resource listing.

👁 Screenshot that shows the Review environment in the pipeline environment listing.

Example pipeline

The following example pipeline is based on the Deploy to Azure Kubernetes Services template. The pipeline first builds and pushes an image to Azure Container Registry.

The first deployment job then runs for any commits to the main branch, and deploys against a regular Kubernetes resource in the environment.

The second job runs when a PR is created or updated to the main branch, and deploys against a dynamic review app resource it creates in the cluster on demand.

# 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"

Related content


Feedback

Was this page helpful?

Additional resources