Skip to content

feat(helm): make gateway chart pod/service metadata and scheduling configurable#2181

Open
renuka-fernando wants to merge 2 commits into
wso2:mainfrom
renuka-fernando:gw-helm-improvements
Open

feat(helm): make gateway chart pod/service metadata and scheduling configurable#2181
renuka-fernando wants to merge 2 commits into
wso2:mainfrom
renuka-fernando:gw-helm-improvements

Conversation

@renuka-fernando

Copy link
Copy Markdown
Contributor

Purpose

The gateway-helm-chart did not expose several pod-, service-, and resource-level customization knobs that customer setups commonly require, and it had two correctness bugs in how labels and annotations were rendered. This PR adds the missing configuration and fixes the rendering bugs.

Approach

Bugs fixed

  • Duplicate label keys: setting the same key in commonLabels and a component's deployment.labels/podLabels rendered duplicate YAML map keys (rejected by strict parsers and GitOps tools like ArgoCD/kubeconform). Labels are now merged with a clear precedence instead of appended.
  • Inconsistent annotation precedence: per-resource annotations now win over commonAnnotations consistently at both resource and pod level (previously commonAnnotations silently won at resource level).

New configuration support (controller + gateway-runtime)

  • topologySpreadConstraints, deployment strategy, terminationGracePeriodSeconds, hostAliases, dnsPolicy/dnsConfig, and pod-level automountServiceAccountToken.
  • Optional startupProbe (controller template had no support; runtime value was undocumented).
  • Service tunables: clusterIP, externalTrafficPolicy, loadBalancerClass, loadBalancerSourceRanges, ipFamilyPolicy/ipFamilies, and static nodePorts.* (type-gated so they only render on capable Service types).
  • app.kubernetes.io/name added to the standard label set.
  • PVC labels/annotations (e.g. helm.sh/resource-policy: keep).
  • commonLabels/commonAnnotations now applied to every resource the chart renders (ServiceAccount, HPAs, PDBs, PVC, Certificate, Issuer, and the ConfigMaps were previously missed), with per-resource values winning on key conflicts.

Out of scope: extraContainers/sidecar injection on the gateway-runtime pod (tracked separately in #2180-adjacent work).

Validation

All validation done with helm lint + helm template (default values, values-local.yaml, and a conflict-heavy values file).

Check Result
helm lint (dev-mode + values-local) ✅ 0 failures
Render vs main baseline (default values) ✅ Only expected diffs: added app.kubernetes.io/name label, alphabetical label ordering, SA automountServiceAccountToken: true
Deployment spec.selector + pod-label content vs baseline ✅ Unchanged → helm upgrade safe, no immutable-selector error
Duplicate label/annotation keys (conflict-heavy values) ✅ Zero duplicates (previously rendered duplicate YAML keys)
Label/annotation precedence ✅ Specific > commonLabels/commonAnnotations > standard, everywhere
Selector-label protection podLabels: {app.kubernetes.io/name: evil} cannot override selector labels
checksum/config pod annotation ✅ Exactly one per pod (sha); user-injected values via common/podAnnotations are dropped
commonAnnotations coverage ✅ All 14 rendered resources (was: only Deployments/Services/main ConfigMap)
Value coercion num: 123 / flag: true render as "123" / "true"
Service tunables type-gating ✅ Rendered on LoadBalancer/NodePort; correctly absent on ClusterIP even when set
New pod knobs (strategy, topologySpread, TGPS, hostAliases, DNS, automount, startupProbe) ✅ All render
PVC labels/annotations (helm.sh/resource-policy: keep) ✅ Renders
Null-safety (nodePorts: null) ✅ Renders
Sample input (conflict-heavy values used for validation)
commonLabels:
  team: core
  conflict: common            # overridden per-resource below
  num: 123                    # coercion check
  flag: true
commonAnnotations:
  owner: common               # overridden per-resource below
  checksum/config: evil       # must not displace the real pod checksum
gateway:
  controller:
    persistence:
      labels: { pvc-label: yes-label }
      annotations: { helm.sh/resource-policy: keep }
    deployment:
      labels: { conflict: deployment }
      annotations: { owner: ctrl-deploy }
      podLabels:
        conflict: pod
        app.kubernetes.io/name: evil   # must NOT override selector label
      podAnnotations: { owner: ctrl-pod, checksum/config: evil-pod }
      strategy: { type: Recreate }
      terminationGracePeriodSeconds: 45
      dnsPolicy: "None"
      dnsConfig: { nameservers: ["1.1.1.1"] }
      automountServiceAccountToken: false
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: ScheduleAnyway
          labelSelector:
            matchLabels: { app.kubernetes.io/component: controller }
      startupProbe:
        httpGet: { path: /api/admin/v0.9/health, port: admin }
  gatewayRuntime:
    service:
      type: LoadBalancer
      externalTrafficPolicy: Local
      loadBalancerClass: service.k8s.aws/nlb
      loadBalancerSourceRanges: ["10.0.0.0/8"]
      ipFamilyPolicy: SingleStack
      ipFamilies: ["IPv4"]
      nodePorts: { http: "30080", https: "30443" }
Sample output (rendered artifacts)

Controller Deployment — merged labels (no duplicates, specific wins, values coerced), app.kubernetes.io/name added, pod checksum protected:

metadata:
  name: gw-gateway-controller
  labels:
    app.kubernetes.io/component: controller
    app.kubernetes.io/name: gateway        # new standard label
    conflict: deployment                   # deployment.labels won over commonLabels
    flag: "true"                           # coerced to string
    num: "123"
    team: core
  annotations:
    owner: ctrl-deploy                     # deployment.annotations won over commonAnnotations
spec:
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app.kubernetes.io/name: gateway    # selector label won over podLabels "evil"
        conflict: pod                      # podLabels won over commonLabels
      annotations:
        checksum/config: b78c78cf…         # real sha — injected "evil" values dropped
        owner: ctrl-pod

Gateway-runtime Service (LoadBalancer) — commonLabels/commonAnnotations applied + new network tunables:

metadata:
  name: gw-gateway-gateway-runtime
  labels:
    app.kubernetes.io/component: gateway-runtime
    app.kubernetes.io/name: gateway
    team: core                       # from commonLabels
    conflict: common
    flag: "true"
    num: "123"
  annotations:
    owner: common                    # from commonAnnotations
spec:
  type: LoadBalancer
  externalTrafficPolicy: Local
  loadBalancerClass: service.k8s.aws/nlb
  loadBalancerSourceRanges:
    - 10.0.0.0/8
  ipFamilyPolicy: SingleStack
  ipFamilies:
    - IPv4
  ports:
    - { name: http, port: 8080, targetPort: http, nodePort: 30080 }
    - { name: https, port: 8443, targetPort: https, nodePort: 30443 }

PVC — commonLabels/commonAnnotations + own labels/annotations:

metadata:
  name: gw-gateway-controller-data
  labels:
    app.kubernetes.io/component: controller
    team: core                       # from commonLabels
    conflict: common
    pvc-label: yes-label             # from persistence.labels
  annotations:
    owner: common                    # from commonAnnotations
    helm.sh/resource-policy: keep    # from persistence.annotations

ServiceAccount — commonLabels applied, commonAnnotations applied (specific wins) + automount knob:

metadata:
  name: gw-gateway
  labels:
    app.kubernetes.io/name: gateway
    team: core                       # from commonLabels
    conflict: common
  annotations:
    owner: sa-specific               # serviceAccount.annotations won over commonAnnotations "owner: common"
automountServiceAccountToken: true

Related Issues

Related #2179

Remarks

Behavior change for reviewers: resource-level annotation precedence flipped — per-resource annotations now win over commonAnnotations on key conflicts (previously commonAnnotations silently won). Pod-level behavior is unchanged.

Checklist

  • Tests added or updated (unit, integration, etc.)
  • Samples updated (if applicable)

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: d20cc3d0-c698-4f10-b4a4-384c663f7b64

📥 Commits

Reviewing files that changed from the base of the PR and between cb0b40a and a03137d.

📒 Files selected for processing (17)
  • kubernetes/helm/gateway-helm-chart/README.md
  • kubernetes/helm/gateway-helm-chart/templates/_helpers.tpl
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/certificate.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/deployment.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/hpa.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/issuer.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/pdb.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/pvc.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-config.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/deployment.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/hpa.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/llm-pricing-configmap.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/pdb.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/serviceaccount.yaml
  • kubernetes/helm/gateway-helm-chart/values.yaml
✅ Files skipped from review due to trivial changes (1)
  • kubernetes/helm/gateway-helm-chart/README.md
🚧 Files skipped from review as they are similar to previous changes (12)
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/llm-pricing-configmap.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/certificate.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/hpa.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/pvc.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/pdb.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/hpa.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/deployment.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/issuer.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-config.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/deployment.yaml
  • kubernetes/helm/gateway-helm-chart/values.yaml

📝 Walkthrough

Overview

This PR enhances the gateway Helm chart by making pod-, service-, and resource-level metadata and scheduling/resource knobs configurable. It also fixes Helm rendering correctness issues for labels and annotations by centralizing string-map rendering and enforcing consistent merge/precedence rules across resources.

Bug Fixes

  • Label deduplication & precedence: Eliminated duplicate YAML label keys when the same key appeared in commonLabels and component-specific deployment.labels/podLabels. Label merging is now deterministic, with clear precedence to avoid invalid/duplicated output.
  • Annotation precedence: Standardized annotation merging so that per-resource annotations and pod/deployment-level annotations resolve consistently against commonAnnotations, eliminating inconsistent override behavior across resource types.

New Helm Chart Configuration

Pod/Deployment scheduling & runtime knobs

Added support for:

  • topologySpreadConstraints
  • deployment.strategy
  • terminationGracePeriodSeconds
  • hostAliases
  • dnsPolicy / dnsConfig
  • automountServiceAccountToken (pod-level)
  • optional startupProbe

Service tunables

Extended controller and gateway-runtime Services with configurable networking/load-balancing fields, including:

  • clusterIP
  • externalTrafficPolicy
  • loadBalancerClass
  • loadBalancerSourceRanges
  • ipFamilyPolicy / ipFamilies
  • static per-port nodePorts, rendered only for compatible Service types (e.g., NodePort/LoadBalancer as gated by the chart)

Metadata behavior applied broadly

  • Added app.kubernetes.io/name to the chart’s standard labels.
  • Supports commonLabels / commonAnnotations applied across rendered resources (e.g., ServiceAccount, HPAs, PDBs, PVCs, Certificate/Issuer, ConfigMaps), with per-resource values winning on key conflicts according to the chart’s precedence rules.
  • Ensures selector labels aren’t overridden by component podLabels.

Implementation Changes

  • Refactored _helpers.tpl label/annotation rendering via new helpers:
    • gateway-operator.renderStringMap (string coercion for map values and consistent YAML emission)
    • gateway-operator.labels, resourceLabels, componentLabels, componentPodLabels, and annotations to enforce precedence and avoid duplicate keys.
  • Updated templates for controller and gateway-runtime resources to use the shared helpers for consistent label/annotation rendering.
  • Ensured pod config checksum annotations are rendered consistently and avoids emitting multiple/incorrect checksum entries per pod.

Validation

Chart rendering was validated with helm lint and helm template across multiple value sets (including conflict-heavy scenarios), confirming:

  • no duplicate YAML label keys
  • preserved selector behavior
  • consistent annotation precedence
  • correct rendering of the newly introduced configuration knobs
  • appropriate gating for Service nodePort rendering by Service type

Files Modified

  • kubernetes/helm/gateway-helm-chart/README.md
  • kubernetes/helm/gateway-helm-chart/templates/_helpers.tpl
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/
    • certificate.yaml, deployment.yaml, hpa.yaml, issuer.yaml, pdb.yaml, pvc.yaml, service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-config.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/
    • deployment.yaml, hpa.yaml, llm-pricing-configmap.yaml, pdb.yaml, service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/serviceaccount.yaml
  • kubernetes/helm/gateway-helm-chart/values.yaml

Walkthrough

This pull request enhances the API Gateway Helm chart with a standardized metadata rendering system and expanded Kubernetes resource configuration options. Core helper templates (renderStringMap, labels, resourceLabels, componentLabels, componentPodLabels, annotations) are introduced to handle consistent label and annotation rendering across resources. These helpers are applied across controller and gateway-runtime manifests, replacing inline merge-and-render logic. The chart values are extended to expose additional Kubernetes configuration (NodePort assignments, LoadBalancer settings, IP family policies, pod scheduling/DNS/hostAliases, automountServiceAccountToken, optional startupProbes, and PVC labels/annotations). README updates document the new configuration and metadata override behavior.

Suggested reviewers

  • RakhithaRR
  • Tharsanan1
  • VirajSalaka
  • PasanT9
  • Krishanx92
  • HeshanSudarshana
  • HiranyaKavishani
  • pubudu538
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the primary change: adding configurability for pod/service metadata and scheduling in the Helm chart.
Description check ✅ Passed The description is comprehensive, addressing purpose, approach, bugs fixed, new features, and validation results, though it deviates from the template structure.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@kubernetes/helm/gateway-helm-chart/README.md`:
- Line 129: The README incorrectly references the ConfigMap values path as
gateway.controller.configMap; update the documentation to use the actual values
key gateway.configMap so user overrides are applied (leave the reference to
gateway.controller.persistence as-is for PVCs), i.e., replace occurrences of
gateway.controller.configMap with gateway.configMap in the README content.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b545aa1d-d5c1-4915-8cf4-23d120c50560

📥 Commits

Reviewing files that changed from the base of the PR and between e8c551c and bb634f7.

📒 Files selected for processing (17)
  • kubernetes/helm/gateway-helm-chart/README.md
  • kubernetes/helm/gateway-helm-chart/templates/_helpers.tpl
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/certificate.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/deployment.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/hpa.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/issuer.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/pdb.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/pvc.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/controller/service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-config.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/deployment.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/hpa.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/llm-pricing-configmap.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/pdb.yaml
  • kubernetes/helm/gateway-helm-chart/templates/gateway/gateway-runtime/service.yaml
  • kubernetes/helm/gateway-helm-chart/templates/serviceaccount.yaml
  • kubernetes/helm/gateway-helm-chart/values.yaml

Comment thread kubernetes/helm/gateway-helm-chart/README.md Outdated
…nfigurable

Add pod-, service-, and resource-level customization knobs to the
gateway-helm-chart and fix two label/annotation rendering bugs.

Bugs fixed:
- Duplicate label keys when the same key appears in commonLabels and a
  component's deployment.labels/podLabels (rejected by strict parsers and
  GitOps tools). Labels are now merged with a clear precedence.
- Inconsistent annotation precedence: per-resource annotations now win over
  commonAnnotations consistently at both resource and pod level.

New configuration (controller + gateway-runtime):
- topologySpreadConstraints, deployment strategy, terminationGracePeriodSeconds,
  hostAliases, dnsPolicy/dnsConfig, pod-level automountServiceAccountToken
- optional startupProbe (controller template + documented runtime value)
- service tunables: clusterIP, externalTrafficPolicy, loadBalancerClass,
  loadBalancerSourceRanges, ipFamilyPolicy/ipFamilies, static nodePorts
  (type-gated to capable Service types)
- app.kubernetes.io/name added to the standard label set
- PVC labels/annotations (e.g. helm.sh/resource-policy: keep)
- commonLabels/commonAnnotations now applied to every rendered resource
  (ServiceAccount, HPAs, PDBs, PVC, Certificate, Issuer, ConfigMaps)

Validated with helm lint + helm template (default, values-local, and a
conflict-heavy values file): no duplicate keys, correct precedence, selector
labels protected from override, type-gated service fields, value coercion.
The Configuration section referenced gateway.controller.configMap, but the
values key is gateway.configMap (sibling of gateway.controller). Using the
documented path would not apply user overrides.
@renuka-fernando renuka-fernando force-pushed the gw-helm-improvements branch 2 times, most recently from cb0b40a to a03137d Compare June 14, 2026 05:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant