In Azure DevOps you can use Kubernetes resources to target Kubernetes clusters in an environment for deployment. You can configure your local Kubernetes cluster using Docker-desktop and then create an environment in Azure DevOps. You can use deployment job in pipeline to deploy your microservice in Kubernetes resource created in environment.

Steps:

Note: It requires a self hosted build agent to be running on this laptop where Docker-desktop kubernetes setup is running.

1. Install Docker-desktop and enable kubernetes. This will create local kubernetes setup on your laptop/desktop.

2. Now create service account, role and rolebinding to allow Azure DevOps to access this local Kubernetes cluster in Docker-desktop. The existing ServiceAccount can be mapped to a Kubernetes resource within your environment to a namespace.

–> Create Namespace

apiVersion: v1
kind: Namespace
metadata:
  name: dev-cluster

 

–> Create Service-Account

apiVersion: v1
kind: ServiceAccount
metadata:
  name: dev-cluster-svc
  namespace: dev-cluster

 

–> Create Role

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: dev-cluster
  name: role-dev-cluster
rules:
- apiGroups: ["extensions", "apps",""]
  resources: ["*"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]

 

–> Create Role-binding

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: role-binding-dev-cluster
  namespace: dev-cluster
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: role-dev-cluster
subjects:
- kind: ServiceAccount
  name: dev-cluster-svc
  namespace: dev-cluster 

Note: You can change scope of Role and name of service and namespace.

3. Now create Kubernetes Resource under Environments in Azure DevOps. Login to Azure DevOps and select Environments under Pipelines as shown-

 

>>> On the new screen enter Name, description and select Kubernetes as shown-

>> To fill the values on new screen, use the following commands to get the values of cluster, namespace, api server url and serviceaccount’s secret value.

#get cluster names
kubectl config get-contexts

#get api server url 
kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}{"\n"}'

#get service account secret names
kubectl get serviceAccounts dev-cluster-svc -n dev-cluster -o=jsonpath='{.secrets[*].name}{"\n"}'

#get secret value in json format
kubectl get secret dev-cluster-svc-token-7scpf -n dev-cluster -o json

 

 

>> Click on “Validate and create”. It will throw error windows as shown. The reason is Azure DevOps not able to reach your local Kubernetes Server Api URL. you can click on “continue anyway”. It will create Environment.

NOTE: The only limitation is that Azure DevOps will not be able to connect to K8s resources to show the service, pods etc in the Environment screen. Also the deployment will work only with self host build agent running on this laptop where docker-desktop kubernetes cluster is setup.

>>> It will show the environment created as shown-

4. Now we will add deployment task in build pipeline-

For my sample project which is in Golang, the pipeline is

trigger: 
 - main

pool:
   name: Self-Hosted-Agent

variables:
  - group: dev
stages:
- stage: Build 
  jobs:
  - job:
    displayName: Build the application
    steps: 
    - task: Go@0
      displayName: "Go Get"
      inputs:
        command: 'get'
        arguments: '-d'
        workingDirectory: '$(System.DefaultWorkingDirectory)'
    - task: Go@0
      displayName: "Go Build"
      inputs:
        command: 'build'
        workingDirectory: '$(System.DefaultWorkingDirectory)'
    - task: qetza.replacetokens.replacetokens-task.replacetokens@3
      displayName: 'Replace image version in deployment.yaml'
      inputs:
        rootDirectory: '$(System.DefaultWorkingDirectory)'
        targetFiles: 'deployment.yaml'
        tokenPrefix: '#{'
        tokenSuffix: '}#'
    - task: CopyFiles@2
      inputs:
        SourceFolder: '$(System.DefaultWorkingDirectory)'
        Contents: 'deployment.yaml'
        TargetFolder: '$(Build.ArtifactStagingDirectory)'
    - task: PublishBuildArtifacts@1
      inputs:
         artifactName: drop

    - task: Docker@2
      displayName: Build an image
      inputs:
        command: build
        dockerfile: '$(System.DefaultWorkingDirectory)/Dockerfile'
        buildContext: '$(System.DefaultWorkingDirectory)'
        repository: $(AWS_ECR_MAGE_URI)

    - task: ECRPushImage@1
      inputs:
        awsCredentials: 'AWS_Service'
        regionName: $(AWS_REGION)
        imageSource: 'imagename'
        sourceImageName: $(AWS_ECR_MAGE_URI)
        sourceImageTag: $(Build.BuildId)
        pushTag: $(Build.BuildId)
        repositoryName: $(AWS_ECR_REPOSITORY_NAME)
- stage: Dev
  dependsOn: Build
  jobs:
  - deployment:
    displayName: Dev deploy
    environment: dev
    strategy:
     runOnce:
       deploy:
         steps:
           - script: kubectl apply -f deployment.yaml
             displayName: 'Dev Deploy'

 

Deployment.yaml is

apiVersion: apps/v1
kind: Deployment
metadata:
  name: helloworld-deploy
  namespace: dev-cluster
  labels:
    app: hello-world-deploy
spec:
  replicas: 1
  selector:
    matchLabels:
      app: hello-world-app
  template:
    metadata:
      labels:
        app: hello-world-app
    spec:
      containers:
      - name: helloworldapp
        image: 706949302588.dkr.ecr.ap-southeast-2.amazonaws.com/test-hello-world:#{Build.BuildId}#
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 8080
        resources:
          limits:
            cpu: 100m
            memory: 512Mi
          requests:
            cpu: 100m
            memory: 512Mi
      securityContext:
        runAsUser: 1000
      imagePullSecrets:
      - name: aws-registry
          
          
          
---

apiVersion: v1
kind: Service
metadata:
  labels:
    app: hello-world-svc
  name: hello-world-svc
  namespace: dev-cluster
spec:
  ports:
  - name: helloworld
    nodePort: 30423
    port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: hello-world-app
  sessionAffinity: None
  type: NodePort

 

When you run the pipeline, no need to provide Kubernetes connection details. Only Environment name needs to be set in Dev stage. It deploys the pods and service into the cluster based on resource set for Dev environment.

The deployment will look like below screen after successful deployment-

 

Also under Environments you can see the deployments

 

 

Reference:

https://docs.microsoft.com/en-us/azure/devops/pipelines/process/environments-kubernetes?view=azure-devops