Skip to content

Attach additional volume for postgres, #4210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

benjaminjb
Copy link
Contributor

Checklist:

  • Have you added an explanation of what your changes do and why you'd like them to be included?
  • Have you updated or added documentation for the change, as applicable?
  • Have you tested your changes on all related environments with successful results, as applicable?
    • Have you added automated tests?

Type of Changes:

  • New feature
  • Bug fix
  • Documentation
  • Testing enhancement
  • Other

What is the current behavior (link to any open issues here)?

Only can add additional volumes to database container through abuse of the tablespace volumes.

What is the new behavior (if this is a feature change)?

  • Breaking change (fix or feature that would cause existing functionality to change)

Ability to add PVC (either BYO or create from template) to multiple containers in the Postgres pod

Other Information:
Issues: [PGO-2556]

// volume for instance.
func AdditionalVolume(cluster *v1beta1.PostgresCluster,
volume *v1beta1.AdditionalVolume) metav1.ObjectMeta {
// TODO: What's the name for the PVC if not given?
Copy link
Member

Choose a reason for hiding this comment

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

🔧 The name field, I imagine. That field should have validation that rejects weird filepath stuff (e.g. slash) and is also valid for K8s API name (subdomain?). We have a few predefined types for names.

[PersistentVolumeClaim (PVC) names are DNS subdomains](https://releases.k8s.io/v1.23.0/pkg/apis/core/validation/validation.go#L2066).

// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
type DNS1123Subdomain = string

@benjaminjb benjaminjb force-pushed the benjb/additional-volumes-postgres branch from d9d4932 to f906775 Compare July 30, 2025 20:03
@benjaminjb benjaminjb force-pushed the benjb/additional-volumes-postgres branch from 88d226d to 955087a Compare August 4, 2025 20:32
Change the API to allow users to specify preexisting
PVCs to attach to specified containers in the postgres
instance pods.

Issues: [PGO-2556]
@benjaminjb benjaminjb force-pushed the benjb/additional-volumes-postgres branch from 955087a to 0f1cf63 Compare August 4, 2025 20:33
Comment on lines +343 to +345
template.Spec.Volumes = append(
template.Spec.Volumes,
additionalVolume)
Copy link
Contributor

Choose a reason for hiding this comment

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

This is probably fine, but just to clarify, it seems we will always add the volume even if we don't mount it to any containers (which would only happen if the user specifies a container(s) but none of the containers specified actually exist in the pod)...

Do we want to warn the user in any way if any of the containers they've specified don't exist? 🤔 Seems unlikely the user would do this on purpose, but if they misspell/typo their container name and don't realize it...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, it's funny, I was just talking with Andrew earlier in the week about how some people might want to not add the volume to any containers through our system, but mount them manually through, say, the sidecar container spec.

But we don't actually let people mount to no containers: we have some (list the containers) and all (a blank list). Should we add a "none" option or special keyword?

But yeah, right now, we have (a) no way to skip mounting and (b) no validation on the containers being present.

Now if I mispell "database" when trying to mount to the pod, what should our behavior be? I guess we should error out because, likely, if a user put in the wrong container name, and we just warned and created the pod, then they'd find out later, and fix the spec, causing the pod to regenerate. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

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

What would be the point of the user adding their PVC to volumes.additional if they don't want us to mount it to any containers?

Yeah I think doing something (error/warning event/log) makes sense if the user specifies a container that doesn't exist.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, the only potential that I see -- though there might be others -- is that the user has a container definition that already has that volume mounted and it's easier for them (for some reason, potentially CI related) to use that as a custom sidecar (with the volume mounted) rather than define the postgrescluster spec with that volume mounted to that container.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@andrewlecuyer This question isn't a blocker (as we can refine the solution as we move forwards) but I want to raise it:

If the user supplies a container that doesn't exist, what should our behavior be?

Options:

  1. Ignore that issue, let them figure it out. (Con: not very user friendly to not provide feedback)
  2. Issue a warning event, but continue to reconcile the pod (Con: if they see the warning, the user will have to fix the spec, which will cause a pod regeneration of a mis-spec'ed pod)
  3. Error, stop reconciling pod, issue event

@benjaminjb benjaminjb force-pushed the benjb/additional-volumes-postgres branch from 22ab593 to a7ea055 Compare August 12, 2025 21:32
//
// +kubebuilder:validation:MinLength=1
// Max length is less than max 63 to allow prepending `volumes-` to name
// +kubebuilder:validation:MaxLength=55
Copy link
Member

Choose a reason for hiding this comment

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

❓ Can this be 63 here and AdditionalVolume.Name override it with 55 there?

@@ -32,6 +32,16 @@ type ConfigDataKey = string
// +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?([.][a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
type DNS1123Subdomain = string

// ---
Copy link
Member

Choose a reason for hiding this comment

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

⛏️ When possible, I like linking to the user-doc-y stuff, too.

Suggested change
// ---
// ---
// https://docs.k8s.io/concepts/overview/working-with-objects/names#dns-label-names

ClaimName string `json:"claimName"`

// The containers to attach this volume to.
// A blank/unset `Containers` field matches all containers.
Copy link
Member

Choose a reason for hiding this comment

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

❓ Where did we land on empty-list? Does it mean all or none?

📝 I've used the phrase "when omitted" or "when this is omitted" to explain what happens when a field is missing from the spec.

Copy link
Contributor

Choose a reason for hiding this comment

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

I still don't quite understand the use-case for adding a volume that is not mounted into any containers... But I could see how a zero value (empty list) could mean "none" while leaving the field off entirely would mean "all"

// A reference to a preexisting PVC.
// ---
// +required
ClaimName string `json:"claimName"`
Copy link
Member

Choose a reason for hiding this comment

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

🔧 PVC names are 1123 subdomains, so we can use that type here.

https://github.com/kubernetes/kubernetes/blob/v1.33.0/pkg/apis/core/validation/validation.go#L2253ValidatePersistentVolumeNameNameIsDNSSubdomainIsDNS1123Subdomain

Comment on lines +338 to +340
if names.Has(template.Spec.Containers[i].Name) {
names.Delete(template.Spec.Containers[i].Name)
}
Copy link
Member

Choose a reason for hiding this comment

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

⛏️ The guard is unnecessary.

Suggested change
if names.Has(template.Spec.Containers[i].Name) {
names.Delete(template.Spec.Containers[i].Name)
}
names.Delete(template.Spec.Containers[i].Name)

}
}

missingContainers = append(missingContainers, names.UnsortedList()...)
Copy link
Member

Choose a reason for hiding this comment

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

💭 Using Delete to subtract from names relies on init and regular containers having unique names together. That's correct and fine, but I wonder if it is worth calling out.

🤔 Should the resulting slice be a Set?

Copy link
Contributor

Choose a reason for hiding this comment

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

I was about to raise this concern myself... Is it correct though, when you take sidecars into consideration? Couldn't the user add a sidecar to Containers that has the same name as one in InitContainers?

Copy link
Contributor

Choose a reason for hiding this comment

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

Answering my own question: No, the user could not add a sidecar with the same name as an init container. Ben tried it out and the Pod fails to roll out. He also found this in k8s documentation: “The name of each app and init container in a Pod must be unique; a validation error is thrown for any container sharing a name with another.”

Copy link
Member

Choose a reason for hiding this comment

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

🤩 This diff is so small and tidy without the template!

// +listType=map
// +listMapKey=name
// +kubebuilder:validation:MaxItems=10
Additional []v1beta1.AdditionalVolume `json:"additional,omitempty"`
Copy link
Member

Choose a reason for hiding this comment

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

⛏️ I like to alphabetize things. Can Additional go before/above Temp?

Copy link
Member

Choose a reason for hiding this comment

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

🤔 This doesn't seem like the kind of change that needs E2E. Is this here because we have more to add in the future? Are there are tests in the postgrescluster package more like cluster-spec-in → pod-spec-out ?

Comment on lines +1261 to +1262
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "MissingContainers",
"The following containers were specified for additional volumes but are missing: %s.", missingContainers)
Copy link
Contributor

Choose a reason for hiding this comment

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

I think what you have is fine, but you expressed dissatisfaction with what you have, so maybe something like this?

Suggested change
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "MissingContainers",
"The following containers were specified for additional volumes but are missing: %s.", missingContainers)
r.Recorder.Eventf(cluster, corev1.EventTypeWarning, "SpecifiedContainerNotFound",
"The following containers were specified for additional volumes but cannot be found: %s.", missingContainers)


names := sets.New(additionalVolumeRequest.Containers...)
allContainers := false
if names.Len() == 0 {
Copy link
Contributor

Choose a reason for hiding this comment

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

IF we want omission of containers to mean "All" and an empty slice for containers to mean "None":

Suggested change
if names.Len() == 0 {
if additionalVolumeRequest.Containers == nil {

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.

3 participants