Skip to content

Commit c9cada6

Browse files
authored
add pooler suffix to DNS annotation of pooler LoadBalancer service (#2188)
* add pooler suffix to DNS annotation of pooler LoadBalancer service * need generatePoolerServiceAnnotations function
1 parent 7887ebb commit c9cada6

File tree

7 files changed

+91
-36
lines changed

7 files changed

+91
-36
lines changed

docs/administrator.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,9 @@ Load balancer services can also be enabled for the [connection pooler](user.md#c
810810
pods with manifest flags `enableMasterPoolerLoadBalancer` and/or
811811
`enableReplicaPoolerLoadBalancer` or in the operator configuration with
812812
`enable_master_pooler_load_balancer` and/or `enable_replica_pooler_load_balancer`.
813+
For the `external-dns.alpha.kubernetes.io/hostname` annotation the `-pooler`
814+
suffix will be appended to the cluster name used in the template which is
815+
defined in `master|replica_dns_name_format`.
813816

814817
## Running periodic 'autorepair' scans of K8s objects
815818

e2e/tests/test_e2e.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -670,6 +670,20 @@ def test_enable_disable_connection_pooler(self):
670670
'LoadBalancer',
671671
"Expected LoadBalancer service type for replica pooler pod, found {}")
672672

673+
master_annotations = {
674+
"external-dns.alpha.kubernetes.io/hostname": "acid-minimal-cluster-pooler.default.db.example.com",
675+
"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "3600",
676+
}
677+
self.eventuallyTrue(lambda: k8s.check_service_annotations(
678+
master_pooler_label+","+pooler_label, master_annotations), "Wrong annotations")
679+
680+
replica_annotations = {
681+
"external-dns.alpha.kubernetes.io/hostname": "acid-minimal-cluster-pooler-repl.default.db.example.com",
682+
"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "3600",
683+
}
684+
self.eventuallyTrue(lambda: k8s.check_service_annotations(
685+
replica_pooler_label+","+pooler_label, replica_annotations), "Wrong annotations")
686+
673687
# Turn off only master connection pooler
674688
k8s.api.custom_objects_api.patch_namespaced_custom_object(
675689
'acid.zalan.do', 'v1', 'default',

manifests/complete-postgres-manifest.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ spec:
2828
enableReplicaLoadBalancer: false
2929
enableConnectionPooler: false # enable/disable connection pooler deployment
3030
enableReplicaConnectionPooler: false # set to enable connectionPooler for replica service
31+
enableMasterPoolerLoadBalancer: false
32+
enableReplicaPoolerLoadBalancer: false
3133
allowedSourceRanges: # load balancers' source ranges for both master and replica services
3234
- 127.0.0.1/32
3335
databases:

pkg/cluster/connection_pooler.go

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ type ConnectionPoolerObjects struct {
4545
}
4646

4747
func (c *Cluster) connectionPoolerName(role PostgresRole) string {
48-
name := c.Name + "-pooler"
48+
name := fmt.Sprintf("%s-%s", c.Name, constants.ConnectionPoolerResourceSuffix)
4949
if role == Replica {
5050
name = fmt.Sprintf("%s-%s", name, "repl")
5151
}
@@ -163,24 +163,27 @@ func (c *Cluster) createConnectionPooler(LookupFunction InstallFunction) (SyncRe
163163
return reason, nil
164164
}
165165

166-
//
167166
// Generate pool size related environment variables.
168167
//
169168
// MAX_DB_CONN would specify the global maximum for connections to a target
170-
// database.
169+
//
170+
// database.
171171
//
172172
// MAX_CLIENT_CONN is not configurable at the moment, just set it high enough.
173173
//
174174
// DEFAULT_SIZE is a pool size per db/user (having in mind the use case when
175-
// most of the queries coming through a connection pooler are from the same
176-
// user to the same db). In case if we want to spin up more connection pooler
177-
// instances, take this into account and maintain the same number of
178-
// connections.
175+
//
176+
// most of the queries coming through a connection pooler are from the same
177+
// user to the same db). In case if we want to spin up more connection pooler
178+
// instances, take this into account and maintain the same number of
179+
// connections.
179180
//
180181
// MIN_SIZE is a pool's minimal size, to prevent situation when sudden workload
181-
// have to wait for spinning up a new connections.
182+
//
183+
// have to wait for spinning up a new connections.
182184
//
183185
// RESERVE_SIZE is how many additional connections to allow for a pooler.
186+
184187
func (c *Cluster) getConnectionPoolerEnvVars() []v1.EnvVar {
185188
spec := &c.Spec
186189
connectionPoolerSpec := spec.ConnectionPooler
@@ -475,23 +478,23 @@ func (c *Cluster) generateConnectionPoolerDeployment(connectionPooler *Connectio
475478
}
476479

477480
func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPoolerObjects) *v1.Service {
478-
479481
spec := &c.Spec
482+
poolerRole := connectionPooler.Role
480483
serviceSpec := v1.ServiceSpec{
481484
Ports: []v1.ServicePort{
482485
{
483486
Name: connectionPooler.Name,
484487
Port: pgPort,
485-
TargetPort: intstr.IntOrString{IntVal: c.servicePort(connectionPooler.Role)},
488+
TargetPort: intstr.IntOrString{IntVal: c.servicePort(poolerRole)},
486489
},
487490
},
488491
Type: v1.ServiceTypeClusterIP,
489492
Selector: map[string]string{
490-
"connection-pooler": c.connectionPoolerName(connectionPooler.Role),
493+
"connection-pooler": c.connectionPoolerName(poolerRole),
491494
},
492495
}
493496

494-
if c.shouldCreateLoadBalancerForPoolerService(connectionPooler.Role, spec) {
497+
if c.shouldCreateLoadBalancerForPoolerService(poolerRole, spec) {
495498
c.configureLoadBalanceService(&serviceSpec, spec.AllowedSourceRanges)
496499
}
497500

@@ -500,7 +503,7 @@ func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPo
500503
Name: connectionPooler.Name,
501504
Namespace: connectionPooler.Namespace,
502505
Labels: c.connectionPoolerLabels(connectionPooler.Role, false).MatchLabels,
503-
Annotations: c.annotationsSet(c.generateServiceAnnotations(connectionPooler.Role, spec)),
506+
Annotations: c.annotationsSet(c.generatePoolerServiceAnnotations(poolerRole, spec)),
504507
// make StatefulSet object its owner to represent the dependency.
505508
// By itself StatefulSet is being deleted with "Orphaned"
506509
// propagation policy, which means that it's deletion will not
@@ -515,6 +518,32 @@ func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPo
515518
return service
516519
}
517520

521+
func (c *Cluster) generatePoolerServiceAnnotations(role PostgresRole, spec *acidv1.PostgresSpec) map[string]string {
522+
var dnsString string
523+
annotations := c.getCustomServiceAnnotations(role, spec)
524+
525+
if c.shouldCreateLoadBalancerForPoolerService(role, spec) {
526+
// set ELB Timeout annotation with default value
527+
if _, ok := annotations[constants.ElbTimeoutAnnotationName]; !ok {
528+
annotations[constants.ElbTimeoutAnnotationName] = constants.ElbTimeoutAnnotationValue
529+
}
530+
// -repl suffix will be added by replicaDNSName
531+
clusterNameWithPoolerSuffix := c.connectionPoolerName(Master)
532+
if role == Master {
533+
dnsString = c.masterDNSName(clusterNameWithPoolerSuffix)
534+
} else {
535+
dnsString = c.replicaDNSName(clusterNameWithPoolerSuffix)
536+
}
537+
annotations[constants.ZalandoDNSNameAnnotation] = dnsString
538+
}
539+
540+
if len(annotations) == 0 {
541+
return nil
542+
}
543+
544+
return annotations
545+
}
546+
518547
func (c *Cluster) shouldCreateLoadBalancerForPoolerService(role PostgresRole, spec *acidv1.PostgresSpec) bool {
519548

520549
switch role {
@@ -546,7 +575,7 @@ func (c *Cluster) listPoolerPods(listOptions metav1.ListOptions) ([]v1.Pod, erro
546575
return pods.Items, nil
547576
}
548577

549-
//delete connection pooler
578+
// delete connection pooler
550579
func (c *Cluster) deleteConnectionPooler(role PostgresRole) (err error) {
551580
c.logger.Infof("deleting connection pooler spilo-role=%s", role)
552581

@@ -605,7 +634,7 @@ func (c *Cluster) deleteConnectionPooler(role PostgresRole) (err error) {
605634
return nil
606635
}
607636

608-
//delete connection pooler
637+
// delete connection pooler
609638
func (c *Cluster) deleteConnectionPoolerSecret() (err error) {
610639
// Repeat the same for the secret object
611640
secretName := c.credentialSecretName(c.OpConfig.ConnectionPooler.User)
@@ -654,7 +683,7 @@ func updateConnectionPoolerDeployment(KubeClient k8sutil.KubernetesClient, newDe
654683
return deployment, nil
655684
}
656685

657-
//updateConnectionPoolerAnnotations updates the annotations of connection pooler deployment
686+
// updateConnectionPoolerAnnotations updates the annotations of connection pooler deployment
658687
func updateConnectionPoolerAnnotations(KubeClient k8sutil.KubernetesClient, deployment *appsv1.Deployment, annotations map[string]string) (*appsv1.Deployment, error) {
659688
patchData, err := metaAnnotationsPatch(annotations)
660689
if err != nil {

pkg/cluster/k8sres.go

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,25 +1901,13 @@ func (c *Cluster) configureLoadBalanceService(serviceSpec *v1.ServiceSpec, sourc
19011901
}
19021902

19031903
func (c *Cluster) generateServiceAnnotations(role PostgresRole, spec *acidv1.PostgresSpec) map[string]string {
1904-
annotations := make(map[string]string)
1905-
maps.Copy(annotations, c.OpConfig.CustomServiceAnnotations)
1906-
1907-
if spec != nil {
1908-
maps.Copy(annotations, spec.ServiceAnnotations)
1909-
1910-
switch role {
1911-
case Master:
1912-
maps.Copy(annotations, spec.MasterServiceAnnotations)
1913-
case Replica:
1914-
maps.Copy(annotations, spec.ReplicaServiceAnnotations)
1915-
}
1916-
}
1904+
annotations := c.getCustomServiceAnnotations(role, spec)
19171905

19181906
if c.shouldCreateLoadBalancerForService(role, spec) {
19191907
dnsName := c.dnsName(role)
19201908

19211909
// Just set ELB Timeout annotation with default value, if it does not
1922-
// have a cutom value
1910+
// have a custom value
19231911
if _, ok := annotations[constants.ElbTimeoutAnnotationName]; !ok {
19241912
annotations[constants.ElbTimeoutAnnotationName] = constants.ElbTimeoutAnnotationValue
19251913
}
@@ -1934,6 +1922,24 @@ func (c *Cluster) generateServiceAnnotations(role PostgresRole, spec *acidv1.Pos
19341922
return annotations
19351923
}
19361924

1925+
func (c *Cluster) getCustomServiceAnnotations(role PostgresRole, spec *acidv1.PostgresSpec) map[string]string {
1926+
annotations := make(map[string]string)
1927+
maps.Copy(annotations, c.OpConfig.CustomServiceAnnotations)
1928+
1929+
if spec != nil {
1930+
maps.Copy(annotations, spec.ServiceAnnotations)
1931+
1932+
switch role {
1933+
case Master:
1934+
maps.Copy(annotations, spec.MasterServiceAnnotations)
1935+
case Replica:
1936+
maps.Copy(annotations, spec.ReplicaServiceAnnotations)
1937+
}
1938+
}
1939+
1940+
return annotations
1941+
}
1942+
19371943
func (c *Cluster) generateEndpoint(role PostgresRole, subsets []v1.EndpointSubset) *v1.Endpoints {
19381944
endpoints := &v1.Endpoints{
19391945
ObjectMeta: metav1.ObjectMeta{

pkg/cluster/util.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -509,9 +509,9 @@ func (c *Cluster) dnsName(role PostgresRole) string {
509509
var dnsString, oldDnsString string
510510

511511
if role == Master {
512-
dnsString = c.masterDNSName()
512+
dnsString = c.masterDNSName(c.Name)
513513
} else {
514-
dnsString = c.replicaDNSName()
514+
dnsString = c.replicaDNSName(c.Name)
515515
}
516516

517517
// if cluster name starts with teamID we might need to provide backwards compatibility
@@ -528,17 +528,17 @@ func (c *Cluster) dnsName(role PostgresRole) string {
528528
return dnsString
529529
}
530530

531-
func (c *Cluster) masterDNSName() string {
531+
func (c *Cluster) masterDNSName(clusterName string) string {
532532
return strings.ToLower(c.OpConfig.MasterDNSNameFormat.Format(
533-
"cluster", c.Name,
533+
"cluster", clusterName,
534534
"namespace", c.Namespace,
535535
"team", c.teamName(),
536536
"hostedzone", c.OpConfig.DbHostedZone))
537537
}
538538

539-
func (c *Cluster) replicaDNSName() string {
539+
func (c *Cluster) replicaDNSName(clusterName string) string {
540540
return strings.ToLower(c.OpConfig.ReplicaDNSNameFormat.Format(
541-
"cluster", c.Name,
541+
"cluster", clusterName,
542542
"namespace", c.Namespace,
543543
"team", c.teamName(),
544544
"hostedzone", c.OpConfig.DbHostedZone))

pkg/util/constants/pooler.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package constants
22

33
// Connection pooler specific constants
44
const (
5+
ConnectionPoolerResourceSuffix = "pooler"
56
ConnectionPoolerUserName = "pooler"
67
ConnectionPoolerSchemaName = "pooler"
78
ConnectionPoolerDefaultType = "pgbouncer"

0 commit comments

Comments
 (0)