You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@fluss.apache.org by ip...@apache.org on 2026/04/23 17:04:35 UTC

(fluss) branch release-0.9 updated: [helm] Add pod annotations, labels, and pod disruption budget support (#3114) (#3185)

This is an automated email from the ASF dual-hosted git repository.

polyzos pushed a commit to branch release-0.9
in repository https://gitbox.apache.org/repos/asf/fluss.git


The following commit(s) were added to refs/heads/release-0.9 by this push:
     new a96d9e61b [helm] Add pod annotations, labels, and pod disruption budget support (#3114) (#3185)
a96d9e61b is described below

commit a96d9e61ba538338855b51ce4f8eb0443d3119cb
Author: Muhammet Orazov <91...@users.noreply.github.com>
AuthorDate: Thu Apr 23 19:04:30 2026 +0200

    [helm] Add pod annotations, labels, and pod disruption budget support (#3114) (#3185)
    
    * [helm] Add pod annotations, labels, and pod disruption budget support
    
    * address feedback
    
    (cherry picked from commit 845ced63e9410d3346d189f52b531649f18a7325)
    
    Co-authored-by: Anton Borisov <14...@users.noreply.github.com>
---
 helm/templates/NOTES.txt                           |   1 +
 helm/templates/_helpers.tpl                        |  31 +++
 helm/templates/{NOTES.txt => pdb-coordinator.yaml} |  25 +-
 helm/templates/{NOTES.txt => pdb-tablet.yaml}      |  25 +-
 helm/templates/sts-coordinator.yaml                |   7 +
 helm/templates/sts-tablet.yaml                     |   7 +
 helm/tests/pod_metadata_and_pdb_test.yaml          | 285 +++++++++++++++++++++
 helm/values.yaml                                   |  12 +
 website/docs/install-deploy/deploying-with-helm.md |  10 +
 9 files changed, 391 insertions(+), 12 deletions(-)

diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt
index 7a2dfd2dd..e47360e6c 100644
--- a/helm/templates/NOTES.txt
+++ b/helm/templates/NOTES.txt
@@ -22,3 +22,4 @@ APP VERSION: {{ .Chart.AppVersion }}
 
 {{ include "fluss.security.validateValues" . }}
 {{ include "fluss.metrics.validateValues" . }}
+{{ include "fluss.pdb.validateValues" . }}
diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl
index 5fe371e0c..3933debca 100644
--- a/helm/templates/_helpers.tpl
+++ b/helm/templates/_helpers.tpl
@@ -100,3 +100,34 @@ imagePullSecrets:
 {{- end }}
 {{- end }}
 
+{{/*
+  Validate PodDisruptionBudget for a given component.
+  Usage: include "fluss.pdb.validate" (dict "component" "tablet" "pdb" .Values.tablet.podDisruptionBudget)
+*/}}
+{{- define "fluss.pdb.validate" -}}
+{{- if .pdb.enabled -}}
+  {{- $hasMin := hasKey .pdb "minAvailable" -}}
+  {{- $hasMax := hasKey .pdb "maxUnavailable" -}}
+  {{- if and $hasMin $hasMax -}}
+    {{- printf "%s.podDisruptionBudget: cannot set both minAvailable and maxUnavailable" .component -}}
+  {{- else if not (or $hasMin $hasMax) -}}
+    {{- printf "%s.podDisruptionBudget: must set either minAvailable or maxUnavailable when enabled" .component -}}
+  {{- end -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+  Aggregate PDB validation for all components.
+  include "fluss.pdb.validateValues" .
+*/}}
+{{- define "fluss.pdb.validateValues" -}}
+{{- $errMessages := list -}}
+{{- $errMessages = append $errMessages (include "fluss.pdb.validate" (dict "component" "tablet" "pdb" .Values.tablet.podDisruptionBudget)) -}}
+{{- $errMessages = append $errMessages (include "fluss.pdb.validate" (dict "component" "coordinator" "pdb" .Values.coordinator.podDisruptionBudget)) -}}
+{{- $errMessages = without $errMessages "" -}}
+{{- $errMessage := join "\n" $errMessages -}}
+{{- if $errMessage -}}
+{{-   printf "\nPDB VALIDATION:\n%s" $errMessage | fail -}}
+{{- end -}}
+{{- end -}}
+
diff --git a/helm/templates/NOTES.txt b/helm/templates/pdb-coordinator.yaml
similarity index 53%
copy from helm/templates/NOTES.txt
copy to helm/templates/pdb-coordinator.yaml
index 7a2dfd2dd..79e03f345 100644
--- a/helm/templates/NOTES.txt
+++ b/helm/templates/pdb-coordinator.yaml
@@ -16,9 +16,22 @@
 # limitations under the License.
 #
 
-CHART NAME: {{ .Chart.Name }}
-CHART VERSION: {{ .Chart.Version }}
-APP VERSION: {{ .Chart.AppVersion }}
-
-{{ include "fluss.security.validateValues" . }}
-{{ include "fluss.metrics.validateValues" . }}
+{{- if .Values.coordinator.podDisruptionBudget.enabled }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: coordinator-server
+  labels:
+  {{- include "fluss.labels" . | nindent 4 }}
+spec:
+  {{- if hasKey .Values.coordinator.podDisruptionBudget "minAvailable" }}
+  minAvailable: {{ .Values.coordinator.podDisruptionBudget.minAvailable }}
+  {{- end }}
+  {{- if hasKey .Values.coordinator.podDisruptionBudget "maxUnavailable" }}
+  maxUnavailable: {{ .Values.coordinator.podDisruptionBudget.maxUnavailable }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "fluss.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/component: coordinator
+{{- end }}
diff --git a/helm/templates/NOTES.txt b/helm/templates/pdb-tablet.yaml
similarity index 55%
copy from helm/templates/NOTES.txt
copy to helm/templates/pdb-tablet.yaml
index 7a2dfd2dd..ce7641efd 100644
--- a/helm/templates/NOTES.txt
+++ b/helm/templates/pdb-tablet.yaml
@@ -16,9 +16,22 @@
 # limitations under the License.
 #
 
-CHART NAME: {{ .Chart.Name }}
-CHART VERSION: {{ .Chart.Version }}
-APP VERSION: {{ .Chart.AppVersion }}
-
-{{ include "fluss.security.validateValues" . }}
-{{ include "fluss.metrics.validateValues" . }}
+{{- if .Values.tablet.podDisruptionBudget.enabled }}
+apiVersion: policy/v1
+kind: PodDisruptionBudget
+metadata:
+  name: tablet-server
+  labels:
+  {{- include "fluss.labels" . | nindent 4 }}
+spec:
+  {{- if hasKey .Values.tablet.podDisruptionBudget "minAvailable" }}
+  minAvailable: {{ .Values.tablet.podDisruptionBudget.minAvailable }}
+  {{- end }}
+  {{- if hasKey .Values.tablet.podDisruptionBudget "maxUnavailable" }}
+  maxUnavailable: {{ .Values.tablet.podDisruptionBudget.maxUnavailable }}
+  {{- end }}
+  selector:
+    matchLabels:
+      {{- include "fluss.selectorLabels" . | nindent 6 }}
+      app.kubernetes.io/component: tablet
+{{- end }}
diff --git a/helm/templates/sts-coordinator.yaml b/helm/templates/sts-coordinator.yaml
index fbdd36712..1f5d046a0 100644
--- a/helm/templates/sts-coordinator.yaml
+++ b/helm/templates/sts-coordinator.yaml
@@ -32,8 +32,15 @@ spec:
   template:
     metadata:
       labels:
+        {{- with .Values.coordinator.podLabels }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
         {{- include "fluss.selectorLabels" . | nindent 8 }}
         app.kubernetes.io/component: coordinator
+      {{- with .Values.coordinator.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
     spec:
       {{- if .Values.serviceAccount.create }}
       serviceAccountName: {{ .Values.serviceAccount.name | default (include "fluss.fullname" .) }}
diff --git a/helm/templates/sts-tablet.yaml b/helm/templates/sts-tablet.yaml
index bb8be8b57..94710561e 100644
--- a/helm/templates/sts-tablet.yaml
+++ b/helm/templates/sts-tablet.yaml
@@ -32,8 +32,15 @@ spec:
   template:
     metadata:
       labels:
+        {{- with .Values.tablet.podLabels }}
+        {{- toYaml . | nindent 8 }}
+        {{- end }}
         {{- include "fluss.selectorLabels" . | nindent 8 }}
         app.kubernetes.io/component: tablet
+      {{- with .Values.tablet.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
     spec:
       {{- if .Values.serviceAccount.create }}
       serviceAccountName: {{ .Values.serviceAccount.name | default (include "fluss.fullname" .) }}
diff --git a/helm/tests/pod_metadata_and_pdb_test.yaml b/helm/tests/pod_metadata_and_pdb_test.yaml
new file mode 100644
index 000000000..53527568f
--- /dev/null
+++ b/helm/tests/pod_metadata_and_pdb_test.yaml
@@ -0,0 +1,285 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+suite: pod-metadata-defaults
+templates:
+  - templates/sts-tablet.yaml
+  - templates/sts-coordinator.yaml
+
+tests:
+  - it: should not render pod annotations by default on tablet
+    asserts:
+      - isNull:
+          path: spec.template.metadata.annotations
+        template: templates/sts-tablet.yaml
+
+  - it: should not render pod annotations by default on coordinator
+    asserts:
+      - isNull:
+          path: spec.template.metadata.annotations
+        template: templates/sts-coordinator.yaml
+
+---
+
+suite: tablet-pod-annotations
+templates:
+  - templates/sts-tablet.yaml
+
+tests:
+  - it: should render pod annotations on tablet
+    set:
+      tablet.podAnnotations:
+        prometheus.io/scrape: "true"
+        prometheus.io/port: "9249"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations
+          value:
+            prometheus.io/scrape: "true"
+            prometheus.io/port: "9249"
+
+  - it: should not apply coordinator annotations to tablet
+    set:
+      coordinator.podAnnotations:
+        prometheus.io/scrape: "true"
+    asserts:
+      - isNull:
+          path: spec.template.metadata.annotations
+
+---
+
+suite: coordinator-pod-annotations
+templates:
+  - templates/sts-coordinator.yaml
+
+tests:
+  - it: should render pod annotations on coordinator
+    set:
+      coordinator.podAnnotations:
+        prometheus.io/scrape: "true"
+    asserts:
+      - equal:
+          path: spec.template.metadata.annotations
+          value:
+            prometheus.io/scrape: "true"
+
+---
+
+suite: tablet-pod-labels
+templates:
+  - templates/sts-tablet.yaml
+
+tests:
+  - it: should render custom pod labels on tablet
+    set:
+      tablet.podLabels:
+        team: data-platform
+        env: production
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.team
+          value: data-platform
+      - equal:
+          path: spec.template.metadata.labels.env
+          value: production
+
+  - it: should preserve built-in labels when custom labels are added
+    set:
+      tablet.podLabels:
+        custom: label
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels["app.kubernetes.io/component"]
+          value: tablet
+      - equal:
+          path: spec.template.metadata.labels.custom
+          value: label
+
+---
+
+suite: coordinator-pod-labels
+templates:
+  - templates/sts-coordinator.yaml
+
+tests:
+  - it: should render custom pod labels on coordinator
+    set:
+      coordinator.podLabels:
+        team: data-platform
+    asserts:
+      - equal:
+          path: spec.template.metadata.labels.team
+          value: data-platform
+
+---
+
+suite: pdb-defaults
+templates:
+  - templates/pdb-tablet.yaml
+  - templates/pdb-coordinator.yaml
+
+tests:
+  - it: should not render tablet PDB by default
+    asserts:
+      - hasDocuments:
+          count: 0
+        template: templates/pdb-tablet.yaml
+
+  - it: should not render coordinator PDB by default
+    asserts:
+      - hasDocuments:
+          count: 0
+        template: templates/pdb-coordinator.yaml
+
+---
+
+suite: tablet-pdb
+templates:
+  - templates/pdb-tablet.yaml
+
+tests:
+  - it: should render tablet PDB with minAvailable
+    set:
+      tablet.podDisruptionBudget:
+        enabled: true
+        minAvailable: 2
+    asserts:
+      - hasDocuments:
+          count: 1
+      - equal:
+          path: kind
+          value: PodDisruptionBudget
+      - equal:
+          path: metadata.name
+          value: tablet-server
+      - equal:
+          path: spec.minAvailable
+          value: 2
+      - equal:
+          path: spec.selector.matchLabels["app.kubernetes.io/component"]
+          value: tablet
+
+  - it: should render tablet PDB with maxUnavailable
+    set:
+      tablet.podDisruptionBudget:
+        enabled: true
+        maxUnavailable: 1
+    asserts:
+      - equal:
+          path: spec.maxUnavailable
+          value: 1
+      - isNull:
+          path: spec.minAvailable
+
+---
+
+suite: coordinator-pdb
+templates:
+  - templates/pdb-coordinator.yaml
+
+tests:
+  - it: should render coordinator PDB with minAvailable
+    set:
+      coordinator.podDisruptionBudget:
+        enabled: true
+        minAvailable: 1
+    asserts:
+      - hasDocuments:
+          count: 1
+      - equal:
+          path: kind
+          value: PodDisruptionBudget
+      - equal:
+          path: metadata.name
+          value: coordinator-server
+      - equal:
+          path: spec.minAvailable
+          value: 1
+      - equal:
+          path: spec.selector.matchLabels["app.kubernetes.io/component"]
+          value: coordinator
+
+---
+
+suite: pdb-validation
+templates:
+  - templates/NOTES.txt
+
+tests:
+  - it: should fail when both minAvailable and maxUnavailable are set on tablet
+    set:
+      tablet.podDisruptionBudget:
+        enabled: true
+        minAvailable: 2
+        maxUnavailable: 1
+    asserts:
+      - failedTemplate:
+          errorPattern: "cannot set both minAvailable and maxUnavailable"
+
+  - it: should fail when neither minAvailable nor maxUnavailable is set on tablet
+    set:
+      tablet.podDisruptionBudget:
+        enabled: true
+    asserts:
+      - failedTemplate:
+          errorPattern: "must set either minAvailable or maxUnavailable when enabled"
+
+  - it: should fail when both minAvailable and maxUnavailable are set on coordinator
+    set:
+      coordinator.podDisruptionBudget:
+        enabled: true
+        minAvailable: 1
+        maxUnavailable: 1
+    asserts:
+      - failedTemplate:
+          errorPattern: "cannot set both minAvailable and maxUnavailable"
+
+  - it: should fail when neither minAvailable nor maxUnavailable is set on coordinator
+    set:
+      coordinator.podDisruptionBudget:
+        enabled: true
+    asserts:
+      - failedTemplate:
+          errorPattern: "must set either minAvailable or maxUnavailable when enabled"
+
+---
+
+suite: pdb-zero-values
+templates:
+  - templates/pdb-tablet.yaml
+
+tests:
+  - it: should render tablet PDB with minAvailable set to zero
+    set:
+      tablet.podDisruptionBudget:
+        enabled: true
+        minAvailable: 0
+    asserts:
+      - equal:
+          path: spec.minAvailable
+          value: 0
+
+  - it: should render tablet PDB with maxUnavailable set to zero
+    set:
+      tablet.podDisruptionBudget:
+        enabled: true
+        maxUnavailable: 0
+    asserts:
+      - equal:
+          path: spec.maxUnavailable
+          value: 0
diff --git a/helm/values.yaml b/helm/values.yaml
index bf9f3022e..082b22b26 100644
--- a/helm/values.yaml
+++ b/helm/values.yaml
@@ -46,6 +46,12 @@ tablet:
   extraVolumes: []
   extraVolumeMounts: []
   initContainers: []
+  podAnnotations: {}
+  podLabels: {}
+  podDisruptionBudget:
+    enabled: false
+    # minAvailable: 1
+    # maxUnavailable: 1
   # Pod scheduling configuration
   affinity: {}
   # Example: spread tablet server pods across availability zones and nodes.
@@ -81,6 +87,12 @@ coordinator:
   extraVolumes: []
   extraVolumeMounts: []
   initContainers: []
+  podAnnotations: {}
+  podLabels: {}
+  podDisruptionBudget:
+    enabled: false
+    # minAvailable: 1
+    # maxUnavailable: 1
   affinity: {}
   nodeSelector: {}
   tolerations: []
diff --git a/website/docs/install-deploy/deploying-with-helm.md b/website/docs/install-deploy/deploying-with-helm.md
index 270c366df..f38a56299 100644
--- a/website/docs/install-deploy/deploying-with-helm.md
+++ b/website/docs/install-deploy/deploying-with-helm.md
@@ -284,9 +284,19 @@ It is recommended to set these explicitly in production.
 | `coordinator.extraVolumes` | Extra volumes to add to the CoordinatorServer pod spec | `[]` |
 | `coordinator.extraVolumeMounts` | Extra volume mounts to add to the coordinator container | `[]` |
 | `coordinator.initContainers` | Init containers to run before the coordinator container starts | `[]` |
+| `coordinator.podAnnotations` | Annotations to add to CoordinatorServer pods | `{}` |
+| `coordinator.podLabels` | Additional labels to add to CoordinatorServer pods | `{}` |
+| `coordinator.podDisruptionBudget.enabled` | Enable PodDisruptionBudget for CoordinatorServer | `false` |
+| `coordinator.podDisruptionBudget.minAvailable` | Minimum available coordinator pods during disruption | Not set |
+| `coordinator.podDisruptionBudget.maxUnavailable` | Maximum unavailable coordinator pods during disruption | Not set |
 | `tablet.extraVolumes` | Extra volumes to add to TabletServer pod specs | `[]` |
 | `tablet.extraVolumeMounts` | Extra volume mounts to add to the tablet container | `[]` |
 | `tablet.initContainers` | Init containers to run before the tablet container starts | `[]` |
+| `tablet.podAnnotations` | Annotations to add to TabletServer pods | `{}` |
+| `tablet.podLabels` | Additional labels to add to TabletServer pods | `{}` |
+| `tablet.podDisruptionBudget.enabled` | Enable PodDisruptionBudget for TabletServer | `false` |
+| `tablet.podDisruptionBudget.minAvailable` | Minimum available tablet server pods during disruption | Not set |
+| `tablet.podDisruptionBudget.maxUnavailable` | Maximum unavailable tablet server pods during disruption | Not set |
 
 ## Advanced Configuration