Skip to content

Commit eb6b893

Browse files
Jonathan S. Katzjkatz
authored andcommitted
Allow for user to specify memory limits for certain containers
With the work on memory management for this release, one of the discoveries made involved how the OOM killer on Kubelets would interact with PostgreSQL instances (as well as pgBackRest, pgBouncer) in ways that could lead to some undesired behavior. As such, the ability to implicitly set memory limits was removed for the time being. However, there may be cases where one may want to set a memory limit, along side a memory request + CPU request/limit to get a Guaranteed QoS on a Pod, perhaps for pgBouncer or pgBackRest. This patch allows for this via the `--enable-memory-limit` flag, specifically: pgo create cluster --enable-memory-limit pgo create cluster --enable-pgbackrest-memory-limit pgo create cluster --enable-pgbouncer-memory-limit pgo update cluster --enable-memory-limit pgo update cluster --disable-memory-limit pgo update cluster --enable-pgbackrest-memory-limit pgo update cluster --disable-pgbackrest-memory-limit pgo create pgbouncer --enable-memory-limit pgo update pgbouncer --enable-memory-limit pgo update pgbouncer --disable-memory-limit The net effect is that if a memory request is present (and all of PostgreSQL, pgBackRest, and pgBouncer have default values for memory requests), the limit will also be set if it is enabled. By default, the PostgreSQL Operator does not setting the memory limit per the behavioral issues mentioned above. If the memory limit is enabled, it is set to be identical to the memory request. This setting is also reactive, i.e. if you modify it in the CR directly, the PostgreSQL Operator will roll out the changes to the managed Pods. Issue: [ch8043]
1 parent 248745e commit eb6b893

File tree

23 files changed

+296
-101
lines changed

23 files changed

+296
-101
lines changed

apis/crunchydata.com/v1/cluster.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,9 +88,15 @@ type PgclusterSpec struct {
8888
// Now, for CPU, we set both the Request and the Limit, based on how
8989
// Kubernetes interacts with these parameters
9090
Resources v1.ResourceList `json:"resources"`
91+
// EnableMemoryLimit specifies whether or not the "Limit" for memory
92+
// should be set on the Pod. Defaults to false
93+
EnableMemoryLimit bool `json:"enableMemoryLimit"`
9194
// BackrestResources, if specified, contains the container request resources
9295
// for the pgBackRest Deployment for this PostgreSQL cluster
9396
BackrestResources v1.ResourceList `json:"backrestResources"`
97+
// EnableBackrestMemoryLimit specifies whether or not the "Limit" for memory
98+
// should be set on the Pod. Defaults to false
99+
EnableBackrestMemoryLimit bool `json:"enableBackrestMemoryLimit"`
94100
// PgBouncer contains all of the settings to properly maintain a pgBouncer
95101
// implementation
96102
PgBouncer PgBouncerSpec `json:"pgBouncer"`
@@ -172,6 +178,9 @@ type PodAntiAffinitySpec struct {
172178
// - what resources it should consume
173179
// - the total number of replicas
174180
type PgBouncerSpec struct {
181+
// EnableMemoryLimit specifies whether or not the "Limit" for memory
182+
// should be set on the Pod. Defaults to false
183+
EnableMemoryLimit bool `json:"enableMemoryLimit"`
175184
// Replicas represents the total number of Pods to deploy with pgBouncer,
176185
// which effectively enables/disables the pgBouncer.
177186
//

apiserver/clusterservice/clusterimpl.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1045,6 +1045,11 @@ func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabel
10451045
spec.Resources[v1.ResourceMemory] = apiserver.Pgo.Cluster.DefaultInstanceResourceMemory
10461046
}
10471047

1048+
// determine if we should apply a memory limit for the PostgreSQL clusters
1049+
if request.MemoryLimitStatus == msgs.MemoryLimitEnable {
1050+
spec.EnableMemoryLimit = true
1051+
}
1052+
10481053
// similarly, if there are any overriding pgBackRest repository container
10491054
// resource request values, set them here
10501055
if request.BackrestCPURequest != "" {
@@ -1061,6 +1066,11 @@ func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabel
10611066
spec.BackrestResources[v1.ResourceMemory] = apiserver.Pgo.Cluster.DefaultBackrestResourceMemory
10621067
}
10631068

1069+
// determine if we should apply a memory limit for the pgBackRest repository
1070+
if request.BackrestMemoryLimitStatus == msgs.MemoryLimitEnable {
1071+
spec.EnableBackrestMemoryLimit = true
1072+
}
1073+
10641074
// if the pgBouncer flag is set to true, indicate that the pgBouncer
10651075
// deployment should be made available in this cluster
10661076
if request.PgbouncerFlag {
@@ -1071,6 +1081,11 @@ func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabel
10711081
if request.PgBouncerReplicas > 0 {
10721082
spec.PgBouncer.Replicas = request.PgBouncerReplicas
10731083
}
1084+
1085+
// determine if we should apply a memory limit for the pgBouncer instances
1086+
if request.PgBouncerMemoryLimitStatus == msgs.MemoryLimitEnable {
1087+
spec.PgBouncer.EnableMemoryLimit = true
1088+
}
10741089
}
10751090

10761091
// similarly, if there are any overriding pgBouncer container resource request
@@ -1716,6 +1731,14 @@ func UpdateCluster(request *msgs.UpdateClusterRequest) msgs.UpdateClusterRespons
17161731
cluster.Spec.Resources[v1.ResourceMemory] = quantity
17171732
}
17181733

1734+
// determine if the memory limit should be applied to PostgreSQL instances
1735+
switch request.MemoryLimitStatus {
1736+
case msgs.MemoryLimitEnable:
1737+
cluster.Spec.EnableMemoryLimit = true
1738+
case msgs.MemoryLimitDisable:
1739+
cluster.Spec.EnableMemoryLimit = false
1740+
}
1741+
17191742
// ensure there is a value for BackrestResources
17201743
if cluster.Spec.BackrestResources == nil {
17211744
cluster.Spec.BackrestResources = v1.ResourceList{}
@@ -1733,6 +1756,14 @@ func UpdateCluster(request *msgs.UpdateClusterRequest) msgs.UpdateClusterRespons
17331756
cluster.Spec.BackrestResources[v1.ResourceMemory] = quantity
17341757
}
17351758

1759+
// determine if the memory limit should be applied to pgBackRest
1760+
switch request.BackrestMemoryLimitStatus {
1761+
case msgs.MemoryLimitEnable:
1762+
cluster.Spec.EnableBackrestMemoryLimit = true
1763+
case msgs.MemoryLimitDisable:
1764+
cluster.Spec.EnableBackrestMemoryLimit = false
1765+
}
1766+
17361767
// extract the parameters for the TablespaceMounts and put them in the
17371768
// format that is required by the pgcluster CRD
17381769
for _, tablespace := range request.Tablespaces {

apiserver/pgbouncerservice/pgbouncerimpl.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,11 @@ func CreatePgbouncer(request *msgs.CreatePgbouncerRequest, ns, pgouser string) m
117117
resources[v1.ResourceMemory] = apiserver.Pgo.Cluster.DefaultPgBouncerResourceMemory
118118
}
119119

120+
// determine if we should apply a memory limit for the pgBouncer instances
121+
if request.MemoryLimitStatus == msgs.MemoryLimitEnable {
122+
cluster.Spec.PgBouncer.EnableMemoryLimit = true
123+
}
124+
120125
cluster.Spec.PgBouncer.Resources = resources
121126

122127
// update the cluster CRD with these udpates. If there is an error
@@ -184,6 +189,9 @@ func DeletePgbouncer(request *msgs.DeletePgbouncerRequest, ns string) msgs.Delet
184189

185190
// Disable the pgBouncer Deploymnet, whcih means setting Replicas to 0
186191
cluster.Spec.PgBouncer.Replicas = 0
192+
// Set the MemoryLimit of pgBouncer to false as well, as this is the default
193+
// setting
194+
cluster.Spec.PgBouncer.EnableMemoryLimit = false
187195

188196
// update the cluster CRD with these udpates. If there is an error
189197
if err := kubeapi.Updatepgcluster(apiserver.RESTClient, &cluster, cluster.Name, request.Namespace); err != nil {
@@ -373,6 +381,14 @@ func UpdatePgBouncer(request *msgs.UpdatePgBouncerRequest, namespace, pgouser st
373381
}
374382
}
375383

384+
// determine if we should apply a memory limit for the pgBouncer instances
385+
switch request.MemoryLimitStatus {
386+
case msgs.MemoryLimitEnable:
387+
cluster.Spec.PgBouncer.EnableMemoryLimit = true
388+
case msgs.MemoryLimitDisable:
389+
cluster.Spec.PgBouncer.EnableMemoryLimit = false
390+
}
391+
376392
// apply the replica count number if there is a change, i.e. replicas is not
377393
// 0
378394
if request.Replicas > 0 {

apiservermsgs/clustermsgs.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,20 +121,35 @@ type CreateClusterRequest struct {
121121
// CPURequest is the value of how much CPU should be requested for deploying
122122
// the PostgreSQL cluster
123123
CPURequest string
124+
// MemoryLimitStatus determines whether or not the Kubernetes Resource Limit
125+
// for memory should be set on the request. Defaults to "do nothing", which
126+
// effectively disable setting the memory limit, which is currently the
127+
// preferred behavior
128+
MemoryLimitStatus MemoryLimitStatus
124129
// MemoryRequest is the value of how much RAM should be requested for
125130
// deploying the PostgreSQL cluster
126131
MemoryRequest string
127132
// PgBouncerCPURequest, if specified, is the value of how much CPU should be
128133
// requested for deploying pgBouncer instances. Defaults to not being
129134
// requested
130135
PgBouncerCPURequest string
136+
// PgBouncerMemoryLimitStatus determines whether or not the Kubernetes
137+
// Resource Limit for memory should be set on the request. Defaults to
138+
// "do nothing", which effectively disable setting the memory limit, which is
139+
// currently the preferred behavior
140+
PgBouncerMemoryLimitStatus MemoryLimitStatus
131141
// PgBouncerMemoryRequest, if specified, is the value of how much RAM should
132142
// be requested for deploying pgBouncer instances. Defaults to the server
133143
// specified default
134144
PgBouncerMemoryRequest string
135145
// BackrestCPURequest, if specified, is the value of how much CPU should be
136146
// requested the pgBackRest repository. Defaults to not being requested
137147
BackrestCPURequest string
148+
// BackrestMemoryLimitStatus determines whether or not the Kubernetes
149+
// Resource Limit for memory should be set on the request. Defaults to
150+
// "do nothing", which effectively disable setting the memory limit, which is
151+
// currently the preferred behavior
152+
BackrestMemoryLimitStatus MemoryLimitStatus
138153
// BackrestMemoryRequest, if specified, is the value of how much RAM should
139154
// be requested for the pgBackRest repository. Defaults to the server
140155
// specified default
@@ -312,12 +327,20 @@ type UpdateClusterRequest struct {
312327
// BackrestCPURequest, if specified, is the value of how much CPU should be
313328
// requested the pgBackRest repository.
314329
BackrestCPURequest string
330+
// BackrestMemoryLimitStatus determines whether or not the Kubernetes
331+
// Resource Limit for memory should be set on the request. Defaults to
332+
// "do nothing", which does nothing
333+
BackrestMemoryLimitStatus MemoryLimitStatus
315334
// BackrestMemoryRequest, if specified, is the value of how much RAM should
316335
// be requested for the pgBackRest repository.
317336
BackrestMemoryRequest string
318337
// CPURequest is the value of how much CPU should be requested for deploying
319338
// the PostgreSQL cluster
320339
CPURequest string
340+
// MemoryLimitStatus determines whether or not the Kubernetes Resource Limit
341+
// for memory should be set on the request. Defaults to "do nothing", which
342+
// does nothing
343+
MemoryLimitStatus MemoryLimitStatus
321344
// MemoryRequest is the value of how much RAM should be requested for
322345
// deploying the PostgreSQL cluster
323346
MemoryRequest string

apiservermsgs/common.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,3 +47,14 @@ type BasicAuthCredentials struct {
4747
func (b BasicAuthCredentials) HasUsernameAndPassword() bool {
4848
return len(b.Username) > 0 && len(b.Password) > 0
4949
}
50+
51+
// set the types for updating the memory limit
52+
type MemoryLimitStatus int
53+
54+
// set the different values around updating the "memory limit" parameter for
55+
// setting whether or not the memory limit for a Pod should be set
56+
const (
57+
MemoryLimitDoNothing MemoryLimitStatus = iota
58+
MemoryLimitEnable
59+
MemoryLimitDisable
60+
)

apiservermsgs/pgbouncermsgs.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ type CreatePgbouncerRequest struct {
2424
// requested for deploying pgBouncer instances. Defaults to not being
2525
// requested
2626
CPURequest string
27+
// MemoryLimitStatus determines whether or not the Kubernetes Resource Limit
28+
// for memory should be set on the request. Defaults to "do nothing", which
29+
// effectively disable setting the memory limit, which is currently the
30+
// preferred behavior
31+
MemoryLimitStatus MemoryLimitStatus
2732
// MemoryRequest, if specified, is the value of how much RAM should
2833
// be requested for deploying pgBouncer instances. Defaults to the server
2934
// specified default
@@ -150,6 +155,12 @@ type UpdatePgBouncerRequest struct {
150155
// requested
151156
CPURequest string
152157

158+
// MemoryLimitStatus determines whether or not the Kubernetes Resource Limit
159+
// for memory should be set on the request. Defaults to "do nothing", which
160+
// effectively disable setting the memory limit, which is currently the
161+
// preferred behavior
162+
MemoryLimitStatus MemoryLimitStatus
163+
153164
// MemoryRequest, if specified, is the value of how much RAM should
154165
// be requested for deploying pgBouncer instances. Defaults to the server
155166
// specified default

conf/postgres-operator/container-resources.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
{{ if or .RequestsMemory .RequestsCPU }}
22
"resources": {
3-
{{ if .RequestsCPU }}
43
"limits": {
5-
"cpu": "{{.RequestsCPU}}"
4+
{{ if .RequestsCPU }}
5+
"cpu": "{{.RequestsCPU}}"{{ if and .EnableMemoryLimit .RequestsMemory }},{{ end }}
6+
{{ end }}
7+
{{ if and .EnableMemoryLimit .RequestsMemory }}
8+
"memory": "{{.RequestsMemory}}"
9+
{{ end }}
610
},
7-
{{ end }}
811
"requests": {
912
{{ if .RequestsCPU }}
1013
"cpu": "{{.RequestsCPU}}"{{ if .RequestsMemory }},{{ end }}

controller/pgcluster/pgclustercontroller.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,8 @@ func (c *Controller) onUpdate(oldObj, newObj interface{}) {
212212

213213
// see if any of the resource values have changed, and if so, update them
214214
if oldcluster.Spec.Resources[v1.ResourceCPU] != newcluster.Spec.Resources[v1.ResourceCPU] ||
215-
oldcluster.Spec.Resources[v1.ResourceMemory] != newcluster.Spec.Resources[v1.ResourceMemory] {
215+
oldcluster.Spec.Resources[v1.ResourceMemory] != newcluster.Spec.Resources[v1.ResourceMemory] ||
216+
oldcluster.Spec.EnableMemoryLimit != newcluster.Spec.EnableMemoryLimit {
216217
if err := clusteroperator.UpdateResources(c.PgclusterClientset, c.PgclusterConfig, newcluster); err != nil {
217218
log.Error(err)
218219
return
@@ -222,7 +223,8 @@ func (c *Controller) onUpdate(oldObj, newObj interface{}) {
222223
// see if any of the pgBackRest repository resource values have changed, and
223224
// if so, update them
224225
if oldcluster.Spec.BackrestResources[v1.ResourceCPU] != newcluster.Spec.BackrestResources[v1.ResourceCPU] ||
225-
oldcluster.Spec.BackrestResources[v1.ResourceMemory] != newcluster.Spec.BackrestResources[v1.ResourceMemory] {
226+
oldcluster.Spec.BackrestResources[v1.ResourceMemory] != newcluster.Spec.BackrestResources[v1.ResourceMemory] ||
227+
oldcluster.Spec.EnableBackrestMemoryLimit != newcluster.Spec.EnableBackrestMemoryLimit {
226228
if err := backrestoperator.UpdateResources(c.PgclusterClientset, c.PgclusterConfig, newcluster); err != nil {
227229
log.Error(err)
228230
return

docs/content/pgo-client/reference/pgo_create_cluster.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ pgo create cluster [flags]
2525
--custom-config string The name of a configMap that holds custom PostgreSQL configuration files used to override defaults.
2626
-d, --database string If specified, sets the name of the initial database that is created for the user. Defaults to the value set in the PostgreSQL Operator configuration, or if that is not present, the name of the cluster
2727
--disable-autofail Disables autofail capabitilies in the cluster following cluster initialization.
28+
--enable-memory-limit Enables PostgreSQL instances to be set with a memory limit on top of the memory request.
29+
--enable-pgbackrest-memory-limit Enables the pgBackRest repository to be set with a memory limit on top of the memory request.
30+
--enable-pgbouncer-memory-limit Enables pgBouncer instances to be set with a memory limit on top of the memory request. This has no effect if there is no pgBouncer deployment.
2831
-h, --help help for cluster
2932
-l, --labels string The labels to apply to this cluster.
3033
--memory string Set the amount of RAM to request, e.g. 1GiB. Overrides the default server value.
@@ -100,4 +103,4 @@ pgo create cluster [flags]
100103

101104
* [pgo create](/pgo-client/reference/pgo_create/) - Create a Postgres Operator resource
102105

103-
###### Auto generated by spf13/cobra on 27-Apr-2020
106+
###### Auto generated by spf13/cobra on 29-Apr-2020

docs/content/pgo-client/reference/pgo_create_pgbouncer.md

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,12 @@ pgo create pgbouncer [flags]
1818
### Options
1919

2020
```
21-
--cpu string Set the number of millicores to request for CPU for pgBouncer. Defaults to being unset.
22-
-h, --help help for pgbouncer
23-
--memory string Set the amount of Memory to request for pgBouncer. Defaults to server value (24Mi).
24-
--replicas int32 Set the total number of pgBouncer instances to deploy. If not set, defaults to 1.
25-
-s, --selector string The selector to use for cluster filtering.
21+
--cpu string Set the number of millicores to request for CPU for pgBouncer. Defaults to being unset.
22+
--enable-memory-limit Enables pgBouncer instances to be set with a memory limit on top of the memory request.
23+
-h, --help help for pgbouncer
24+
--memory string Set the amount of Memory to request for pgBouncer. Defaults to server value (24Mi).
25+
--replicas int32 Set the total number of pgBouncer instances to deploy. If not set, defaults to 1.
26+
-s, --selector string The selector to use for cluster filtering.
2627
```
2728

2829
### Options inherited from parent commands
@@ -42,4 +43,4 @@ pgo create pgbouncer [flags]
4243

4344
* [pgo create](/pgo-client/reference/pgo_create/) - Create a Postgres Operator resource
4445

45-
###### Auto generated by spf13/cobra on 21-Apr-2020
46+
###### Auto generated by spf13/cobra on 29-Apr-2020

0 commit comments

Comments
 (0)