diff --git a/.github/workflows/pipeline.yaml b/.github/workflows/pipeline.yaml index e788e83f..5932adc6 100644 --- a/.github/workflows/pipeline.yaml +++ b/.github/workflows/pipeline.yaml @@ -148,7 +148,7 @@ jobs: type=sha labels: | io.artifacthub.package.category=integration-delivery - io.artifacthub.package.keywords=agent,azure,azure-devops,azure-pipelines,container,devops,docker,helm,kubernetes,pipelines + io.artifacthub.package.keywords=agent,azure,azure-devops,azure-pipelines,container,devops,docker,helm,kubernetes,pipelines,self-hosted,self-hosted-agent,auto-scale,keda io.artifacthub.package.logo-url=https://raw.githubusercontent.com/${{ env.CONTAINER_NAME }}/${{ github.sha }}/logo.svg io.artifacthub.package.maintainers=[{"name":"${{ github.actor }}","email":"${{ github.actor }}@users.noreply.github.com"}] io.artifacthub.package.readme-url=https://raw.githubusercontent.com/${{ env.CONTAINER_NAME }}/${{ github.sha }}/README.md diff --git a/README.md b/README.md index 57bc7f37..566e7c07 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Azure Pipelines Agent -[Azure Pipelines Agent](https://github.com/clemlesne/azure-pipelines-agent) is self-hosted agent that you can run in a container with Kubernetes. +[Azure Pipelines Agent](https://github.com/clemlesne/azure-pipelines-agent) is self-hosted agent in Kubernetes, cheap to run, secure, auto-scaled and easy to deploy. [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/azure-pipelines-agent)](https://artifacthub.io/packages/search?repo=azure-pipelines-agent) [![Artifact Hub](https://img.shields.io/endpoint?url=https://artifacthub.io/badge/repository/azure-pipelines-agent-container)](https://artifacthub.io/packages/search?repo=azure-pipelines-agent-container) @@ -11,6 +11,8 @@ Features: - Agent register itself with the Azure DevOps server. - Agent restart itself if it crashes. - Agent update itself to the latest version. +- Auto-scale based on Pipeline usage (requires [KEDA](https://keda.sh)). +- Cheap to run (dynamic provisioning of agents, can scale to 0 and in few seconds 100+). - Compatible with all Debian and Ubuntu LTS releases. - Container security updates are applied every week. - SBOM (Software Bill of Materials) is packaged with each container image. @@ -20,6 +22,15 @@ Features: ### Deployment in Kubernetes using Helm +Minimal configuration: + +```yaml +pipelines: + url: https://dev.azure.com/your-organization + pat: your-pat + pool: your-pool +``` + Use Helm to install the latest released chart: ```bash @@ -44,6 +55,10 @@ helm upgrade --install agent clemlesne-azure-pipelines-agent/azure-pipelines-age |-|-|-| | `additionalEnv` | Additional environment variables for the agent container. | `[]` | | `affinity` | Node affinity for pod assignment | `{}` | +| `autoscaling.cooldown` | Time in seconds the automation will wait until there is no more pipeline asking for an agent. Same time is then applied for system termination. | `60` | +| `autoscaling.enabled` | Enable the auto-scaling, requires [KEDA](https://keda.sh). | `true` | +| `autoscaling.maxReplicas` | Maximum number of pods, remaining jobs will be kept in queue. | `100` | +| `autoscaling.minReplicas` | Minimum number of pods. If autoscaling not enabled, the number of replicas to run. | `1` | | `extraVolumeMounts` | Additional volume mounts for the agent container. | `[]` | | `extraVolumes` | Additional volumes for the agent pod. | `[]` | | `fullnameOverride` | Overrides release fullname | `""` | @@ -52,15 +67,15 @@ helm upgrade --install agent clemlesne-azure-pipelines-agent/azure-pipelines-age | `initContainers` | InitContainers for the agent pod. | `[]` | | `nameOverride` | Overrides release name | `""` | | `nodeSelector` | Node labels for pod assignment | `{}` | -| `pipelines.agent.workDir` | The work directory the agent should use | `_work` | -| `pipelines.pat` | Personal Access Token (PAT) used by the agent to connect. | `""` | -| `pipelines.pool` | Agent pool to which the Agent should register. | `""` | -| `pipelines.url` | The Azure base URL for your organization | `""` | -| `resources` | Resource limits | `{}` | +| `pipelines.pat` | Personal Access Token (PAT) used by the agent to connect. | *None* | +| `pipelines.pool` | Agent pool to which the Agent should register. | *None* | +| `pipelines.url` | The Azure base URL for your organization | *None* | +| `pipelines.workDir` | The work directory the agent should use | `_work` | +| `resources` | Resource limits | `{ "resources": { "limits": { "cpu": 2, "memory": "4Gi" }, "requests": { "cpu": 1, "memory": "2Gi" } }}` | | `serviceAccount.create` | Create ServiceAccount | `true` | -| `serviceAccount.name` | ServiceAccount name | _release name_ | -| `tagSuffix` | Container image tag | `""` (same version as the chart) | -| `tolerations` | Toleration labels for pod assignment | `[]` | +| `serviceAccount.name` | ServiceAccount name | *Release name* | +| `tagSuffix` | Container image tag | *App version* | +| `tolerations` | Toleration labels for pod assignment. | `[]` | ## Support diff --git a/src/helm/azure-pipelines-agent/Chart.yaml b/src/helm/azure-pipelines-agent/Chart.yaml index dc44ce55..ce0cc29c 100644 --- a/src/helm/azure-pipelines-agent/Chart.yaml +++ b/src/helm/azure-pipelines-agent/Chart.yaml @@ -7,6 +7,7 @@ appVersion: 0.0.0 icon: https://raw.githubusercontent.com/clemlesne/azure-pipelines-agent/master/logo.svg keywords: - agent + - auto-scale - azure - azure-devops - azure-pipelines @@ -14,8 +15,11 @@ keywords: - devops - docker - helm + - keda - kubernetes - pipelines + - self-hosted + - self-hosted-agent home: https://github.com/clemlesne/azure-pipelines-agent sources: - https://github.com/clemlesne/azure-pipelines-agent diff --git a/src/helm/azure-pipelines-agent/templates/deployment.yaml b/src/helm/azure-pipelines-agent/templates/deployment.yaml index 608a2609..914e73a9 100644 --- a/src/helm/azure-pipelines-agent/templates/deployment.yaml +++ b/src/helm/azure-pipelines-agent/templates/deployment.yaml @@ -5,6 +5,9 @@ metadata: labels: {{- include "this.labels" . | nindent 4 }} spec: + {{- if not (and (.Values.autoscaling.enabled) (.Capabilities.APIVersions.Has "keda.sh/v1alpha1")) }} + replicas: {{ .Values.autoscaling.minReplicas }} + {{- end }} selector: matchLabels: {{- include "this.selectorLabels" . | nindent 6 }} @@ -20,6 +23,7 @@ spec: {{- toYaml . | nindent 8 }} {{- end }} serviceAccountName: {{ include "this.serviceAccountName" . }} + terminationGracePeriodSeconds: {{ .Values.autoscaling.cooldown }} containers: - name: {{ .Chart.Name }} securityContext: @@ -38,9 +42,9 @@ spec: name: {{ include "this.fullname" . }} key: url - name: AZP_POOL - value: {{ .Values.pipelines.pool | quote }} + value: {{ .Values.pipelines.pool | quote | required "A value for .Values.pipelines.pool is required" }} - name: AZP_WORK - value: {{ .Values.pipelines.agent.workDir | quote }} + value: {{ .Values.pipelines.workDir | quote }} - name: AZP_TOKEN valueFrom: secretKeyRef: diff --git a/src/helm/azure-pipelines-agent/templates/hpa.yaml b/src/helm/azure-pipelines-agent/templates/hpa.yaml index 596bf6e9..f18eb3fa 100644 --- a/src/helm/azure-pipelines-agent/templates/hpa.yaml +++ b/src/helm/azure-pipelines-agent/templates/hpa.yaml @@ -1,3 +1,4 @@ +{{- if and (.Values.autoscaling.enabled) (.Capabilities.APIVersions.Has "keda.sh/v1alpha1") }} apiVersion: keda.sh/v1alpha1 kind: TriggerAuthentication metadata: @@ -25,10 +26,11 @@ spec: maxReplicaCount: {{ .Values.autoscaling.maxReplicas }} minReplicaCount: {{ .Values.autoscaling.minReplicas }} pollingInterval: 5 - cooldownPeriod: 60 + cooldownPeriod: {{ .Values.autoscaling.cooldown }} triggers: - type: azure-pipelines metadata: - poolName: {{ .Values.pipelines.pool }} + poolName: {{ .Values.pipelines.pool | required "A value for .Values.pipelines.pool is required" }} authenticationRef: name: {{ include "this.fullname" . }} +{{- end }} diff --git a/src/helm/azure-pipelines-agent/templates/secret.yaml b/src/helm/azure-pipelines-agent/templates/secret.yaml index a1e49c02..d8eba2fb 100644 --- a/src/helm/azure-pipelines-agent/templates/secret.yaml +++ b/src/helm/azure-pipelines-agent/templates/secret.yaml @@ -6,5 +6,5 @@ metadata: labels: {{- include "this.labels" . | nindent 4 }} stringData: - pat: {{ .Values.pipelines.pat | quote }} - url: {{ .Values.pipelines.url | quote }} + pat: {{ .Values.pipelines.pat | quote | required "A value for .Values.pipelines.pat is required" }} + url: {{ .Values.pipelines.url | quote | required "A value for .Values.pipelines.url is required" }} diff --git a/src/helm/azure-pipelines-agent/values.yaml b/src/helm/azure-pipelines-agent/values.yaml index c7a2e9d4..cd152d27 100644 --- a/src/helm/azure-pipelines-agent/values.yaml +++ b/src/helm/azure-pipelines-agent/values.yaml @@ -1,9 +1,3 @@ -# Default values for this. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - -replicaCount: 1 - image: repository: ghcr.io/clemlesne/azure-pipelines-agent:bullseye pullPolicy: IfNotPresent @@ -15,16 +9,17 @@ nameOverride: "" fullnameOverride: "" autoscaling: + enabled: true + # If autoscaling not enabled, the number of replicas to run minReplicas: 1 maxReplicas: 100 + cooldown: 60 pipelines: - url: "" - pat: "" - pool: Default - agent: - name: "" - workDir: _work + url: null + pat: null + pool: null + workDir: _work serviceAccount: create: true @@ -42,17 +37,13 @@ securityContext: {} # runAsNonRoot: true # runAsUser: 1000 -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m -# memory: 128Mi +resources: + limits: + cpu: 2 + memory: 4Gi + requests: + cpu: 1 + memory: 2Gi nodeSelector: {}