add pooler suffix to DNS annotation of pooler LoadBalancer service (#2188)

* add pooler suffix to DNS annotation of pooler LoadBalancer service
* need generatePoolerServiceAnnotations function
This commit is contained in:
Felix Kunde 2023-01-27 12:07:48 +01:00 committed by GitHub
parent 7887ebbbce
commit c9cada66c7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 38 deletions

View File

@ -810,6 +810,9 @@ Load balancer services can also be enabled for the [connection pooler](user.md#c
pods with manifest flags `enableMasterPoolerLoadBalancer` and/or
`enableReplicaPoolerLoadBalancer` or in the operator configuration with
`enable_master_pooler_load_balancer` and/or `enable_replica_pooler_load_balancer`.
For the `external-dns.alpha.kubernetes.io/hostname` annotation the `-pooler`
suffix will be appended to the cluster name used in the template which is
defined in `master|replica_dns_name_format`.
## Running periodic 'autorepair' scans of K8s objects

View File

@ -670,6 +670,20 @@ class EndToEndTestCase(unittest.TestCase):
'LoadBalancer',
"Expected LoadBalancer service type for replica pooler pod, found {}")
master_annotations = {
"external-dns.alpha.kubernetes.io/hostname": "acid-minimal-cluster-pooler.default.db.example.com",
"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "3600",
}
self.eventuallyTrue(lambda: k8s.check_service_annotations(
master_pooler_label+","+pooler_label, master_annotations), "Wrong annotations")
replica_annotations = {
"external-dns.alpha.kubernetes.io/hostname": "acid-minimal-cluster-pooler-repl.default.db.example.com",
"service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout": "3600",
}
self.eventuallyTrue(lambda: k8s.check_service_annotations(
replica_pooler_label+","+pooler_label, replica_annotations), "Wrong annotations")
# Turn off only master connection pooler
k8s.api.custom_objects_api.patch_namespaced_custom_object(
'acid.zalan.do', 'v1', 'default',

View File

@ -28,6 +28,8 @@ spec:
enableReplicaLoadBalancer: false
enableConnectionPooler: false # enable/disable connection pooler deployment
enableReplicaConnectionPooler: false # set to enable connectionPooler for replica service
enableMasterPoolerLoadBalancer: false
enableReplicaPoolerLoadBalancer: false
allowedSourceRanges: # load balancers' source ranges for both master and replica services
- 127.0.0.1/32
databases:

View File

@ -45,7 +45,7 @@ type ConnectionPoolerObjects struct {
}
func (c *Cluster) connectionPoolerName(role PostgresRole) string {
name := c.Name + "-pooler"
name := fmt.Sprintf("%s-%s", c.Name, constants.ConnectionPoolerResourceSuffix)
if role == Replica {
name = fmt.Sprintf("%s-%s", name, "repl")
}
@ -163,24 +163,27 @@ func (c *Cluster) createConnectionPooler(LookupFunction InstallFunction) (SyncRe
return reason, nil
}
//
// Generate pool size related environment variables.
//
// MAX_DB_CONN would specify the global maximum for connections to a target
//
// database.
//
// MAX_CLIENT_CONN is not configurable at the moment, just set it high enough.
//
// DEFAULT_SIZE is a pool size per db/user (having in mind the use case when
//
// most of the queries coming through a connection pooler are from the same
// user to the same db). In case if we want to spin up more connection pooler
// instances, take this into account and maintain the same number of
// connections.
//
// MIN_SIZE is a pool's minimal size, to prevent situation when sudden workload
//
// have to wait for spinning up a new connections.
//
// RESERVE_SIZE is how many additional connections to allow for a pooler.
func (c *Cluster) getConnectionPoolerEnvVars() []v1.EnvVar {
spec := &c.Spec
connectionPoolerSpec := spec.ConnectionPooler
@ -475,23 +478,23 @@ func (c *Cluster) generateConnectionPoolerDeployment(connectionPooler *Connectio
}
func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPoolerObjects) *v1.Service {
spec := &c.Spec
poolerRole := connectionPooler.Role
serviceSpec := v1.ServiceSpec{
Ports: []v1.ServicePort{
{
Name: connectionPooler.Name,
Port: pgPort,
TargetPort: intstr.IntOrString{IntVal: c.servicePort(connectionPooler.Role)},
TargetPort: intstr.IntOrString{IntVal: c.servicePort(poolerRole)},
},
},
Type: v1.ServiceTypeClusterIP,
Selector: map[string]string{
"connection-pooler": c.connectionPoolerName(connectionPooler.Role),
"connection-pooler": c.connectionPoolerName(poolerRole),
},
}
if c.shouldCreateLoadBalancerForPoolerService(connectionPooler.Role, spec) {
if c.shouldCreateLoadBalancerForPoolerService(poolerRole, spec) {
c.configureLoadBalanceService(&serviceSpec, spec.AllowedSourceRanges)
}
@ -500,7 +503,7 @@ func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPo
Name: connectionPooler.Name,
Namespace: connectionPooler.Namespace,
Labels: c.connectionPoolerLabels(connectionPooler.Role, false).MatchLabels,
Annotations: c.annotationsSet(c.generateServiceAnnotations(connectionPooler.Role, spec)),
Annotations: c.annotationsSet(c.generatePoolerServiceAnnotations(poolerRole, spec)),
// make StatefulSet object its owner to represent the dependency.
// By itself StatefulSet is being deleted with "Orphaned"
// propagation policy, which means that it's deletion will not
@ -515,6 +518,32 @@ func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPo
return service
}
func (c *Cluster) generatePoolerServiceAnnotations(role PostgresRole, spec *acidv1.PostgresSpec) map[string]string {
var dnsString string
annotations := c.getCustomServiceAnnotations(role, spec)
if c.shouldCreateLoadBalancerForPoolerService(role, spec) {
// set ELB Timeout annotation with default value
if _, ok := annotations[constants.ElbTimeoutAnnotationName]; !ok {
annotations[constants.ElbTimeoutAnnotationName] = constants.ElbTimeoutAnnotationValue
}
// -repl suffix will be added by replicaDNSName
clusterNameWithPoolerSuffix := c.connectionPoolerName(Master)
if role == Master {
dnsString = c.masterDNSName(clusterNameWithPoolerSuffix)
} else {
dnsString = c.replicaDNSName(clusterNameWithPoolerSuffix)
}
annotations[constants.ZalandoDNSNameAnnotation] = dnsString
}
if len(annotations) == 0 {
return nil
}
return annotations
}
func (c *Cluster) shouldCreateLoadBalancerForPoolerService(role PostgresRole, spec *acidv1.PostgresSpec) bool {
switch role {

View File

@ -1901,6 +1901,28 @@ func (c *Cluster) configureLoadBalanceService(serviceSpec *v1.ServiceSpec, sourc
}
func (c *Cluster) generateServiceAnnotations(role PostgresRole, spec *acidv1.PostgresSpec) map[string]string {
annotations := c.getCustomServiceAnnotations(role, spec)
if c.shouldCreateLoadBalancerForService(role, spec) {
dnsName := c.dnsName(role)
// Just set ELB Timeout annotation with default value, if it does not
// have a custom value
if _, ok := annotations[constants.ElbTimeoutAnnotationName]; !ok {
annotations[constants.ElbTimeoutAnnotationName] = constants.ElbTimeoutAnnotationValue
}
// External DNS name annotation is not customizable
annotations[constants.ZalandoDNSNameAnnotation] = dnsName
}
if len(annotations) == 0 {
return nil
}
return annotations
}
func (c *Cluster) getCustomServiceAnnotations(role PostgresRole, spec *acidv1.PostgresSpec) map[string]string {
annotations := make(map[string]string)
maps.Copy(annotations, c.OpConfig.CustomServiceAnnotations)
@ -1915,22 +1937,6 @@ func (c *Cluster) generateServiceAnnotations(role PostgresRole, spec *acidv1.Pos
}
}
if c.shouldCreateLoadBalancerForService(role, spec) {
dnsName := c.dnsName(role)
// Just set ELB Timeout annotation with default value, if it does not
// have a cutom value
if _, ok := annotations[constants.ElbTimeoutAnnotationName]; !ok {
annotations[constants.ElbTimeoutAnnotationName] = constants.ElbTimeoutAnnotationValue
}
// External DNS name annotation is not customizable
annotations[constants.ZalandoDNSNameAnnotation] = dnsName
}
if len(annotations) == 0 {
return nil
}
return annotations
}

View File

@ -509,9 +509,9 @@ func (c *Cluster) dnsName(role PostgresRole) string {
var dnsString, oldDnsString string
if role == Master {
dnsString = c.masterDNSName()
dnsString = c.masterDNSName(c.Name)
} else {
dnsString = c.replicaDNSName()
dnsString = c.replicaDNSName(c.Name)
}
// if cluster name starts with teamID we might need to provide backwards compatibility
@ -528,17 +528,17 @@ func (c *Cluster) dnsName(role PostgresRole) string {
return dnsString
}
func (c *Cluster) masterDNSName() string {
func (c *Cluster) masterDNSName(clusterName string) string {
return strings.ToLower(c.OpConfig.MasterDNSNameFormat.Format(
"cluster", c.Name,
"cluster", clusterName,
"namespace", c.Namespace,
"team", c.teamName(),
"hostedzone", c.OpConfig.DbHostedZone))
}
func (c *Cluster) replicaDNSName() string {
func (c *Cluster) replicaDNSName(clusterName string) string {
return strings.ToLower(c.OpConfig.ReplicaDNSNameFormat.Format(
"cluster", c.Name,
"cluster", clusterName,
"namespace", c.Namespace,
"team", c.teamName(),
"hostedzone", c.OpConfig.DbHostedZone))

View File

@ -2,6 +2,7 @@ package constants
// Connection pooler specific constants
const (
ConnectionPoolerResourceSuffix = "pooler"
ConnectionPoolerUserName = "pooler"
ConnectionPoolerSchemaName = "pooler"
ConnectionPoolerDefaultType = "pgbouncer"