make pooler labels configurable and change defaults

This commit is contained in:
Felix Kunde
2026-04-15 12:09:39 +02:00
parent e9478894a8
commit d859cc58a5
16 changed files with 96 additions and 38 deletions
+10 -2
View File
@@ -452,8 +452,8 @@ configuration they are grouped under the `kubernetes` key.
pooler deployment. The default is empty.
* **pod_role_label**
name of the label assigned to the Postgres pods (and services/endpoints) by
the operator. The default is `spilo-role`.
name of the label assigned to most cluster resources to distinguish objects
with relation to the primary instance from the replica(s). The default is `spilo-role`.
* **cluster_labels**
list of `name:value` pairs for additional labels assigned to the cluster
@@ -1069,6 +1069,14 @@ operator being able to provide some reasonable defaults.
* **connection_pooler_mode**
Default pooler mode, `session` or `transaction`. Default is `transaction`.
* **connection_pooler_labels**
List of `name:value` pairs for additional labels assigned to the pooler
objects. The default is `component:db-connection-pooler`.
* **connection_pooler_role_label**
name of the label assigned to most pooler resources to distinguish objects
with relation to the primary instance from the replica(s). The default is `pooler-role`.
* **connection_pooler_default_cpu_request**
**connection_pooler_default_memory_reques**
**connection_pooler_default_cpu_limit**
+1 -1
View File
@@ -1,6 +1,6 @@
#!/bin/bash
kubectl delete postgresql acid-minimal-cluster
kubectl delete deployments -l application=db-connection-pooler,cluster-name=acid-minimal-cluster
kubectl delete deployments -l application=spilo,cluster-name=acid-minimal-cluster,component=db-connection-pooler
kubectl delete statefulsets -l application=spilo,cluster-name=acid-minimal-cluster
kubectl delete services -l application=spilo,cluster-name=acid-minimal-cluster
kubectl delete configmap postgres-operator
+2 -2
View File
@@ -10,13 +10,13 @@ echo
echo 'Pods'
kubectl get pods -l application=spilo -o wide --all-namespaces
echo
kubectl get pods -l application=db-connection-pooler -o wide --all-namespaces
kubectl get pods -l application=spilo,component=db-connection-pooler -o wide --all-namespaces
echo
echo 'Statefulsets'
kubectl get statefulsets --all-namespaces
echo
echo 'Deployments'
kubectl get deployments --all-namespaces -l application=db-connection-pooler
kubectl get deployments --all-namespaces -l application=spilo,component=db-connection-pooler
kubectl get deployments --all-namespaces -l application=postgres-operator
echo
echo
+1 -1
View File
@@ -678,7 +678,7 @@ class EndToEndTestCase(unittest.TestCase):
the end turn connection pooler off to not interfere with other tests.
'''
k8s = self.k8s
pooler_label = 'application=db-connection-pooler,cluster-name=acid-minimal-cluster'
pooler_label = 'application=spilo,component=db-connection-pooler,cluster-name=acid-minimal-cluster'
master_pooler_label = 'connection-pooler=acid-minimal-cluster-pooler'
replica_pooler_label = master_pooler_label + '-repl'
self.eventuallyEqual(lambda: k8s.get_operator_state(), {"0": "idle"}, "Operator does not get in sync")
@@ -4,19 +4,22 @@ kind: Deployment
metadata:
name: acid-minimal-cluster-pooler
labels:
application: db-connection-pooler
application: spilo
component: db-connection-pooler
connection-pooler: acid-minimal-cluster-pooler
spec:
replicas: 1
selector:
matchLabels:
application: db-connection-pooler
application: spilo
component: db-connection-pooler
connection-pooler: acid-minimal-cluster-pooler
cluster-name: acid-minimal-cluster
template:
metadata:
labels:
application: db-connection-pooler
application: spilo
component: db-connection-pooler
connection-pooler: acid-minimal-cluster-pooler
cluster-name: acid-minimal-cluster
spec:
+11
View File
@@ -898,6 +898,17 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
"connection_pooler_image": {
Type: "string",
},
"connection_pooler_labels": {
Type: "object",
AdditionalProperties: &apiextv1.JSONSchemaPropsOrBool{
Schema: &apiextv1.JSONSchemaProps{
Type: "string",
},
},
},
"connection_pooler_role_label": {
Type: "string",
},
"connection_pooler_max_db_connections": {
Type: "integer",
},
@@ -209,16 +209,18 @@ type ScalyrConfiguration struct {
// ConnectionPoolerConfiguration defines default configuration for connection pooler
type ConnectionPoolerConfiguration struct {
NumberOfInstances *int32 `json:"connection_pooler_number_of_instances,omitempty"`
Schema string `json:"connection_pooler_schema,omitempty"`
User string `json:"connection_pooler_user,omitempty"`
Image string `json:"connection_pooler_image,omitempty"`
Mode string `json:"connection_pooler_mode,omitempty"`
MaxDBConnections *int32 `json:"connection_pooler_max_db_connections,omitempty"`
DefaultCPURequest string `json:"connection_pooler_default_cpu_request,omitempty"`
DefaultMemoryRequest string `json:"connection_pooler_default_memory_request,omitempty"`
DefaultCPULimit string `json:"connection_pooler_default_cpu_limit,omitempty"`
DefaultMemoryLimit string `json:"connection_pooler_default_memory_limit,omitempty"`
NumberOfInstances *int32 `json:"connection_pooler_number_of_instances,omitempty"`
Schema string `json:"connection_pooler_schema,omitempty"`
User string `json:"connection_pooler_user,omitempty"`
Image string `json:"connection_pooler_image,omitempty"`
Mode string `json:"connection_pooler_mode,omitempty"`
MaxDBConnections *int32 `json:"connection_pooler_max_db_connections,omitempty"`
Labels map[string]string `json:"connection_pooler_labels,omitempty"`
RoleLabel string `json:"connection_pooler_role_label,omitempty"`
DefaultCPURequest string `json:"connection_pooler_default_cpu_request,omitempty"`
DefaultMemoryRequest string `json:"connection_pooler_default_memory_request,omitempty"`
DefaultCPULimit string `json:"connection_pooler_default_cpu_limit,omitempty"`
DefaultMemoryLimit string `json:"connection_pooler_default_memory_limit,omitempty"`
}
// OperatorLogicalBackupConfiguration defines configuration for logical backup
+2
View File
@@ -1782,6 +1782,8 @@ func TestCrossNamespacedSecrets(t *testing.T) {
Config{
OpConfig: config.Config{
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
+4 -3
View File
@@ -115,8 +115,9 @@ func (c *Cluster) poolerUser(spec *acidv1.PostgresSpec) string {
func (c *Cluster) poolerLabelsSet(addExtraLabels bool) labels.Set {
poolerLabels := c.labelsSet(addExtraLabels)
// TODO should be config values
poolerLabels["application"] = "db-connection-pooler"
for k, v := range c.OpConfig.ConnectionPooler.Labels {
poolerLabels[k] = v
}
return poolerLabels
}
@@ -134,7 +135,7 @@ func (c *Cluster) connectionPoolerLabels(role PostgresRole, addExtraLabels bool)
if addExtraLabels {
extraLabels := map[string]string{}
extraLabels[c.OpConfig.PodRoleLabel] = string(role)
extraLabels[c.OpConfig.ConnectionPooler.RoleLabel] = string(role)
poolerLabelsSet = labels.Merge(poolerLabelsSet, extraLabels)
}
+19 -5
View File
@@ -45,7 +45,7 @@ func deploymentUpdated(cluster *Cluster, err error, reason SyncReason) error {
for _, role := range [2]PostgresRole{Master, Replica} {
poolerLabels := cluster.labelsSet(false)
poolerLabels["application"] = "db-connection-pooler"
poolerLabels["component"] = "db-connection-pooler"
poolerLabels["connection-pooler"] = cluster.connectionPoolerName(role)
if cluster.ConnectionPooler[role] != nil && cluster.ConnectionPooler[role].Deployment != nil &&
@@ -65,7 +65,7 @@ func objectsAreSaved(cluster *Cluster, err error, reason SyncReason) error {
for _, role := range []PostgresRole{Master, Replica} {
poolerLabels := cluster.labelsSet(false)
poolerLabels["application"] = "db-connection-pooler"
poolerLabels["component"] = "db-connection-pooler"
poolerLabels["connection-pooler"] = cluster.connectionPoolerName(role)
if cluster.ConnectionPooler[role].Deployment == nil || !util.MapContains(cluster.ConnectionPooler[role].Deployment.Labels, poolerLabels) {
@@ -86,7 +86,7 @@ func MasterObjectsAreSaved(cluster *Cluster, err error, reason SyncReason) error
}
poolerLabels := cluster.labelsSet(false)
poolerLabels["application"] = "db-connection-pooler"
poolerLabels["component"] = "db-connection-pooler"
poolerLabels["connection-pooler"] = cluster.connectionPoolerName(Master)
if cluster.ConnectionPooler[Master].Deployment == nil || !util.MapContains(cluster.ConnectionPooler[Master].Deployment.Labels, poolerLabels) {
@@ -106,7 +106,7 @@ func ReplicaObjectsAreSaved(cluster *Cluster, err error, reason SyncReason) erro
}
poolerLabels := cluster.labelsSet(false)
poolerLabels["application"] = "db-connection-pooler"
poolerLabels["component"] = "db-connection-pooler"
poolerLabels["connection-pooler"] = cluster.connectionPoolerName(Replica)
if cluster.ConnectionPooler[Replica].Deployment == nil || !util.MapContains(cluster.ConnectionPooler[Replica].Deployment.Labels, poolerLabels) {
@@ -170,6 +170,8 @@ func TestNeedConnectionPooler(t *testing.T) {
ReplicationUsername: replicationUserName,
},
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -301,6 +303,8 @@ func TestConnectionPoolerCreateDeletion(t *testing.T) {
Config{
OpConfig: config.Config{
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -336,7 +340,7 @@ func TestConnectionPoolerCreateDeletion(t *testing.T) {
}
for _, role := range [2]PostgresRole{Master, Replica} {
poolerLabels := cluster.labelsSet(false)
poolerLabels["application"] = "db-connection-pooler"
poolerLabels["component"] = "db-connection-pooler"
poolerLabels["connection-pooler"] = cluster.connectionPoolerName(role)
if cluster.ConnectionPooler[role] != nil {
@@ -409,6 +413,8 @@ func TestConnectionPoolerSync(t *testing.T) {
Config{
OpConfig: config.Config{
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -678,6 +684,8 @@ func TestConnectionPoolerPodSpec(t *testing.T) {
PodServiceAccountName: "postgres-pod",
ConnectionPooler: config.ConnectionPooler{
MaxDBConnections: k8sutil.Int32ToPointer(60),
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -789,6 +797,8 @@ func TestConnectionPoolerDeploymentSpec(t *testing.T) {
ReplicationUsername: replicationUserName,
},
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -1003,6 +1013,8 @@ func TestPoolerTLS(t *testing.T) {
SpiloFSGroup: &spiloFSGroup,
},
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -1072,6 +1084,8 @@ func TestConnectionPoolerServiceSpec(t *testing.T) {
ReplicationUsername: replicationUserName,
},
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
+4
View File
@@ -3022,6 +3022,8 @@ func TestEnableLoadBalancers(t *testing.T) {
subTest: "LBs enabled in config, disabled in manifest",
config: config.Config{
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
@@ -3069,6 +3071,8 @@ func TestEnableLoadBalancers(t *testing.T) {
subTest: "LBs enabled in manifest, disabled in config",
config: config.Config{
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
+2
View File
@@ -192,6 +192,8 @@ func TestPodAnnotationsSync(t *testing.T) {
PodManagementPolicy: "ordered_ready",
CustomPodAnnotations: customPodAnnotations,
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
+2
View File
@@ -301,6 +301,8 @@ func newInheritedAnnotationsCluster(client k8sutil.KubernetesClient) (*Cluster,
PatroniAPICheckTimeout: time.Duration(5),
KubernetesUseConfigMaps: true,
ConnectionPooler: config.ConnectionPooler{
Labels: map[string]string{"component": "db-connection-pooler"},
RoleLabel: "pooler-role",
ConnectionPoolerDefaultCPURequest: "100m",
ConnectionPoolerDefaultCPULimit: "100m",
ConnectionPoolerDefaultMemoryRequest: "100Mi",
+2
View File
@@ -280,6 +280,8 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
fromCRD.ConnectionPooler.Mode,
constants.ConnectionPoolerDefaultMode)
result.ConnectionPooler.Labels = util.CoalesceStrMap(fromCRD.ConnectionPooler.Labels, map[string]string{"application": "spilo"})
result.ConnectionPooler.RoleLabel = util.Coalesce(fromCRD.ConnectionPooler.RoleLabel, "pooler-role")
result.ConnectionPooler.ConnectionPoolerDefaultCPURequest = fromCRD.ConnectionPooler.DefaultCPURequest
result.ConnectionPooler.ConnectionPoolerDefaultMemoryRequest = fromCRD.ConnectionPooler.DefaultMemoryRequest
result.ConnectionPooler.ConnectionPoolerDefaultCPULimit = fromCRD.ConnectionPooler.DefaultCPULimit
+17 -10
View File
@@ -152,16 +152,18 @@ type LogicalBackup struct {
// Operator options for connection pooler
type ConnectionPooler struct {
NumberOfInstances *int32 `name:"connection_pooler_number_of_instances" default:"2"`
Schema string `name:"connection_pooler_schema" default:"pooler"`
User string `name:"connection_pooler_user" default:"pooler"`
Image string `name:"connection_pooler_image" default:"registry.opensource.zalan.do/acid/pgbouncer"`
Mode string `name:"connection_pooler_mode" default:"transaction"`
MaxDBConnections *int32 `name:"connection_pooler_max_db_connections" default:"60"`
ConnectionPoolerDefaultCPURequest string `name:"connection_pooler_default_cpu_request"`
ConnectionPoolerDefaultMemoryRequest string `name:"connection_pooler_default_memory_request"`
ConnectionPoolerDefaultCPULimit string `name:"connection_pooler_default_cpu_limit"`
ConnectionPoolerDefaultMemoryLimit string `name:"connection_pooler_default_memory_limit"`
NumberOfInstances *int32 `name:"connection_pooler_number_of_instances" default:"2"`
Schema string `name:"connection_pooler_schema" default:"pooler"`
User string `name:"connection_pooler_user" default:"pooler"`
Image string `name:"connection_pooler_image" default:"registry.opensource.zalan.do/acid/pgbouncer"`
Mode string `name:"connection_pooler_mode" default:"transaction"`
MaxDBConnections *int32 `name:"connection_pooler_max_db_connections" default:"60"`
Labels map[string]string `name:"connection_pooler_labels,omitempty" default:"component:db-connection-pooler"`
RoleLabel string `name:"connection_pooler_role_label" default:"pooler-role"`
ConnectionPoolerDefaultCPURequest string `name:"connection_pooler_default_cpu_request"`
ConnectionPoolerDefaultMemoryRequest string `name:"connection_pooler_default_memory_request"`
ConnectionPoolerDefaultCPULimit string `name:"connection_pooler_default_cpu_limit"`
ConnectionPoolerDefaultMemoryLimit string `name:"connection_pooler_default_memory_limit"`
}
// Config describes operator config
@@ -304,6 +306,11 @@ func Copy(c *Config) Config {
cfg.ClusterLabels[k] = v
}
cfg.ConnectionPooler.Labels = make(map[string]string, len(c.ConnectionPooler.Labels))
for k, v := range c.ConnectionPooler.Labels {
cfg.ConnectionPooler.Labels[k] = v
}
return cfg
}
+1 -1
View File
@@ -17,7 +17,7 @@ AWS_ENDPOINT = getenv('AWS_ENDPOINT')
OPERATOR_CLUSTER_NAME_LABEL = getenv('OPERATOR_CLUSTER_NAME_LABEL', 'cluster-name')
COMMON_CLUSTER_LABEL = getenv('COMMON_CLUSTER_LABEL', '{"application":"spilo"}')
COMMON_POOLER_LABEL = getenv('COMMON_POOLER_LABEL', '{"application":"db-connection-pooler"}')
COMMON_POOLER_LABEL = getenv('COMMON_POOLER_LABEL', '{"application":"spilo","component":"db-connection-pooler"}')
logger.info("Common Cluster Label: {}".format(COMMON_CLUSTER_LABEL))
logger.info("Common Pooler Label: {}".format(COMMON_POOLER_LABEL))