add pooler sidecars
This commit is contained in:
		
							parent
							
								
									cc9074c184
								
							
						
					
					
						commit
						6522461c47
					
				|  | @ -173,6 +173,12 @@ spec: | ||||||
|                             pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' |                             pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' | ||||||
|                   schema: |                   schema: | ||||||
|                     type: string |                     type: string | ||||||
|  |                   sidecars: | ||||||
|  |                     type: array | ||||||
|  |                     nullable: true | ||||||
|  |                     items: | ||||||
|  |                       type: object | ||||||
|  |                       x-kubernetes-preserve-unknown-fields: true | ||||||
|                   user: |                   user: | ||||||
|                     type: string |                     type: string | ||||||
|               databases: |               databases: | ||||||
|  |  | ||||||
|  | @ -171,6 +171,12 @@ spec: | ||||||
|                             pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' |                             pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' | ||||||
|                   schema: |                   schema: | ||||||
|                     type: string |                     type: string | ||||||
|  |                   sidecars: | ||||||
|  |                     type: array | ||||||
|  |                     nullable: true | ||||||
|  |                     items: | ||||||
|  |                       type: object | ||||||
|  |                       x-kubernetes-preserve-unknown-fields: true | ||||||
|                   user: |                   user: | ||||||
|                     type: string |                     type: string | ||||||
|               databases: |               databases: | ||||||
|  |  | ||||||
|  | @ -275,6 +275,16 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ | ||||||
| 							"schema": { | 							"schema": { | ||||||
| 								Type: "string", | 								Type: "string", | ||||||
| 							}, | 							}, | ||||||
|  | 							"sidecars": { | ||||||
|  | 								Type:     "array", | ||||||
|  | 								Nullable: true, | ||||||
|  | 								Items: &apiextv1.JSONSchemaPropsOrArray{ | ||||||
|  | 									Schema: &apiextv1.JSONSchemaProps{ | ||||||
|  | 										Type:                   "object", | ||||||
|  | 										XPreserveUnknownFields: util.True(), | ||||||
|  | 									}, | ||||||
|  | 								}, | ||||||
|  | 							}, | ||||||
| 							"user": { | 							"user": { | ||||||
| 								Type: "string", | 								Type: "string", | ||||||
| 							}, | 							}, | ||||||
|  |  | ||||||
|  | @ -241,12 +241,13 @@ type PostgresStatus struct { | ||||||
| // makes sense to expose. E.g. pool size (min/max boundaries), max client
 | // makes sense to expose. E.g. pool size (min/max boundaries), max client
 | ||||||
| // connections etc.
 | // connections etc.
 | ||||||
| type ConnectionPooler struct { | type ConnectionPooler struct { | ||||||
| 	NumberOfInstances *int32 `json:"numberOfInstances,omitempty"` | 	NumberOfInstances *int32    `json:"numberOfInstances,omitempty"` | ||||||
| 	Schema            string `json:"schema,omitempty"` | 	Schema            string    `json:"schema,omitempty"` | ||||||
| 	User              string `json:"user,omitempty"` | 	User              string    `json:"user,omitempty"` | ||||||
| 	Mode              string `json:"mode,omitempty"` | 	Mode              string    `json:"mode,omitempty"` | ||||||
| 	DockerImage       string `json:"dockerImage,omitempty"` | 	DockerImage       string    `json:"dockerImage,omitempty"` | ||||||
| 	MaxDBConnections  *int32 `json:"maxDBConnections,omitempty"` | 	MaxDBConnections  *int32    `json:"maxDBConnections,omitempty"` | ||||||
|  | 	Sidecars          []Sidecar `json:"sidecars,omitempty"` | ||||||
| 
 | 
 | ||||||
| 	*Resources `json:"resources,omitempty"` | 	*Resources `json:"resources,omitempty"` | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -111,6 +111,13 @@ func (in *ConnectionPooler) DeepCopyInto(out *ConnectionPooler) { | ||||||
| 		*out = new(int32) | 		*out = new(int32) | ||||||
| 		**out = **in | 		**out = **in | ||||||
| 	} | 	} | ||||||
|  | 	if in.Sidecars != nil { | ||||||
|  | 		in, out := &in.Sidecars, &out.Sidecars | ||||||
|  | 		*out = make([]Sidecar, len(*in)) | ||||||
|  | 		for i := range *in { | ||||||
|  | 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
| 	if in.Resources != nil { | 	if in.Resources != nil { | ||||||
| 		in, out := &in.Resources, &out.Resources | 		in, out := &in.Resources, &out.Resources | ||||||
| 		*out = new(Resources) | 		*out = new(Resources) | ||||||
|  |  | ||||||
|  | @ -342,6 +342,18 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) ( | ||||||
| 		}, | 		}, | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	sidecars := []v1.Container{} | ||||||
|  | 	if connectionPoolerSpec.Sidecars != nil && len(connectionPoolerSpec.Sidecars) > 0 { | ||||||
|  | 		sidecars, err = c.generateSidecarContainers( | ||||||
|  | 			connectionPoolerSpec.Sidecars, | ||||||
|  | 			makeDefaultConnectionPoolerResources(&c.OpConfig), | ||||||
|  | 			0, | ||||||
|  | 		) | ||||||
|  | 		if err != nil { | ||||||
|  | 			return nil, fmt.Errorf("could not generate pooler sidecar containers: %v", err) | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	// If the cluster has custom TLS certificates configured, we do the following:
 | 	// If the cluster has custom TLS certificates configured, we do the following:
 | ||||||
| 	//  1. Add environment variables to tell pgBouncer where to find the TLS certificates
 | 	//  1. Add environment variables to tell pgBouncer where to find the TLS certificates
 | ||||||
| 	//  2. Reference the secret in a volume
 | 	//  2. Reference the secret in a volume
 | ||||||
|  | @ -403,7 +415,7 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) ( | ||||||
| 		}, | 		}, | ||||||
| 		Spec: v1.PodSpec{ | 		Spec: v1.PodSpec{ | ||||||
| 			TerminationGracePeriodSeconds: &gracePeriod, | 			TerminationGracePeriodSeconds: &gracePeriod, | ||||||
| 			Containers:                    []v1.Container{poolerContainer}, | 			Containers:                    append([]v1.Container{poolerContainer}, sidecars...), | ||||||
| 			Tolerations:                   tolerationsSpec, | 			Tolerations:                   tolerationsSpec, | ||||||
| 			Volumes:                       poolerVolumes, | 			Volumes:                       poolerVolumes, | ||||||
| 			SecurityContext:               &securityContext, | 			SecurityContext:               &securityContext, | ||||||
|  |  | ||||||
|  | @ -869,6 +869,65 @@ func TestConnectionPoolerDeploymentSpec(t *testing.T) { | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | func TestConnectionPoolerSidecars (t *testing.T) { | ||||||
|  | 	var cluster = New( | ||||||
|  | 		Config{ | ||||||
|  | 			OpConfig: config.Config{ | ||||||
|  | 				ProtectedRoles: []string{"admin"}, | ||||||
|  | 				Auth: config.Auth{ | ||||||
|  | 					SuperUsername:       superUserName, | ||||||
|  | 					ReplicationUsername: replicationUserName, | ||||||
|  | 				}, | ||||||
|  | 				ConnectionPooler: config.ConnectionPooler{ | ||||||
|  | 					ConnectionPoolerDefaultCPURequest:    "100m", | ||||||
|  | 					ConnectionPoolerDefaultCPULimit:      "100m", | ||||||
|  | 					ConnectionPoolerDefaultMemoryRequest: "100Mi", | ||||||
|  | 					ConnectionPoolerDefaultMemoryLimit:   "100Mi", | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, k8sutil.KubernetesClient{}, acidv1.Postgresql{}, logger, eventRecorder) | ||||||
|  | 	cluster.Statefulset = &appsv1.StatefulSet{ | ||||||
|  | 		ObjectMeta: metav1.ObjectMeta{ | ||||||
|  | 			Name: "test-sts", | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	cluster.ConnectionPooler = map[PostgresRole]*ConnectionPoolerObjects{ | ||||||
|  | 		Master: { | ||||||
|  | 			Deployment:     nil, | ||||||
|  | 			Service:        nil, | ||||||
|  | 			LookupFunction: true, | ||||||
|  | 			Name:           "", | ||||||
|  | 			Role:           Master, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 	cluster.Spec = acidv1.PostgresSpec{ | ||||||
|  | 		ConnectionPooler: &acidv1.ConnectionPooler{ | ||||||
|  | 			Sidecars: []acidv1.Sidecar{ | ||||||
|  | 				acidv1.Sidecar{ | ||||||
|  | 					Name:        "sidecar", | ||||||
|  | 					DockerImage: "image", | ||||||
|  | 					Env: []v1.EnvVar{ | ||||||
|  | 						{ | ||||||
|  | 							Name:  "SOME_VAR", | ||||||
|  | 							Value: "some-value", | ||||||
|  | 						}, | ||||||
|  | 					}, | ||||||
|  | 				}, | ||||||
|  | 			}, | ||||||
|  | 		}, | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	deployment, err := cluster.generateConnectionPoolerDeployment(cluster.ConnectionPooler[Master])  | ||||||
|  | 	assert.NoError(t, err) | ||||||
|  | 
 | ||||||
|  | 	containers := deployment.Spec.Template.Spec.Containers | ||||||
|  | 	assert.Equal(t, 2, len(containers), "wrong number of containers") | ||||||
|  | 	assert.Equal(t, "sidecar", containers[1].Name, "wrong name of sidecar") | ||||||
|  | 	assert.Equal(t, "image", containers[1].Image, "wrong image of sidecar") | ||||||
|  | 	assert.Equal(t, "SOME_VAR", containers[1].Env[0].Name, "wrong name of env var in sidecar") | ||||||
|  | 	assert.Equal(t, "some-value", containers[1].Env[0].Value, "wrong value of env var in sidecar") | ||||||
|  | } | ||||||
|  | 
 | ||||||
| func testServiceAccount(cluster *Cluster, podSpec *v1.PodTemplateSpec, role PostgresRole) error { | func testServiceAccount(cluster *Cluster, podSpec *v1.PodTemplateSpec, role PostgresRole) error { | ||||||
| 	poolerServiceAccount := podSpec.Spec.ServiceAccountName | 	poolerServiceAccount := podSpec.Spec.ServiceAccountName | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue