After hosting the DevOps agent on a Kubernetes Cluster, it may be need to auto-scale the number of agents depending on the number of queued builds.
To auto-scale the agent, this post explores using Kubernetes Horizontal Pod Autoscaler (HPA) with an external metric exposed by the Azure DevOps REST API.
Note: The pre-requisite to this post is to have an Image for the DevOps agent as detailed here.
Refer:
- Containerizing the self-hosted agents
- The Containerized agents can be deployed to ACI or AKS
- Auto-Scaling the agents on AKS
The components to achieve this are
- Metrics Provider
- Metrics Aggregator
- HPA Controller
- Agent Deployment
The external metric to scale the agents will be the number of builds in a notStarted Status. The Azure DevOps Services REST API provides the List API with a filter.
Refer to sample exporter here
The aggregator service is responsible to query the DevOps REST API and format the metric as required by Kubernetes
- Uses a PAT token with access to list builds
- REST API call to the devops services
- Format the response in a kubernetes consumable format
- Expose the API on an endpoint the APIService object expects
The format of each metric should be as below
{
"kind": "MetricValueList",
"apiVersion": "custom.metrics.k8s.io/v1beta1",
"metadata": {
"selfLink": "/apis/custom.metrics.k8s.io/v1beta1/"
},
"items": [
{
"describedObject": {
"kind": "Service",
"namespace": "default",
"name": "devops-proxy",
"apiVersion": "/v1beta1"
},
"metricName": "count",
"timestamp": "2018-01-10T16:49:07Z",
"value": "10"
}
]
}
The endpoint that will be consumed by Kubernetes is as /apis/custom.metrics.k8s.io/v1beta1/namespaces/{namespace}/services/{serviceName}/{metricName}
The Horizontal Pod Autoscaler fetches the metrics from the aggregator service and decides to scale the target deployment as required.
- APIService object to register the external API
- HPA object to define the target, metric and the Scale
apiVersion: apiregistration.k8s.io/v1beta1
kind: APIService
metadata:
name: v1beta1.custom.metrics.k8s.io
spec:
insecureSkipTLSVerify: true
group: custom.metrics.k8s.io
groupPriorityMinimum: 1000
versionPriority: 5
service:
name: devops-proxy
namespace: default
version: v1beta1
The HPA object for reference
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: php-apache-autoscaler
namespace: default
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {agentDeploymentName}
minReplicas: 1
maxReplicas: 10
metrics:
- type: Object
object:
target:
kind: Service
name: devops-proxy
metricName: count
targetValue: 1
The deployment manifest for the agent
apiVersion: apps/v1
kind: Deployment
metadata:
name: devops-agent
spec:
selector:
matchLabels:
run: devops-agent
replicas: 1
template:
metadata:
labels:
run: devops-agent
spec:
containers:
- name: devops-agent
image: myregistry.azurecr.io/dockeragent:latest
env:
– name: AZP_URL
value: <https://dev.azure.com/orgname>
– name: AZP_TOKEN
value: <PAT_token>
– name: AZP_AGENT_NAME
value: <agent_name>
– name: AZP_POOL
value: <pool_name>
resources:
limits:
cpu: 500m
requests:
cpu: 200m
Once the deployments are done, queue-up new builds to observe that new agent pods are added.