Skip to content

statefulset.extraVolumeMounts is applied to sidecar but not to redpanda container in v1alpha2 Redpanda CR #1461

@alladinattar

Description

@alladinattar

Summary

When creating a cluster.redpanda.com/v1alpha2 Redpanda resource and setting spec.clusterSpec.statefulset.extraVolumes plus spec.clusterSpec.statefulset.extraVolumeMounts, the extra volume is added to the generated StatefulSet, and the extra volumeMount is added to the sidecar container, but not to the main redpanda container.

Based on the conversion code, statefulset.extraVolumeMounts appears intended to apply to both containers.

Version

Observed with:

  • Redpanda Operator: v26.1.2
  • Redpanda image: v26.1.4

Reproduction

Apply a Redpanda CR like this:

apiVersion: cluster.redpanda.com/v1alpha2
kind: Redpanda
metadata:
  name: redpanda
spec:
  clusterSpec:
    statefulset:
      extraVolumes: |-
        - name: redpanda-io-config
          configMap:
            name: redpanda-io-config
      extraVolumeMounts: |-
        - name: redpanda-io-config
          subPath: io-config.yaml
          mountPath: /etc/redpanda-io-config/io-config.yaml
      additionalRedpandaCmdFlags:
        - "--io-properties-file=/etc/redpanda-io-config/io-config.yaml"

Expected behavior

The generated StatefulSet should contain:

  • the extra volume in .spec.template.spec.volumes
  • the extra volumeMount in both:
    • .spec.template.spec.containers[name=redpanda].volumeMounts
    • .spec.template.spec.containers[name=sidecar].volumeMounts

Actual behavior

In the generated StatefulSet:

  • the extra volume is present
  • the extra volumeMount is present only in the sidecar container
  • the extra volumeMount is missing from the redpanda container

Relevant excerpt from the generated StatefulSet:

spec:
  template:
    spec:
      containers:
      - name: redpanda
        volumeMounts:
        - mountPath: /etc/redpanda
          name: config
        - mountPath: /tmp/base-config
          name: base-config
        - mountPath: /var/lifecycle
          name: lifecycle-scripts
        - mountPath: /var/lib/redpanda/data
          name: datadir
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: kube-api-access
          readOnly: true
      - name: sidecar
        volumeMounts:
        - mountPath: /etc/redpanda
          name: config
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: kube-api-access
          readOnly: true
        - mountPath: /etc/redpanda-io-config/io-config.yaml
          name: redpanda-io-config
          subPath: io-config.yaml
      volumes:
      - name: redpanda-io-config
        configMap:
          name: redpanda-io-config

Suspected cause

This looks like a bug in pod template merge logic rather than in CR conversion.

statefulset.extraVolumeMounts is first converted into statefulset.podTemplate.spec.containers[*].volumeMounts, but later the chart's strategic merge logic merges VolumeMounts by name:

func mergeContainer(original corev1.Container, override applycorev1.ContainerApplyConfiguration) corev1.Container {
	merged := helmette.MergeTo[corev1.Container](override, original)
	merged.Env = mergeSliceBy(original.Env, override.Env, "name", mergeEnvVar)
	merged.VolumeMounts = mergeSliceBy(original.VolumeMounts, override.VolumeMounts, "name", mergeVolumeMount)
	return merged
}

For VolumeMount, name is not a safe merge key because the same volume can legitimately be mounted multiple times with different mountPath/subPath. Using mountPath as the merge key seems more correct and closer to Kubernetes strategic merge behavior.

Suggested change:

func mergeContainer(original corev1.Container, override applycorev1.ContainerApplyConfiguration) corev1.Container {
	merged := helmette.MergeTo[corev1.Container](override, original)
	merged.Env = mergeSliceBy(original.Env, override.Env, "name", mergeEnvVar)
	merged.VolumeMounts = mergeSliceBy(original.VolumeMounts, override.VolumeMounts, "mountPath", mergeVolumeMount)
	return merged
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions