Skip to content

K8SPG-864: add sidecarPVCs and sidecarVolumes#1394

Open
pooknull wants to merge 16 commits intomainfrom
K8SPG-864
Open

K8SPG-864: add sidecarPVCs and sidecarVolumes#1394
pooknull wants to merge 16 commits intomainfrom
K8SPG-864

Conversation

@pooknull
Copy link
Contributor

@pooknull pooknull commented Jan 8, 2026

K8SPG-864 Powered by Pull Request Badge

https://perconadev.atlassian.net/browse/K8SPG-864

DESCRIPTION

This PR adds the following fields to the cr.yaml:

  • .spec.instances[].sidecarPVCs
  • .spec.instances[].sidecarVolumes
  • .spec.proxy.pgBouncer.sidecarPVCs
  • .spec.proxy.pgBouncer.sidecarVolumes
  • .spec.backups.pgbackrest.repoHost.sidecarPVCs
  • .spec.backups.pgbackrest.repoHost.sidecarVolumes

The sidecarPVCs field defines PersistentVolumeClaims that should be created and associated with a specific resource. Example:

sidecarPVCs:
- name: sidecar-volume-claim
  spec:
    resources:
      requests:
        storage: 1Gi
    volumeMode: Filesystem
    accessModes:
      - ReadWriteOnce

The sidecarVolumes field defines volumes that should be attached to a specific resource. Example:

sidecarVolumes:
- name: sidecar-secret
  secret:
    secretName: mysecret
- name: sidecar-config
  configMap:
    name: myconfigmap
- name: backup-nfs
  nfs:
    server: "nfs-service.storage.svc.cluster.local"
    path: "/pg-some-name"

Helm PR: percona/percona-helm-charts#783

CHECKLIST

Jira

  • Is the Jira ticket created and referenced properly?
  • Does the Jira ticket have the proper statuses for documentation (Needs Doc) and QA (Needs QA)?
  • Does the Jira ticket link to the proper milestone (Fix Version field)?

Tests

  • Is an E2E test/test case added for the new feature/change?
  • Are unit tests added where appropriate?

Config/Logging/Testability

  • Are all needed new/changed options added to default YAML files?
  • Are all needed new/changed options added to the Helm Chart?
  • Did we add proper logging messages for operator actions?
  • Did we ensure compatibility with the previous version or cluster upgrade process?
  • Does the change support oldest and newest supported PG version?
  • Does the change support oldest and newest supported Kubernetes version?

@pooknull pooknull marked this pull request as ready for review January 13, 2026 09:50
Comment on lines 1259 to 1266
if cluster.CompareVersion("2.9.0") >= 0 {
for _, p := range spec.SidecarPVCs {
instance.Spec.VolumeClaimTemplates = append(instance.Spec.VolumeClaimTemplates, corev1.PersistentVolumeClaim{
ObjectMeta: metav1.ObjectMeta{Name: p.Name},
Spec: p.Spec,
})
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

does this mean that users can only add sidecar PVCs while creating clusters? i guess we had the same limitation in other operators.

Comment on lines 51 to 53
Copy link
Contributor

Choose a reason for hiding this comment

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

but if we are creating PVCs ourselves why don't we just add them into statefulset volumes so they can also be added after cluster creation?

Copy link
Contributor

Choose a reason for hiding this comment

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

ok, i now realized we're doing this only for pgbouncer because it's a deployment. but if we do this for all, we'd overcome the limitation of adding sidecar pvcs after creation

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

i don't think we should downgrade

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pooknull pooknull requested a review from egegunes February 10, 2026 11:56
Copy link
Contributor

Choose a reason for hiding this comment

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

why this was deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Comment on lines 45 to 48
Copy link
Contributor

Choose a reason for hiding this comment

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

should we have some sort of labels added here so that we know that these pvcs are created by the operator?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), &corev1.PersistentVolumeClaim{})
if err == nil {
// already exists
continue
Copy link
Contributor

Choose a reason for hiding this comment

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

What should happen if the pvcs are updated in terms of specs? should we update them of skip?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@gkech
Copy link
Contributor

gkech commented Feb 11, 2026

let's check also why unit tests are failing on this pr

Run make check
REGISTRY_NAME is not set
Updated IMAGE to: docker.io/perconalab/percona-postgresql-operator:head
docker.io/perconalab/percona-postgresql-operator:head
git -C 'hack/tools/' clone https://github.com/CrunchyData/pgmonitor.git || git -C 'hack/tools/pgmonitor' fetch origin
fatal: cannot change to 'hack/tools/': No such file or directory
fatal: cannot change to 'hack/tools/pgmonitor': No such file or directory
make: *** [Makefile:49: get-pgmonitor] Error 128
Error: Process completed with exit code 2.

@egegunes egegunes added this to the v2.9.0 milestone Feb 12, 2026
Copilot AI review requested due to automatic review settings February 13, 2026 12:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds support for configuring extra volumes and operator-managed PVCs for sidecar containers across instance pods, pgBouncer, and pgBackRest repoHost, along with the necessary API/plumbing, RBAC, and tests.

Changes:

  • Extend CRDs/types with sidecarVolumes and sidecarPVCs for instances, pgBouncer, and pgBackRest repoHost.
  • Reconcile pod specs to mount the configured sidecar volumes/PVCs, and add a controller reconciler to create/update the defined PVCs.
  • Update RBAC and sidecar-related unit/E2E tests to cover the new fields.

Reviewed changes

Copilot reviewed 20 out of 28 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
pkg/apis/postgres-operator.crunchydata.com/v1beta1/zz_generated.deepcopy.go Deepcopy updates for new fields and new SidecarPVC type.
pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go Adds sidecarVolumes/sidecarPVCs to instance set spec + defines SidecarPVC.
pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbouncer_types.go Adds sidecarVolumes/sidecarPVCs to pgBouncer pod spec.
pkg/apis/postgres-operator.crunchydata.com/v1beta1/pgbackrest_types.go Adds sidecarVolumes/sidecarPVCs to pgBackRest repoHost spec.
pkg/apis/pgv2.percona.com/v2/zz_generated.deepcopy.go Deepcopy updates for new Percona API fields.
pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go Adds Percona-level fields and maps them through ToCrunchy().
percona/controller/pgcluster/pvc.go New reconciler to create/update PVCs declared via sidecarPVCs.
percona/controller/pgcluster/controller_test.go Extends sidecar tests to assert volumes + PVC-backed volumes are present.
percona/controller/pgcluster/controller.go Calls PVC reconciler and adds PVC RBAC marker.
internal/postgres/reconcile.go Adds sidecarVolumes to instance pods (version-gated).
internal/pgbouncer/reconcile.go Adds sidecarVolumes and PVC-backed volumes to pgBouncer pod spec (version-gated).
internal/controller/postgrescluster/pgbackrest.go Adds sidecarVolumes and PVC-backed volumes to repoHost pod template (version-gated).
internal/controller/postgrescluster/instance.go Adds PVC-backed volumes to instance StatefulSet pod template (version-gated).
e2e-tests/tests/sidecars/01-create-cluster.yaml Sets sidecarVolumes/sidecarPVCs fields in the sidecars E2E test.
e2e-tests/tests/sidecars/01-assert.yaml Adds assertions for PVC creation/binding in the sidecars E2E test.
deploy/rbac.yaml Grants PVC verbs in deployment RBAC.
deploy/cw-rbac.yaml Same RBAC updates for cw deployment.
config/rbac/namespace/role.yaml Grants PVC verbs in generated namespace Role.
config/rbac/cluster/role.yaml Grants PVC verbs in generated cluster Role.
Makefile Minor formatting/line fix in after-release target.

Copy link
Collaborator

@hors hors left a comment

Choose a reason for hiding this comment

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

@pooknull please check sidecars test

@pooknull pooknull requested a review from hors February 18, 2026 11:25
Copilot AI review requested due to automatic review settings February 18, 2026 12:34
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 20 out of 28 changed files in this pull request and generated 5 comments.

Comment on lines +14 to +21
| yq eval '.spec.instances[0].sidecarVolumes = [{"name": "sidecar-secret", "secret": {"secretName": "mysecret"}}]' - \
| yq eval '.spec.instances[0].sidecarPVCs = [{"name": "sidecar-instance-claim", "spec": {"resources": {"requests": {"storage": "1Gi"}}, "volumeMode": "Filesystem", "accessModes": ["ReadWriteOnce"]}}]' - \
| yq eval '.spec.proxy.pgBouncer.sidecars = [{"name": "sidecar1", "image": "busybox", "command": ["sleep", "30d"]}]' - \
| yq eval '.spec.proxy.pgBouncer.sidecarVolumes = [{"name": "sidecar-secret", "secret": {"secretName": "mysecret"}}]' - \
| yq eval '.spec.proxy.pgBouncer.sidecarPVCs = [{"name": "sidecar-pgbouncer-claim", "spec": {"resources": {"requests": {"storage": "1Gi"}}, "volumeMode": "Filesystem", "accessModes": ["ReadWriteOnce"]}}]' - \
| yq eval '.spec.backups.pgbackrest.repoHost.sidecars = [{"name": "sidecar1", "image": "busybox", "command": ["sleep", "30d"]}]' - \
| yq eval '.spec.backups.pgbackrest.repoHost.sidecarVolumes = [{"name": "sidecar-secret", "secret": {"secretName": "mysecret"}}]' - \
| yq eval '.spec.backups.pgbackrest.repoHost.sidecarPVCs = [{"name": "sidecar-repohost-claim", "spec": {"resources": {"requests": {"storage": "1Gi"}}, "volumeMode": "Filesystem", "accessModes": ["ReadWriteOnce"]}}]' - \
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Problem: The E2E test references a secret named "mysecret" that doesn't appear to be created in the test setup.

Why it matters: If the secret doesn't exist, the sidecarVolumes configuration will fail when Kubernetes tries to mount it, causing pods to be stuck in a pending or error state. The test may pass if the volume is defined but never actually mounted by a sidecar container, masking this issue.

Fix: Either create the secret "mysecret" in the test setup (e.g., in 00-deploy-operator.yaml or a new 00-create-secret.yaml step), or use a volume type that doesn't require external resources (like emptyDir) if the test is only validating that volumes are properly added to the pod spec.

Copilot uses AI. Check for mistakes.
Comment on lines +74 to +88
for _, sidecarPVC := range pvcs {
pvc := new(corev1.PersistentVolumeClaim)
pvc.Name = sidecarPVC.Name
pvc.Namespace = cr.Namespace

if err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), pvc); err != nil {
if !k8serrors.IsNotFound(err) {
return errors.Wrapf(err, "get %s", client.ObjectKeyFromObject(pvc).String())
}
pvc.Spec = sidecarPVC.Spec
pvc.Labels = ls
if err := cl.Create(ctx, pvc); err != nil {
return errors.Wrap(err, "failed to create pvc")
}
continue
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Problem: PVCs created by this function do not have a controller reference set.

Why it matters: Without a controller reference, these PVCs will not be garbage-collected when the cluster is deleted. This leads to resource leaks where PVCs persist after cluster deletion, potentially causing issues with storage quotas and requiring manual cleanup.

Fix: Add a controller reference using controllerutil.SetControllerReference before creating the PVC. This ensures proper ownership and automatic cleanup. See percona/controller/pgcluster/backup.go:191 and percona/controller/pgcluster/patroniversion.go:180 for examples of this pattern in the codebase.

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +114
func ensureSidecarPVCs(
ctx context.Context,
cl client.Client,
cr *v2.PerconaPGCluster,
pvcs []v1beta1.SidecarPVC,
ls map[string]string,
) error {
for _, sidecarPVC := range pvcs {
pvc := new(corev1.PersistentVolumeClaim)
pvc.Name = sidecarPVC.Name
pvc.Namespace = cr.Namespace

if err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), pvc); err != nil {
if !k8serrors.IsNotFound(err) {
return errors.Wrapf(err, "get %s", client.ObjectKeyFromObject(pvc).String())
}
pvc.Spec = sidecarPVC.Spec
pvc.Labels = ls
if err := cl.Create(ctx, pvc); err != nil {
return errors.Wrap(err, "failed to create pvc")
}
continue
}
if v := pvc.Labels[naming.LabelPerconaManagedBy]; v != "percona-postgresql-operator" {
return errors.Errorf("PersistentVolumeClaim %s already exists and not managed by percona-postgresql-operator: %s", client.ObjectKeyFromObject(pvc).String(), v)
}
if v := pvc.Labels[naming.LabelPerconaInstance]; v != cr.Name {
return errors.Errorf("PersistentVolumeClaim %s already exists and belongs to another cluster %s", client.ObjectKeyFromObject(pvc).String(), v)
}

if err := retry.RetryOnConflict(retry.DefaultRetry, func() error {
if err := cl.Get(ctx, client.ObjectKeyFromObject(pvc), pvc); err != nil {
return err
}
maps.Copy(pvc.Labels, ls)

// It's only allowed to update resources.requests and volumeAttributesClassName
pvc.Spec.Resources.Requests = sidecarPVC.Spec.Resources.Requests
pvc.Spec.VolumeAttributesClassName = sidecarPVC.Spec.VolumeAttributesClassName

return cl.Update(ctx, pvc)
}); err != nil {
return errors.Wrapf(err, "update PersistentVolumeClaim %s", client.ObjectKeyFromObject(pvc).String())
}
}

return nil
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Problem: Missing logging for important operator actions during PVC reconciliation.

Why it matters: According to the coding guideline "Add logging for important operator actions (reconcile steps, errors, retries)", logging helps track operator behavior and debug issues in production. PVC creation, updates, and conflicts are important reconcile steps that should be logged.

Fix: Add structured logging using logging.FromContext(ctx) with appropriate log levels (Info for creation/updates, Error for failures). For example, log when creating a PVC, when updating an existing PVC, and when encountering conflicts.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +819 to +822
// K8SPG-864
type SidecarPVC struct {
Name string `json:"name"`

Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Problem: Missing documentation comments for the SidecarPVC type.

Why it matters: The SidecarPVC type is a new public API type that will be used by end-users in their CR YAML files. Following codebase conventions, API types should have documentation describing their purpose and fields.

Fix: Add a documentation comment above the SidecarPVC type definition explaining what it is and how it's used, similar to other type definitions in this file. Also add comments for the Name and Spec fields.

Suggested change
// K8SPG-864
type SidecarPVC struct {
Name string `json:"name"`
// K8SPG-864
// SidecarPVC describes a PersistentVolumeClaim that should be created and
// mounted for a sidecar container.
type SidecarPVC struct {
// Name is the name of the PersistentVolumeClaim used by the sidecar.
Name string `json:"name"`
// Spec defines the desired specification of the PersistentVolumeClaim.

Copilot uses AI. Check for mistakes.
Comment on lines +820 to +824
type SidecarPVC struct {
Name string `json:"name"`

Spec corev1.PersistentVolumeClaimSpec `json:"spec"`
}
Copy link

Copilot AI Feb 18, 2026

Choose a reason for hiding this comment

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

Problem: The SidecarPVC type lacks validation annotations.

Why it matters: Other API types in this codebase use kubebuilder validation annotations (e.g., +kubebuilder:validation:Required) to enforce constraints and provide clear error messages to users. The Name field should be validated (e.g., pattern, required) to ensure proper resource naming in Kubernetes.

Fix: Add appropriate validation annotations. At minimum, the Name field should have +kubebuilder:validation:Required and likely a pattern constraint similar to other name fields in the codebase (e.g., see postgrescluster_types.go:480).

Copilot uses AI. Check for mistakes.
@JNKPercona
Copy link
Collaborator

Test Name Result Time
backup-enable-disable passed 00:05:40
builtin-extensions passed 00:04:53
custom-envs passed 00:19:38
custom-extensions passed 00:13:43
custom-tls passed 00:05:13
database-init-sql passed 00:02:35
demand-backup passed 00:24:22
demand-backup-offline-snapshot passed 00:13:10
dynamic-configuration passed 00:03:11
finalizers passed 00:03:43
init-deploy passed 00:02:46
huge-pages passed 00:03:04
monitoring passed 00:06:55
monitoring-pmm3 passed 00:11:40
one-pod passed 00:05:55
operator-self-healing passed 00:08:59
pitr passed 00:11:59
scaling passed 00:04:45
scheduled-backup passed 00:27:21
self-healing passed 00:08:43
sidecars passed 00:02:50
standby-pgbackrest passed 00:12:01
standby-streaming passed 00:09:15
start-from-backup passed 00:10:56
tablespaces passed 00:06:47
telemetry-transfer passed 00:03:40
upgrade-consistency passed 00:04:39
upgrade-minor passed 00:05:01
users passed 00:04:36
Summary Value
Tests Run 29/29
Job Duration 01:29:20
Total Test Time 04:08:14

commit: 4866e97
image: perconalab/percona-postgresql-operator:PR-1394-4866e9719

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.

5 participants

Comments