Skip to content

Commit 9a900ed

Browse files
Jonathan S. Katzjkatz
authored andcommitted
Allow CPU/Memory resources to be set one-off for pgBackRest repositories
There are cases where it may be helpful to control the container resource utilization for the pgBackRest repository Deployment that comes with every PostgreSQL cluster that is managed by the PostgreSQL Operato . This modifies the pgcluster CRD to store the resource values pertaining to the pgBackRest repository. This also adds new flags to the PostgreSQL Operator client to manage the CPU / memory resources, including: - `pgo create cluster --pgbackrest-cpu` - `pgo create cluster --pgbackrest-memory` - `pgo update cluster --pgbackrest-cpu` - `pgo update cluster --pgbackrest-memory` This also fixes a bug with rotating the pgbouncer system account password, where all pgBouncer Pods would be checked for propagation vs. just the pgBouncer Pods for the specific cluster. Also there are some general code cleanups.
1 parent 43f5dc8 commit 9a900ed

File tree

15 files changed

+239
-41
lines changed

15 files changed

+239
-41
lines changed

apis/crunchydata.com/v1/cluster.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,9 @@ type PgclusterSpec struct {
8181
// https://www.postgresql.org/docs/current/kernel-resources.html#LINUX-MEMORY-OVERCOMMIT
8282
// https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/#how-pods-with-resource-limits-are-run
8383
Resources v1.ResourceList `json:"resources"`
84+
// BackrestResources, if specified, contains the container request resources
85+
// for the pgBackRest Deployment for this PostgreSQL cluster
86+
BackrestResources v1.ResourceList `json:"backrestResources"`
8487
// PgBouncerResources, if specified, contains the container request resources
8588
// for any pgBouncer Deployments that are part of a PostgreSQL cluster
8689
PgBouncerResources v1.ResourceList `json:"pgBouncerResources"`

apis/crunchydata.com/v1/zz_generated.deepcopy.go

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apiserver/clusterservice/clusterimpl.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,20 @@ func CreateCluster(request *msgs.CreateClusterRequest, ns, pgouser string) msgs.
571571
return resp
572572
}
573573

574+
// similarly, if any of the pgBackRest repo CPU / Memory values have been set,
575+
// evaluate those as well
576+
if err := apiserver.ValidateQuantity(request.BackrestCPURequest); err != nil {
577+
resp.Status.Code = msgs.Error
578+
resp.Status.Msg = fmt.Sprintf(apiserver.ErrMessageCPURequest, request.BackrestCPURequest, err.Error())
579+
return resp
580+
}
581+
582+
if err := apiserver.ValidateQuantity(request.BackrestMemoryRequest); err != nil {
583+
resp.Status.Code = msgs.Error
584+
resp.Status.Msg = fmt.Sprintf(apiserver.ErrMessageMemoryRequest, request.BackrestMemoryRequest, err.Error())
585+
return resp
586+
}
587+
574588
// similarly, if any of the pgBouncer CPU / Memory values have been set,
575589
// evaluate those as well
576590
if err := apiserver.ValidateQuantity(request.PgBouncerCPURequest); err != nil {
@@ -990,6 +1004,7 @@ func validateConfigPolicies(clusterName, PoliciesFlag, ns string) error {
9901004
func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabelsMap map[string]string, ns string) *crv1.Pgcluster {
9911005

9921006
spec := crv1.PgclusterSpec{
1007+
BackrestResources: v1.ResourceList{},
9931008
PgBouncerResources: v1.ResourceList{},
9941009
Resources: v1.ResourceList{},
9951010
}
@@ -1012,6 +1027,20 @@ func getClusterParams(request *msgs.CreateClusterRequest, name string, userLabel
10121027
spec.Resources[v1.ResourceMemory] = quantity
10131028
}
10141029

1030+
// similarly, if there are any overriding pgBackRest repository container
1031+
// resource request values, set them here
1032+
if request.BackrestCPURequest != "" {
1033+
// as this was already validated, we can ignore the error
1034+
quantity, _ := resource.ParseQuantity(request.BackrestCPURequest)
1035+
spec.BackrestResources[v1.ResourceCPU] = quantity
1036+
}
1037+
1038+
if request.BackrestMemoryRequest != "" {
1039+
// as this was already validated, we can ignore the error
1040+
quantity, _ := resource.ParseQuantity(request.BackrestMemoryRequest)
1041+
spec.BackrestResources[v1.ResourceMemory] = quantity
1042+
}
1043+
10151044
// similarly, if there are any overriding pgBouncer container resource request
10161045
// values, set them here
10171046
if request.PgBouncerCPURequest != "" {
@@ -1503,6 +1532,20 @@ func UpdateCluster(request *msgs.UpdateClusterRequest) msgs.UpdateClusterRespons
15031532
return response
15041533
}
15051534

1535+
// similarly, if any of the pgBackRest repo CPU / Memory values have been set,
1536+
// evaluate those as well
1537+
if err := apiserver.ValidateQuantity(request.BackrestCPURequest); err != nil {
1538+
response.Status.Code = msgs.Error
1539+
response.Status.Msg = fmt.Sprintf(apiserver.ErrMessageCPURequest, request.BackrestCPURequest, err.Error())
1540+
return response
1541+
}
1542+
1543+
if err := apiserver.ValidateQuantity(request.BackrestMemoryRequest); err != nil {
1544+
response.Status.Code = msgs.Error
1545+
response.Status.Msg = fmt.Sprintf(apiserver.ErrMessageMemoryRequest, request.BackrestMemoryRequest, err.Error())
1546+
return response
1547+
}
1548+
15061549
// validate the storage type for each specified tablespace actually exists.
15071550
// if a PVCSize is passed in, also validate that it follows the Kubernetes
15081551
// format
@@ -1608,6 +1651,23 @@ func UpdateCluster(request *msgs.UpdateClusterRequest) msgs.UpdateClusterRespons
16081651
cluster.Spec.Resources[v1.ResourceMemory] = quantity
16091652
}
16101653

1654+
// ensure there is a value for BackrestResources
1655+
if cluster.Spec.BackrestResources == nil {
1656+
cluster.Spec.BackrestResources = v1.ResourceList{}
1657+
}
1658+
1659+
// if the pgBackRest repository CPU or memory values have been modified,
1660+
// update the values in the cluster CRD
1661+
if request.BackrestCPURequest != "" {
1662+
quantity, _ := resource.ParseQuantity(request.BackrestCPURequest)
1663+
cluster.Spec.BackrestResources[v1.ResourceCPU] = quantity
1664+
}
1665+
1666+
if request.BackrestMemoryRequest != "" {
1667+
quantity, _ := resource.ParseQuantity(request.BackrestMemoryRequest)
1668+
cluster.Spec.BackrestResources[v1.ResourceMemory] = quantity
1669+
}
1670+
16111671
// extract the parameters for the TablespaceMounts and put them in the
16121672
// format that is required by the pgcluster CRD
16131673
for _, tablespace := range request.Tablespaces {

apiservermsgs/clustermsgs.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ type CreateClusterRequest struct {
122122
// be requested for deploying pgBouncer instances. Defaults to the server
123123
// specified default
124124
PgBouncerMemoryRequest string
125+
// BackrestCPURequest, if specified, is the value of how much CPU should be
126+
// requested the pgBackRest repository. Defaults to not being requested
127+
BackrestCPURequest string
128+
// BackrestMemoryRequest, if specified, is the value of how much RAM should
129+
// be requested for the pgBackRest repository. Defaults to the server
130+
// specified default
131+
BackrestMemoryRequest string
125132
// BackrestStorageConfig sets the storage configuration to use for the
126133
// pgBackRest local repository. This overrides the value in pgo.yaml, though
127134
// the value of BackrestPVCSize can override the PVC size set in this
@@ -292,6 +299,12 @@ type UpdateClusterRequest struct {
292299
Namespace string
293300
AllFlag bool
294301
Autofail UpdateClusterAutofailStatus
302+
// BackrestCPURequest, if specified, is the value of how much CPU should be
303+
// requested the pgBackRest repository.
304+
BackrestCPURequest string
305+
// BackrestMemoryRequest, if specified, is the value of how much RAM should
306+
// be requested for the pgBackRest repository.
307+
BackrestMemoryRequest string
295308
// CPURequest is the value of how much CPU should be requested for deploying
296309
// the PostgreSQL cluster
297310
CPURequest string

controller/pgcluster/pgclustercontroller.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
crv1 "github.com/crunchydata/postgres-operator/apis/crunchydata.com/v1"
2525
"github.com/crunchydata/postgres-operator/config"
2626
"github.com/crunchydata/postgres-operator/kubeapi"
27+
backrestoperator "github.com/crunchydata/postgres-operator/operator/backrest"
2728
clusteroperator "github.com/crunchydata/postgres-operator/operator/cluster"
2829
informers "github.com/crunchydata/postgres-operator/pkg/generated/informers/externalversions/crunchydata.com/v1"
2930
"github.com/crunchydata/postgres-operator/util"
@@ -186,6 +187,16 @@ func (c *Controller) onUpdate(oldObj, newObj interface{}) {
186187
}
187188
}
188189

190+
// see if any of the pgBackRest repository resource values have changed, and
191+
// if so, update them
192+
if oldcluster.Spec.BackrestResources[v1.ResourceCPU] != newcluster.Spec.BackrestResources[v1.ResourceCPU] ||
193+
oldcluster.Spec.BackrestResources[v1.ResourceMemory] != newcluster.Spec.BackrestResources[v1.ResourceMemory] {
194+
if err := backrestoperator.UpdateResources(c.PgclusterClientset, c.PgclusterConfig, newcluster); err != nil {
195+
log.Error(err)
196+
return
197+
}
198+
}
199+
189200
// if we are not in a standby state, check to see if the tablespaces have
190201
// differed, and if so, add the additional volumes to the primary and replicas
191202
if !reflect.DeepEqual(oldcluster.Spec.TablespaceMounts, newcluster.Spec.TablespaceMounts) {

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ pgo create cluster [flags]
3333
--password-length int If no password is supplied, sets the length of the automatically generated password. Defaults to the value set on the server.
3434
--password-replication string The password to use for the PostgreSQL replication user.
3535
--password-superuser string The password to use for the PostgreSQL superuser.
36+
--pgbackrest-cpu string Set the number of millicores to request for CPU for the pgBackRest repository. Defaults to being unset.
37+
--pgbackrest-memory string Set the amount of Memory to request for the pgBackRest repository. Defaults to server value (48Mi).
3638
--pgbackrest-pvc-size string The size of the PVC capacity for the pgBackRest repository. Overrides the value set in the storage class. This is ignored if the storage type of "local" is not used. Must follow the standard Kubernetes format, e.g. "10.1Gi"
3739
--pgbackrest-repo-path string The pgBackRest repository path that should be utilized instead of the default. Required for standby
3840
clusters to define the location of an existing pgBackRest repository.

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

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -21,27 +21,29 @@ pgo update cluster [flags]
2121
### Options
2222

2323
```
24-
--all all resources.
25-
--cpu string Set the number of millicores to request for the CPU, e.g. "100m" or "0.1". Overrides the value in "resources-config"
26-
--disable-autofail Disables autofail capabitilies in the cluster.
27-
--disable-standby Disables standby mode if enabled in the cluster(s) specified.
28-
--enable-autofail Enables autofail capabitilies in the cluster.
29-
-h, --help help for cluster
30-
--memory string Set the amount of RAM to request, e.g. 1GiB. Overrides the value in "resources-config"
31-
--no-prompt No command line confirmation.
32-
--promote-standby Enables standby mode in the cluster(s) specified.
33-
-s, --selector string The selector to use for cluster filtering.
34-
--shutdown Shutdown the database cluster if it is currently running.
35-
--startup Restart the database cluster if it is currently shutdown.
36-
--tablespace strings Add a PostgreSQL tablespace on the cluster, e.g. "name=ts1:storageconfig=nfsstorage". The format is a key/value map that is delimited by "=" and separated by ":". The following parameters are available:
37-
38-
- name (required): the name of the PostgreSQL tablespace
39-
- storageconfig (required): the storage configuration to use, as specified in the list available in the "pgo-config" ConfigMap (aka "pgo.yaml")
40-
- pvcsize: the size of the PVC capacity, which overrides the value set in the specified storageconfig. Follows the Kubernetes quantity format.
41-
42-
For example, to create a tablespace with the NFS storage configuration with a PVC of size 10GiB:
43-
44-
--tablespace=name=ts1:storageconfig=nfsstorage:pvcsize=10Gi
24+
--all all resources.
25+
--cpu string Set the number of millicores to request for the CPU, e.g. "100m" or "0.1". Overrides the value in "resources-config"
26+
--disable-autofail Disables autofail capabitilies in the cluster.
27+
--disable-standby Disables standby mode if enabled in the cluster(s) specified.
28+
--enable-autofail Enables autofail capabitilies in the cluster.
29+
-h, --help help for cluster
30+
--memory string Set the amount of RAM to request, e.g. 1GiB. Overrides the value in "resources-config"
31+
--no-prompt No command line confirmation.
32+
--pgbackrest-cpu string Set the number of millicores to request for CPU for the pgBackRest repository.
33+
--pgbackrest-memory string Set the amount of Memory to request for the pgBackRest repository.
34+
--promote-standby Enables standby mode in the cluster(s) specified.
35+
-s, --selector string The selector to use for cluster filtering.
36+
--shutdown Shutdown the database cluster if it is currently running.
37+
--startup Restart the database cluster if it is currently shutdown.
38+
--tablespace strings Add a PostgreSQL tablespace on the cluster, e.g. "name=ts1:storageconfig=nfsstorage". The format is a key/value map that is delimited by "=" and separated by ":". The following parameters are available:
39+
40+
- name (required): the name of the PostgreSQL tablespace
41+
- storageconfig (required): the storage configuration to use, as specified in the list available in the "pgo-config" ConfigMap (aka "pgo.yaml")
42+
- pvcsize: the size of the PVC capacity, which overrides the value set in the specified storageconfig. Follows the Kubernetes quantity format.
43+
44+
For example, to create a tablespace with the NFS storage configuration with a PVC of size 10GiB:
45+
46+
--tablespace=name=ts1:storageconfig=nfsstorage:pvcsize=10Gi
4547
```
4648

4749
### Options inherited from parent commands
@@ -61,4 +63,4 @@ pgo update cluster [flags]
6163

6264
* [pgo update](/pgo-client/reference/pgo_update/) - Update a pgouser, pgorole, or cluster
6365

64-
###### Auto generated by spf13/cobra on 28-Mar-2020
66+
###### Auto generated by spf13/cobra on 6-Apr-2020

operator/backrest/repo.go

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,14 @@ import (
2727
"github.com/crunchydata/postgres-operator/operator"
2828
"github.com/crunchydata/postgres-operator/operator/pvc"
2929
"github.com/crunchydata/postgres-operator/util"
30+
3031
log "github.com/sirupsen/logrus"
31-
v1 "k8s.io/api/apps/v1"
32-
corev1 "k8s.io/api/core/v1"
32+
appsv1 "k8s.io/api/apps/v1"
33+
v1 "k8s.io/api/core/v1"
3334
"k8s.io/client-go/kubernetes"
35+
"k8s.io/client-go/rest"
3436
)
3537

36-
const BackrestRepoServiceName = "%s-backrest-shared-repo"
37-
const BackrestRepoPVCName = "%s-pgbr-repo"
38-
3938
type RepoDeploymentTemplateFields struct {
4039
SecurityContext string
4140
PGOImagePrefix string
@@ -68,8 +67,8 @@ func CreateRepoDeployment(clientset *kubernetes.Clientset, namespace string, clu
6867

6968
var b bytes.Buffer
7069

71-
repoName := fmt.Sprintf(BackrestRepoPVCName, cluster.Name)
72-
serviceName := fmt.Sprintf(BackrestRepoServiceName, cluster.Name)
70+
repoName := fmt.Sprintf(util.BackrestRepoPVCName, cluster.Name)
71+
serviceName := fmt.Sprintf(util.BackrestRepoServiceName, cluster.Name)
7372

7473
//create backrest repo service
7574
serviceFields := RepoServiceTemplateFields{
@@ -103,7 +102,7 @@ func CreateRepoDeployment(clientset *kubernetes.Clientset, namespace string, clu
103102
fields := RepoDeploymentTemplateFields{
104103
PGOImagePrefix: operator.Pgo.Pgo.PGOImagePrefix,
105104
PGOImageTag: operator.Pgo.Pgo.PGOImageTag,
106-
ContainerResources: "",
105+
ContainerResources: operator.GetResourcesJSON(cluster.Spec.BackrestResources),
107106
BackrestRepoClaimName: repoName,
108107
SshdSecretsName: "pgo-backrest-repo-config",
109108
PGbackrestDBHost: cluster.Name,
@@ -135,7 +134,7 @@ func CreateRepoDeployment(clientset *kubernetes.Clientset, namespace string, clu
135134
config.PgoBackrestRepoTemplate.Execute(os.Stdout, fields)
136135
}
137136

138-
deployment := v1.Deployment{}
137+
deployment := appsv1.Deployment{}
139138
err = json.Unmarshal(b.Bytes(), &deployment)
140139
if err != nil {
141140
log.Error("error unmarshalling backrest repo json into Deployment " + err.Error())
@@ -152,6 +151,52 @@ func CreateRepoDeployment(clientset *kubernetes.Clientset, namespace string, clu
152151

153152
}
154153

154+
// UpdateResources updates the pgBackRest repository Deployment to reflect any
155+
// resource updates
156+
func UpdateResources(clientset *kubernetes.Clientset, restConfig *rest.Config, cluster *crv1.Pgcluster) error {
157+
// get a list of all of the instance deployments for the cluster
158+
deployment, err := operator.GetBackrestDeployment(clientset, cluster)
159+
160+
if err != nil {
161+
return err
162+
}
163+
164+
// iterate through each PostgreSQL instance deployment and update the
165+
// resource values for the pgBackRest repository container. This is the first
166+
// container
167+
requestResourceList := v1.ResourceList{}
168+
169+
// if there is a request resource list available already, use that one
170+
// NOTE: this works as the "database" container is always first
171+
if deployment.Spec.Template.Spec.Containers[0].Resources.Requests != nil {
172+
requestResourceList = deployment.Spec.Template.Spec.Containers[0].Resources.Requests
173+
}
174+
175+
// handle the CPU update
176+
if request, ok := cluster.Spec.BackrestResources[v1.ResourceCPU]; ok {
177+
requestResourceList[v1.ResourceCPU] = request
178+
} else {
179+
delete(requestResourceList, v1.ResourceCPU)
180+
}
181+
182+
// handle the memory update
183+
if request, ok := cluster.Spec.BackrestResources[v1.ResourceMemory]; ok {
184+
requestResourceList[v1.ResourceMemory] = request
185+
} else {
186+
delete(requestResourceList, v1.ResourceMemory)
187+
}
188+
189+
// update the requests resourcelist
190+
deployment.Spec.Template.Spec.Containers[0].Resources.Requests = requestResourceList
191+
192+
// update the deployment with the new values
193+
if err := kubeapi.UpdateDeployment(clientset, deployment); err != nil {
194+
return err
195+
}
196+
197+
return nil
198+
}
199+
155200
func createService(clientset *kubernetes.Clientset, fields *RepoServiceTemplateFields, namespace string) error {
156201
var err error
157202

@@ -170,7 +215,7 @@ func createService(clientset *kubernetes.Clientset, fields *RepoServiceTemplateF
170215
config.PgoBackrestRepoServiceTemplate.Execute(os.Stdout, fields)
171216
}
172217

173-
s := corev1.Service{}
218+
s := v1.Service{}
174219
err = json.Unmarshal(b.Bytes(), &s)
175220
if err != nil {
176221
log.Error("error unmarshalling repo service json into repo Service " + err.Error())

0 commit comments

Comments
 (0)