add pooler sidecars

This commit is contained in:
murtll 2024-08-23 20:01:13 +07:00
parent cc9074c184
commit 6522461c47
7 changed files with 108 additions and 7 deletions

View File

@ -173,6 +173,12 @@ spec:
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
schema:
type: string
sidecars:
type: array
nullable: true
items:
type: object
x-kubernetes-preserve-unknown-fields: true
user:
type: string
databases:

View File

@ -171,6 +171,12 @@ spec:
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
schema:
type: string
sidecars:
type: array
nullable: true
items:
type: object
x-kubernetes-preserve-unknown-fields: true
user:
type: string
databases:

View File

@ -275,6 +275,16 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
"schema": {
Type: "string",
},
"sidecars": {
Type: "array",
Nullable: true,
Items: &apiextv1.JSONSchemaPropsOrArray{
Schema: &apiextv1.JSONSchemaProps{
Type: "object",
XPreserveUnknownFields: util.True(),
},
},
},
"user": {
Type: "string",
},

View File

@ -241,12 +241,13 @@ type PostgresStatus struct {
// makes sense to expose. E.g. pool size (min/max boundaries), max client
// connections etc.
type ConnectionPooler struct {
NumberOfInstances *int32 `json:"numberOfInstances,omitempty"`
Schema string `json:"schema,omitempty"`
User string `json:"user,omitempty"`
Mode string `json:"mode,omitempty"`
DockerImage string `json:"dockerImage,omitempty"`
MaxDBConnections *int32 `json:"maxDBConnections,omitempty"`
NumberOfInstances *int32 `json:"numberOfInstances,omitempty"`
Schema string `json:"schema,omitempty"`
User string `json:"user,omitempty"`
Mode string `json:"mode,omitempty"`
DockerImage string `json:"dockerImage,omitempty"`
MaxDBConnections *int32 `json:"maxDBConnections,omitempty"`
Sidecars []Sidecar `json:"sidecars,omitempty"`
*Resources `json:"resources,omitempty"`
}

View File

@ -111,6 +111,13 @@ func (in *ConnectionPooler) DeepCopyInto(out *ConnectionPooler) {
*out = new(int32)
**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 {
in, out := &in.Resources, &out.Resources
*out = new(Resources)

View File

@ -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:
// 1. Add environment variables to tell pgBouncer where to find the TLS certificates
// 2. Reference the secret in a volume
@ -403,7 +415,7 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
},
Spec: v1.PodSpec{
TerminationGracePeriodSeconds: &gracePeriod,
Containers: []v1.Container{poolerContainer},
Containers: append([]v1.Container{poolerContainer}, sidecars...),
Tolerations: tolerationsSpec,
Volumes: poolerVolumes,
SecurityContext: &securityContext,

View File

@ -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 {
poolerServiceAccount := podSpec.Spec.ServiceAccountName