Skip to content

Commit

Permalink
Feat: Add a way to deploy without KEDA installed
Browse files Browse the repository at this point in the history
Doc: Replace "null" values by their exact representations on the "values.yaml"
  • Loading branch information
clemlesne committed Apr 13, 2023
1 parent 0b5765e commit 60c077e
Show file tree
Hide file tree
Showing 6 changed files with 151 additions and 214 deletions.
32 changes: 16 additions & 16 deletions README.md
Expand Up @@ -232,24 +232,23 @@ Out of the box, argument `--opt platform=linux/amd64,linux/arm64` can be added t

| Parameter | Description | Default |
|-|-|-|
| `additionalEnv` | Additional environment variables for the agent container. | `null` |
| `affinity` | Node affinity for pod assignment | `null` |
| `annotations` | Add custom annotations to the Pod. | `null` |
| `additionalEnv` | Additional environment variables for the agent container. | `[]` |
| `affinity` | Node affinity for pod assignment | `{}` |
| `annotations` | Add custom annotations to the Pod. | `{}` |
| `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), but can be started without. | `true` |
| `autoscaling.enabled` | Enable the auto-scaling. Requires [KEDA](https://keda.sh), but can be started without. Be warning, disabling auto-scaling implies a shutdown of the existing agents during a Helm instance upgrade, according to `pipelines.timeout`. | `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. If `pipelines.capabilities` is defined, cannot be set to `0`. | `1` |
| `extraVolumeMounts` | Additional volume mounts for the agent container. | `null` |
| `extraVolumes` | Additional volumes for the agent pod. | `null` |
| `fullnameOverride` | Overrides release fullname | `null` |
| `image.flavor` | Container image tag | `bullseye` |
| `extraVolumeMounts` | Additional volume mounts for the agent container. | `[]` |
| `extraVolumes` | Additional volumes for the agent pod. | `[]` |
| `fullnameOverride` | Overrides release fullname | `""` |
| `image.flavor` | Container image tag, can be `bullseye`, `focal`, `jammy`, or `ubi8`. | `bullseye` |
| `image.pullPolicy` | Container image pull policy | `IfNotPresent` |
| `image.repository` | Container image repository | `ghcr.io/clemlesne/azure-pipelines-agent:bullseye` |
| `image.version` | Container image tag | *Version* |
| `imagePullSecrets` | Use secrets to pull the container image. | `null` |
| `initContainers` | InitContainers for the agent pod. | `null` |
| `nameOverride` | Overrides release name | `null` |
| `nodeSelector` | Node labels for pod assignment | `null` |
| `imagePullSecrets` | Use secrets to pull the container image. | `[]` |
| `initContainers` | InitContainers for the agent pod. | `[]` |
| `nameOverride` | Overrides release name | `""` |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `pipelines.cacheSize` | Total cache to attach to the Azure Pipelines standard directory. By default, [same amount as the Microsoft Hosted agents](https://learn.microsoft.com/en-us/azure/devops/pipelines/agents/hosted?view=azure-devops&tabs=yaml#hardware). | `10Gi` |
| `pipelines.cacheType` | Disk type to attach to the Azure Pipelines standard directory. See your cloud provider for types ([Azure](https://learn.microsoft.com/en-us/azure/aks/concepts-storage#storage-classes), [AWS](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html)). | `managed-csi` (Azure compatible) |
| `pipelines.capabilities` | Add [demands/capabilities](https://learn.microsoft.com/en-us/azure/devops/pipelines/process/demands?view=azure-devops&tabs=yaml) to the agent | `[]` |
Expand All @@ -259,12 +258,13 @@ Out of the box, argument `--opt platform=linux/amd64,linux/arm64` can be added t
| `pipelines.tmpdirSize` | Total size of the [standard `TMPDIR` directory](https://en.wikipedia.org/wiki/TMPDIR). | `1Gi` |
| `pipelines.tmpdirType` | Disk type to attach to the [standard `TMPDIR` directory](https://en.wikipedia.org/wiki/TMPDIR). See your cloud provider for types ([Azure](https://learn.microsoft.com/en-us/azure/aks/concepts-storage#storage-classes), [AWS](https://docs.aws.amazon.com/eks/latest/userguide/storage-classes.html)). | `managed-csi` (Azure compatible) |
| `pipelines.url` | The Azure base URL for your organization | *None* |
| `podSecurityContext` | Security rules applied to the Pod ([more details](https://kubernetes.io/docs/concepts/security/pod-security-standards)). | `null` |
| `podSecurityContext` | Security rules applied to the Pod ([more details](https://kubernetes.io/docs/concepts/security/pod-security-standards)). | `{}` |
| `replicaCount` | Default fixed amount of agents deployed. Those are not auto-scaled. | `3` |
| `resources` | Resource limits | `{ "resources": { "limits": { "cpu": 2, "memory": "4Gi" }, "requests": { "cpu": 1, "memory": "2Gi" } }}` |
| `securityContext` | Security rules applied to the container ([more details](https://kubernetes.io/docs/concepts/security/pod-security-standards)). | `null` |
| `securityContext` | Security rules applied to the container ([more details](https://kubernetes.io/docs/concepts/security/pod-security-standards)). | `{}` |
| `serviceAccount.create` | Create ServiceAccount | `true` |
| `serviceAccount.name` | ServiceAccount name | *Release name* |
| `tolerations` | Toleration labels for pod assignment. | `null` |
| `tolerations` | Toleration labels for pod assignment. | `[]` |

## [Security](./SECURITY.md)

Expand Down
99 changes: 99 additions & 0 deletions src/helm/azure-pipelines-agent/templates/_helpers.tpl
Expand Up @@ -60,3 +60,102 @@ Create the name of the service account to use
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

{{- define "this.podSharedTemplate" -}}
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 2 }}
{{- end }}
serviceAccountName: {{ include "this.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.initContainers }}
initContainers:
{{- toYaml . | nindent 2 }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.pipelines.timeout | int | required "A value for .Values.pipelines.timeout is required" }}
containers:
- name: azp-agent
securityContext:
runAsUser: 0
{{- with .Values.securityContext }}
{{- toYaml . | nindent 6 }}
{{- end }}
image: "{{ .Values.image.repository | required "A value for .Values.image.repository is required" }}:{{ .Values.image.flavor | required "A value for .Values.image.flavor is required" }}-{{ default .Chart.Version .Values.image.version }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
lifecycle:
preStop:
exec:
command: [bash, -c, "bash ${AZP_HOME}/config.sh remove --auth PAT --token $AZP_TOKEN"]
env:
- name: VSO_AGENT_IGNORE
value: AZP_TOKEN
- name: AZP_AGENT_NAME
value: {{ include "this.fullname" . }}-template
- name: AZP_URL
valueFrom:
secretKeyRef:
name: {{ include "this.fullname" . }}
key: url
- name: AZP_POOL
value: {{ .Values.pipelines.pool | quote | required "A value for .Values.pipelines.pool is required" }}
- name: AZP_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "this.fullname" . }}
key: pat
# Agent capabilities
- name: flavor_{{ .Values.image.flavor | required "A value for .Values.image.flavor is required" }}
{{- range .Values.pipelines.capabilities }}
- name: {{ . }}
{{- end }}
{{- with .Values.additionalEnv }}
{{- toYaml . | nindent 6 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 6 | required "A value for .Values.resources is required" }}
volumeMounts:
- name: azp-work
mountPath: /home/root/azp-work
- name: local-tmp
mountPath: /home/root/.local/tmp
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 6 }}
{{- end }}
volumes:
- name: azp-work
ephemeral:
volumeClaimTemplate:
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: {{ .Values.pipelines.cacheType | required "A value for .Values.pipelines.cacheType is required" }}
resources:
requests:
storage: {{ .Values.pipelines.cacheSize | required "A value for .Values.pipelines.cacheSize is required" }}
- name: local-tmp
ephemeral:
volumeClaimTemplate:
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: {{ .Values.pipelines.tmpdirType | required "A value for .Values.pipelines.tmpdirType is required" }}
resources:
requests:
storage: {{ .Values.pipelines.tmpdirSize | required "A value for .Values.pipelines.tmpdirSize is required" }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 2 }}
{{- end }}
{{- end }}
27 changes: 27 additions & 0 deletions src/helm/azure-pipelines-agent/templates/deployment.yaml
@@ -0,0 +1,27 @@
{{- if not (and (.Values.autoscaling.enabled) (.Capabilities.APIVersions.Has "keda.sh/v1alpha1")) }}
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "this.fullname" . }}-{{ .Release.Revision }}
labels:
{{- include "this.labels" . | nindent 4 }}
spec:
selector:
matchLabels:
{{- include "this.selectorLabels" . | nindent 6 }}
replicas: {{ .Values.replicaCount | int | required "A value for .Values.replicaCount is required" }}
template:
metadata:
labels:
{{- include "this.selectorLabels" . | nindent 8 }}
annotations:
# Cluster autoscaler never evicts this Pod
cluster-autoscaler.kubernetes.io/safe-to-evict: "false"
{{- with .Values.annotations }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
# The pod will shut down at each run, we need to restart it
restartPolicy: Always
{{- include "this.podSharedTemplate" . | nindent 6 }}
{{- end }}
104 changes: 4 additions & 100 deletions src/helm/azure-pipelines-agent/templates/hpa.yaml
Expand Up @@ -35,106 +35,10 @@ spec:
{{- toYaml . | nindent 10 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 10 }}
{{- end }}
serviceAccountName: {{ include "this.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.initContainers }}
initContainers:
{{- toYaml . | nindent 10 }}
{{- end }}
terminationGracePeriodSeconds: {{ .Values.pipelines.timeout | int | required "A value for .Values.pipelines.timeout is required" }}
containers:
- name: azp-agent
securityContext:
runAsUser: 0
{{- with .Values.securityContext }}
{{- toYaml . | nindent 14 }}
{{- end }}
image: "{{ .Values.image.repository | required "A value for .Values.image.repository is required" }}:{{ .Values.image.flavor | required "A value for .Values.image.flavor is required" }}-{{ default .Chart.Version .Values.image.version }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
lifecycle:
preStop:
exec:
command: [bash, -c, "bash ${AZP_HOME}/config.sh remove --auth PAT --token $AZP_TOKEN"]
env:
- name: VSO_AGENT_IGNORE
value: AZP_TOKEN
- name: AZP_AGENT_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: AZP_URL
valueFrom:
secretKeyRef:
name: {{ include "this.fullname" . }}
key: url
- name: AZP_POOL
value: {{ .Values.pipelines.pool | quote | required "A value for .Values.pipelines.pool is required" }}
- name: AZP_TOKEN
valueFrom:
secretKeyRef:
name: {{ include "this.fullname" . }}
key: pat
# Agent capabilities
- name: flavor_{{ .Values.image.flavor | required "A value for .Values.image.flavor is required" }}
{{- range .Values.pipelines.capabilities }}
- name: {{ . }}
{{- end }}
{{- with .Values.additionalEnv }}
{{- toYaml . | nindent 14 }}
{{- end }}
resources:
{{- toYaml .Values.resources | nindent 14 | required "A value for .Values.resources is required" }}
volumeMounts:
- name: azp-work
mountPath: /home/root/azp-work
- name: local-tmp
mountPath: /home/root/.local/tmp
{{- with .Values.extraVolumeMounts }}
{{- toYaml . | nindent 14 }}
{{- end }}
volumes:
- name: azp-work
ephemeral:
volumeClaimTemplate:
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: {{ .Values.pipelines.cacheType | required "A value for .Values.pipelines.cacheType is required" }}
resources:
requests:
storage: {{ .Values.pipelines.cacheSize | required "A value for .Values.pipelines.cacheSize is required" }}
- name: local-tmp
ephemeral:
volumeClaimTemplate:
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: {{ .Values.pipelines.tmpdirType | required "A value for .Values.pipelines.tmpdirType is required" }}
resources:
requests:
storage: {{ .Values.pipelines.tmpdirSize | required "A value for .Values.pipelines.tmpdirSize is required" }}
{{- with .Values.extraVolumes }}
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 10 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 10 }}
{{- end }}
maxReplicaCount: {{ sub (.Values.autoscaling.maxReplicas | int | required "A value for .Values.autoscaling.maxReplicas is required") (.Values.autoscaling.minReplicas | int | required "A value for .Values.autoscaling.minReplicas is required") }}
# The job cannot crash, this is not functionally intended; a shutdown is functionally a pipeline end
restartPolicy: Never
{{- include "this.podSharedTemplate" . | nindent 8 }}
maxReplicaCount: {{ .Values.autoscaling.maxReplicas | int | required "A value for .Values.autoscaling.maxReplicas is required" }}
minReplicaCount: 0
pollingInterval: 15
rollout:
Expand Down

0 comments on commit 60c077e

Please sign in to comment.