From fffe770ecb33d2c5501344ac9810d5c68648fa44 Mon Sep 17 00:00:00 2001 From: pinkneyj Date: Fri, 3 Jul 2026 12:02:28 +0100 Subject: [PATCH 1/4] update affinity on server and aggregator to be automatically set --- helm/templates/agent-deploy.yaml | 4 +++- helm/templates/aggregator-deploy.yaml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/helm/templates/agent-deploy.yaml b/helm/templates/agent-deploy.yaml index 59ec7c3ad..f748b59ef 100644 --- a/helm/templates/agent-deploy.yaml +++ b/helm/templates/agent-deploy.yaml @@ -347,7 +347,9 @@ spec: {{- include "cloudzero-agent.generateImagePullSecrets" (dict "root" . "image" .Values.components.prometheus.image) | nindent 6 }} {{- include "cloudzero-agent.generateNodeSelector" (dict "default" .Values.defaults.nodeSelector "nodeSelector" .Values.server.nodeSelector) | nindent 6 }} {{- include "cloudzero-agent.generateTolerations" (concat .Values.defaults.tolerations .Values.server.tolerations) | nindent 6 }} - {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" .Values.server.affinity) | nindent 6 }} + {{- $podAntiAffinity := dict "podAntiAffinity" (dict "preferredDuringSchedulingIgnoredDuringExecution" (list (dict "weight" 100 "podAffinityTerm" (dict "labelSelector" (dict "matchLabels" (dict "app.kubernetes.io/name" "server")) "topologyKey" "kubernetes.io/hostname")))) }} + {{- $userAffinity := deepCopy (.Values.server.affinity | default (dict)) }} + {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" (merge $userAffinity $podAntiAffinity)) | nindent 6 }} {{- with .Values.server.topologySpreadConstraints }} topologySpreadConstraints: {{- toYaml . | nindent 8 }} diff --git a/helm/templates/aggregator-deploy.yaml b/helm/templates/aggregator-deploy.yaml index 4edf7b430..e4411741d 100644 --- a/helm/templates/aggregator-deploy.yaml +++ b/helm/templates/aggregator-deploy.yaml @@ -177,7 +177,9 @@ spec: {{- include "cloudzero-agent.generateDNSInfo" (dict "defaults" .Values.defaults.dns) | nindent 6 }} {{- include "cloudzero-agent.generateImagePullSecrets" (dict "root" . "image" .Values.components.agent.image) | nindent 6 }} {{- include "cloudzero-agent.generateNodeSelector" (dict "default" .Values.defaults.nodeSelector "nodeSelector" .Values.aggregator.nodeSelector) | nindent 6 }} - {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" .Values.aggregator.affinity) | nindent 6 }} + {{- $podAntiAffinity := dict "podAntiAffinity" (dict "preferredDuringSchedulingIgnoredDuringExecution" (list (dict "weight" 100 "podAffinityTerm" (dict "labelSelector" (dict "matchLabels" (dict "app.kubernetes.io/name" "aggregator")) "topologyKey" "kubernetes.io/hostname")))) }} + {{- $userAffinity := deepCopy (.Values.aggregator.affinity | default (dict)) }} + {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" (merge $userAffinity $podAntiAffinity)) | nindent 6 }} {{- include "cloudzero-agent.generateTolerations" (concat .Values.defaults.tolerations) | nindent 6 }} {{- with .Values.server.topologySpreadConstraints }} From 94043df139bf275a44e0a263f84177c77c30dd9e Mon Sep 17 00:00:00 2001 From: pinkneyj Date: Wed, 5 Aug 2026 14:31:09 +0100 Subject: [PATCH 2/4] push change for greptile pickup --- helm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/README.md b/helm/README.md index 3f840d032..4ea8eaeb1 100644 --- a/helm/README.md +++ b/helm/README.md @@ -6,7 +6,7 @@ A Helm chart for deploying a metrics collector to send cluster metrics to the CloudZero platform. -For the latest release, see [Releases](https://github.com/Cloudzero/cloudzero-charts/releases). You can also [enable release notifications](#enabling-release-notifications). +For the latest release, see [Releases](https://github.com/Cloudzero/cloudzero-charts/releases). You can also [enable release notifications](#enabling-release-notifications). ## Prerequisites From 69940404a3a67c261c0239ac71b692c323b9179e Mon Sep 17 00:00:00 2001 From: pinkneyj Date: Wed, 5 Aug 2026 14:31:31 +0100 Subject: [PATCH 3/4] remove whitespace --- helm/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/helm/README.md b/helm/README.md index 4ea8eaeb1..3f840d032 100644 --- a/helm/README.md +++ b/helm/README.md @@ -6,7 +6,7 @@ A Helm chart for deploying a metrics collector to send cluster metrics to the CloudZero platform. -For the latest release, see [Releases](https://github.com/Cloudzero/cloudzero-charts/releases). You can also [enable release notifications](#enabling-release-notifications). +For the latest release, see [Releases](https://github.com/Cloudzero/cloudzero-charts/releases). You can also [enable release notifications](#enabling-release-notifications). ## Prerequisites From fa1ee1340e75f5a3ce145f2dfd41cad2d847e6bd Mon Sep 17 00:00:00 2001 From: pinkneyj Date: Mon, 24 Aug 2026 15:16:18 +0100 Subject: [PATCH 4/4] update default affinities --- helm/templates/agent-deploy.yaml | 4 +- helm/templates/aggregator-deploy.yaml | 4 +- helm/templates/webhook-deploy.yaml | 18 +---- ..._aggregator_default_antiaffinity_test.yaml | 81 +++++++++++++++++++ helm/values.yaml | 52 +++++++++++- 5 files changed, 132 insertions(+), 27 deletions(-) create mode 100644 helm/tests/server_aggregator_default_antiaffinity_test.yaml diff --git a/helm/templates/agent-deploy.yaml b/helm/templates/agent-deploy.yaml index f748b59ef..59ec7c3ad 100644 --- a/helm/templates/agent-deploy.yaml +++ b/helm/templates/agent-deploy.yaml @@ -347,9 +347,7 @@ spec: {{- include "cloudzero-agent.generateImagePullSecrets" (dict "root" . "image" .Values.components.prometheus.image) | nindent 6 }} {{- include "cloudzero-agent.generateNodeSelector" (dict "default" .Values.defaults.nodeSelector "nodeSelector" .Values.server.nodeSelector) | nindent 6 }} {{- include "cloudzero-agent.generateTolerations" (concat .Values.defaults.tolerations .Values.server.tolerations) | nindent 6 }} - {{- $podAntiAffinity := dict "podAntiAffinity" (dict "preferredDuringSchedulingIgnoredDuringExecution" (list (dict "weight" 100 "podAffinityTerm" (dict "labelSelector" (dict "matchLabels" (dict "app.kubernetes.io/name" "server")) "topologyKey" "kubernetes.io/hostname")))) }} - {{- $userAffinity := deepCopy (.Values.server.affinity | default (dict)) }} - {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" (merge $userAffinity $podAntiAffinity)) | nindent 6 }} + {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" .Values.server.affinity) | nindent 6 }} {{- with .Values.server.topologySpreadConstraints }} topologySpreadConstraints: {{- toYaml . | nindent 8 }} diff --git a/helm/templates/aggregator-deploy.yaml b/helm/templates/aggregator-deploy.yaml index e4411741d..4edf7b430 100644 --- a/helm/templates/aggregator-deploy.yaml +++ b/helm/templates/aggregator-deploy.yaml @@ -177,9 +177,7 @@ spec: {{- include "cloudzero-agent.generateDNSInfo" (dict "defaults" .Values.defaults.dns) | nindent 6 }} {{- include "cloudzero-agent.generateImagePullSecrets" (dict "root" . "image" .Values.components.agent.image) | nindent 6 }} {{- include "cloudzero-agent.generateNodeSelector" (dict "default" .Values.defaults.nodeSelector "nodeSelector" .Values.aggregator.nodeSelector) | nindent 6 }} - {{- $podAntiAffinity := dict "podAntiAffinity" (dict "preferredDuringSchedulingIgnoredDuringExecution" (list (dict "weight" 100 "podAffinityTerm" (dict "labelSelector" (dict "matchLabels" (dict "app.kubernetes.io/name" "aggregator")) "topologyKey" "kubernetes.io/hostname")))) }} - {{- $userAffinity := deepCopy (.Values.aggregator.affinity | default (dict)) }} - {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" (merge $userAffinity $podAntiAffinity)) | nindent 6 }} + {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" .Values.aggregator.affinity) | nindent 6 }} {{- include "cloudzero-agent.generateTolerations" (concat .Values.defaults.tolerations) | nindent 6 }} {{- with .Values.server.topologySpreadConstraints }} diff --git a/helm/templates/webhook-deploy.yaml b/helm/templates/webhook-deploy.yaml index 56a110a4b..6ce5c2dbc 100644 --- a/helm/templates/webhook-deploy.yaml +++ b/helm/templates/webhook-deploy.yaml @@ -103,23 +103,7 @@ spec: (.Values.defaults.securityContext | default (dict)) (.Values.components.webhookServer.securityContext | default (dict)) ) | nindent 6 }} - {{ $podAntiAffinity := dict - "podAntiAffinity" (dict - "preferredDuringSchedulingIgnoredDuringExecution" (list - (dict - "weight" 100 - "podAffinityTerm" (dict - "labelSelector" (dict - "matchLabels" (dict "app.kubernetes.io/name" "webhook-server") - ) - "topologyKey" "kubernetes.io/hostname" - ) - ) - ) - ) - }} - {{- $userAffinity := deepCopy .Values.insightsController.server.affinity }} - {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" (merge $userAffinity $podAntiAffinity)) | nindent 6 }} + {{- include "cloudzero-agent.generateAffinity" (dict "default" .Values.defaults.affinity "affinity" .Values.insightsController.server.affinity) | nindent 6 }} {{- include "cloudzero-agent.generateDNSInfo" (dict "defaults" .Values.defaults.dns) | nindent 6 }} {{- include "cloudzero-agent.generatePriorityClassName" .Values.defaults.priorityClassName | nindent 6 }} {{- include "cloudzero-agent.generateNodeSelector" (dict "default" .Values.defaults.nodeSelector "nodeSelector" .Values.insightsController.server.nodeSelector) | nindent 6 }} diff --git a/helm/tests/server_aggregator_default_antiaffinity_test.yaml b/helm/tests/server_aggregator_default_antiaffinity_test.yaml new file mode 100644 index 000000000..6c3a83077 --- /dev/null +++ b/helm/tests/server_aggregator_default_antiaffinity_test.yaml @@ -0,0 +1,81 @@ +# Regression guard for the default pod anti-affinity now declared directly in +# values.yaml (server.affinity, aggregator.affinity, and +# insightsController.server.affinity) rather than hardcoded in the templates. +# +# Companion to webhook_antiaffinity_selector_test.yaml, which covers the same +# behavior for the webhook server. These assert that, with no user overrides, +# the server and aggregator Deployments render the same soft (preferred), +# weight-100, same-hostname anti-affinity rule scoped to their own +# app.kubernetes.io/name label - and that a user can still fully replace the +# default by overriding affinity. +suite: test default server/aggregator pod anti-affinity +templates: + - templates/agent-deploy.yaml + - templates/aggregator-deploy.yaml +tests: + - it: server should default to a preferred anti-affinity selecting its own pods + template: templates/agent-deploy.yaml + set: + components.agent.mode: clustered + asserts: + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchLabels + value: + app.kubernetes.io/name: server + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].weight + value: 100 + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey + value: kubernetes.io/hostname + + - it: aggregator should default to a preferred anti-affinity selecting its own pods + template: templates/aggregator-deploy.yaml + asserts: + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.labelSelector.matchLabels + value: + app.kubernetes.io/name: aggregator + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].weight + value: 100 + - equal: + path: spec.template.spec.affinity.podAntiAffinity.preferredDuringSchedulingIgnoredDuringExecution[0].podAffinityTerm.topologyKey + value: kubernetes.io/hostname + + - it: users can fully replace the server's default anti-affinity + template: templates/agent-deploy.yaml + set: + components.agent.mode: clustered + server.affinity: + podAntiAffinity: null + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: srv-only-key + operator: Exists + asserts: + - notExists: + path: spec.template.spec.affinity.podAntiAffinity + - equal: + path: spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key + value: srv-only-key + + - it: users can fully replace the aggregator's default anti-affinity + template: templates/aggregator-deploy.yaml + set: + aggregator.affinity: + podAntiAffinity: null + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: agg-only-key + operator: Exists + asserts: + - notExists: + path: spec.template.spec.affinity.podAntiAffinity + - equal: + path: spec.template.spec.affinity.nodeAffinity.requiredDuringSchedulingIgnoredDuringExecution.nodeSelectorTerms[0].matchExpressions[0].key + value: agg-only-key diff --git a/helm/values.yaml b/helm/values.yaml index 8e589a9b8..10020a222 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -1283,11 +1283,25 @@ server: # --Limit the size to 8Gi to lower impact on the cluster, and to provide a reasonable backup for the WAL emptyDir: sizeLimit: 8Gi - # Affinity rules + # Affinity rules for the server pods. + # + # Defaults to a preferred (soft) anti-affinity that spreads server pods + # across different nodes. Override any of these fields to customize the + # behavior, or set podAntiAffinity to null (or affinity to null) to + # remove the default entirely. Note: setting affinity to {} will NOT + # remove it, since Helm re-merges chart defaults into empty maps. # # See the Kubernetes documentation for details: # https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - affinity: {} + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: server + topologyKey: kubernetes.io/hostname # Tolerations configuration for the aggregator pods. # # See the Kubernetes documentation for details: @@ -1508,9 +1522,24 @@ insightsController: tolerations: [] # Affinity rules for the webhook server pods. # + # Defaults to a preferred (soft) anti-affinity that spreads webhook + # server pods across different nodes. Override any of these fields to + # customize the behavior, or set podAntiAffinity to null (or affinity + # to null) to remove the default entirely. Note: setting affinity to + # {} will NOT remove it, since Helm re-merges chart defaults into + # empty maps. + # # See the Kubernetes documentation for details: # https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - affinity: {} + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: webhook-server + topologyKey: kubernetes.io/hostname # Annotations to add to the webhook server Deployment. deploymentAnnotations: {} # Annotations to add to the webhook server pods. @@ -1806,9 +1835,24 @@ aggregator: tolerations: [] # Affinity rules for the aggregator pods. # + # Defaults to a preferred (soft) anti-affinity that spreads aggregator + # pods across different nodes. Override any of these fields to + # customize the behavior, or set podAntiAffinity to null (or affinity + # to null) to remove the default entirely. Note: setting affinity to + # {} will NOT remove it, since Helm re-merges chart defaults into + # empty maps. + # # See the Kubernetes documentation for details: # https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity - affinity: {} + affinity: + podAntiAffinity: + preferredDuringSchedulingIgnoredDuringExecution: + - weight: 100 + podAffinityTerm: + labelSelector: + matchLabels: + app.kubernetes.io/name: aggregator + topologyKey: kubernetes.io/hostname # -- Deprecated. Override the name of the chart. Used in resource naming. nameOverride: