Add hugepages 2Mi and 1Gi fields to ResourceDescription and pass them to the statefulset (#2311)

* Add hugepages-2Mi and 1Gi to ResourceDescription type and crd (#1549, #1788)
* Add tests for hugepages resource requests/limits
* Add tests for hugepages resource requests/limits on sidecars, too
* Add docs for hugepages support
* Add link to kubernetes docs on hugepages
* Add tests for hugepages not being set on container if not requested in custom resource
* Add hugepages resources fields to manifest docs
* Add hugepages resources fields to complete manifest example
* Add hugepages resources fields to chart crd

---------

Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This commit is contained in:
Silas 2024-01-04 15:59:27 +01:00 committed by GitHub
parent 3ca26d0dc8
commit 9581ba969b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 247 additions and 9 deletions

View File

@ -441,6 +441,12 @@ spec:
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
# Note: the value specified here must not be zero or be higher # Note: the value specified here must not be zero or be higher
# than the corresponding limit. # than the corresponding limit.
hugepages-2Mi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
hugepages-1Gi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
requests: requests:
type: object type: object
properties: properties:
@ -450,6 +456,12 @@ spec:
memory: memory:
type: string type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
hugepages-2Mi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
hugepages-1Gi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
schedulerName: schedulerName:
type: string type: string
serviceAnnotations: serviceAnnotations:

View File

@ -359,6 +359,14 @@ CPU and memory requests for the Postgres container.
memory requests for the Postgres container. Optional, overrides the memory requests for the Postgres container. Optional, overrides the
`default_memory_request` operator configuration parameter. `default_memory_request` operator configuration parameter.
* **hugepages-2Mi**
hugepages-2Mi requests for the sidecar container.
Optional, defaults to not set.
* **hugepages-1Gi**
1Gi hugepages requests for the sidecar container.
Optional, defaults to not set.
### Limits ### Limits
CPU and memory limits for the Postgres container. CPU and memory limits for the Postgres container.
@ -371,6 +379,14 @@ CPU and memory limits for the Postgres container.
memory limits for the Postgres container. Optional, overrides the memory limits for the Postgres container. Optional, overrides the
`default_memory_limits` operator configuration parameter. `default_memory_limits` operator configuration parameter.
* **hugepages-2Mi**
hugepages-2Mi requests for the sidecar container.
Optional, defaults to not set.
* **hugepages-1Gi**
1Gi hugepages requests for the sidecar container.
Optional, defaults to not set.
## Parameters defining how to clone the cluster from another one ## Parameters defining how to clone the cluster from another one
Those parameters are applied when the cluster should be a clone of another one Those parameters are applied when the cluster should be a clone of another one
@ -500,6 +516,14 @@ CPU and memory requests for the sidecar container.
memory requests for the sidecar container. Optional, overrides the memory requests for the sidecar container. Optional, overrides the
`default_memory_request` operator configuration parameter. Optional. `default_memory_request` operator configuration parameter. Optional.
* **hugepages-2Mi**
hugepages-2Mi requests for the sidecar container.
Optional, defaults to not set.
* **hugepages-1Gi**
1Gi hugepages requests for the sidecar container.
Optional, defaults to not set.
### Limits ### Limits
CPU and memory limits for the sidecar container. CPU and memory limits for the sidecar container.
@ -512,6 +536,14 @@ CPU and memory limits for the sidecar container.
memory limits for the sidecar container. Optional, overrides the memory limits for the sidecar container. Optional, overrides the
`default_memory_limits` operator configuration parameter. Optional. `default_memory_limits` operator configuration parameter. Optional.
* **hugepages-2Mi**
hugepages-2Mi requests for the sidecar container.
Optional, defaults to not set.
* **hugepages-1Gi**
1Gi hugepages requests for the sidecar container.
Optional, defaults to not set.
## Connection pooler ## Connection pooler
Parameters are grouped under the `connectionPooler` top-level key and specify Parameters are grouped under the `connectionPooler` top-level key and specify

View File

@ -690,6 +690,27 @@ manifest the operator will raise the limits to the configured minimum values.
If no resources are defined in the manifest they will be obtained from the If no resources are defined in the manifest they will be obtained from the
configured [default requests](reference/operator_parameters.md#kubernetes-resource-requests). configured [default requests](reference/operator_parameters.md#kubernetes-resource-requests).
### HugePages support
The operator supports [HugePages](https://www.postgresql.org/docs/15/kernel-resources.html#LINUX-HUGEPAGES).
To enable HugePages, set the matching resource requests and/or limits in the manifest:
```yaml
spec:
resources:
requests:
hugepages-2Mi: 250Mi
hugepages-1Gi: 1Gi
limits:
hugepages-2Mi: 500Mi
hugepages-1Gi: 2Gi
```
There are no minimums or maximums and the default is 0 for both HugePage sizes,
but Kubernetes will not spin up the pod if the requested HugePages cannot be allocated.
For more information on HugePages in Kubernetes, see also
[https://kubernetes.io/docs/tasks/manage-hugepages/scheduling-hugepages/](https://kubernetes.io/docs/tasks/manage-hugepages/scheduling-hugepages/)
## Use taints, tolerations and node affinity for dedicated PostgreSQL nodes ## Use taints, tolerations and node affinity for dedicated PostgreSQL nodes
To ensure Postgres pods are running on nodes without any other application pods, To ensure Postgres pods are running on nodes without any other application pods,

View File

@ -107,9 +107,13 @@ spec:
requests: requests:
cpu: 10m cpu: 10m
memory: 100Mi memory: 100Mi
# hugepages-2Mi: 128Mi
# hugepages-1Gi: 1Gi
limits: limits:
cpu: 500m cpu: 500m
memory: 500Mi memory: 500Mi
# hugepages-2Mi: 128Mi
# hugepages-1Gi: 1Gi
patroni: patroni:
failsafe_mode: false failsafe_mode: false
initdb: initdb:

View File

@ -439,6 +439,12 @@ spec:
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
# Note: the value specified here must not be zero or be higher # Note: the value specified here must not be zero or be higher
# than the corresponding limit. # than the corresponding limit.
hugepages-2Mi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
hugepages-1Gi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
requests: requests:
type: object type: object
properties: properties:
@ -448,6 +454,12 @@ spec:
memory: memory:
type: string type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$' pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
hugepages-2Mi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
hugepages-1Gi:
type: string
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
schedulerName: schedulerName:
type: string type: string
serviceAnnotations: serviceAnnotations:

View File

@ -3,10 +3,11 @@ package v1
import ( import (
"fmt" "fmt"
acidzalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do"
"github.com/zalando/postgres-operator/pkg/util"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
acidzalando "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do"
"github.com/zalando/postgres-operator/pkg/util"
) )
// CRDResource* define names necesssary for the k8s CRD API // CRDResource* define names necesssary for the k8s CRD API
@ -684,6 +685,14 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
Type: "string", Type: "string",
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
}, },
"hugepages-2Mi": {
Type: "string",
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
},
"hugepages-1Gi": {
Type: "string",
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
},
}, },
}, },
"requests": { "requests": {
@ -697,6 +706,14 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
Type: "string", Type: "string",
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$", Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
}, },
"hugepages-2Mi": {
Type: "string",
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
},
"hugepages-1Gi": {
Type: "string",
Pattern: "^(\\d+(e\\d+)?|\\d+(\\.\\d+)?(e\\d+)?[EPTGMK]i?)$",
},
}, },
}, },
}, },

View File

@ -153,8 +153,10 @@ type PostgresqlParam struct {
// ResourceDescription describes CPU and memory resources defined for a cluster. // ResourceDescription describes CPU and memory resources defined for a cluster.
type ResourceDescription struct { type ResourceDescription struct {
CPU string `json:"cpu"` CPU string `json:"cpu"`
Memory string `json:"memory"` Memory string `json:"memory"`
HugePages2Mi string `json:"hugepages-2Mi"`
HugePages1Gi string `json:"hugepages-1Gi"`
} }
// Resources describes requests and limits for the cluster resouces. // Resources describes requests and limits for the cluster resouces.

View File

@ -20,6 +20,10 @@ import (
"k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
"golang.org/x/exp/maps"
batchv1 "k8s.io/api/batch/v1"
"k8s.io/apimachinery/pkg/labels"
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
"github.com/zalando/postgres-operator/pkg/spec" "github.com/zalando/postgres-operator/pkg/spec"
"github.com/zalando/postgres-operator/pkg/util" "github.com/zalando/postgres-operator/pkg/util"
@ -28,9 +32,6 @@ import (
"github.com/zalando/postgres-operator/pkg/util/k8sutil" "github.com/zalando/postgres-operator/pkg/util/k8sutil"
"github.com/zalando/postgres-operator/pkg/util/patroni" "github.com/zalando/postgres-operator/pkg/util/patroni"
"github.com/zalando/postgres-operator/pkg/util/retryutil" "github.com/zalando/postgres-operator/pkg/util/retryutil"
"golang.org/x/exp/maps"
batchv1 "k8s.io/api/batch/v1"
"k8s.io/apimachinery/pkg/labels"
) )
const ( const (
@ -266,6 +267,19 @@ func fillResourceList(spec acidv1.ResourceDescription, defaults acidv1.ResourceD
} }
} }
if spec.HugePages2Mi != "" {
requests[v1.ResourceHugePagesPrefix+"2Mi"], err = resource.ParseQuantity(spec.HugePages2Mi)
if err != nil {
return nil, fmt.Errorf("could not parse hugepages-2Mi quantity: %v", err)
}
}
if spec.HugePages1Gi != "" {
requests[v1.ResourceHugePagesPrefix+"1Gi"], err = resource.ParseQuantity(spec.HugePages1Gi)
if err != nil {
return nil, fmt.Errorf("could not parse hugepages-1Gi quantity: %v", err)
}
}
return requests, nil return requests, nil
} }

View File

@ -5,9 +5,8 @@ import (
"fmt" "fmt"
"reflect" "reflect"
"sort" "sort"
"time"
"testing" "testing"
"time"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -3081,6 +3080,131 @@ func TestGenerateResourceRequirements(t *testing.T) {
ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "2Gi"}, ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "2Gi"},
}, },
}, },
{
subTest: "test HugePages are not set on container when not requested in manifest",
config: config.Config{
Resources: configResources,
PodManagementPolicy: "ordered_ready",
},
pgSpec: acidv1.Postgresql{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
Namespace: namespace,
},
Spec: acidv1.PostgresSpec{
Resources: &acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{},
ResourceLimits: acidv1.ResourceDescription{},
},
TeamID: "acid",
Volume: acidv1.Volume{
Size: "1G",
},
},
},
expectedResources: acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{
CPU: "100m",
Memory: "100Mi",
},
ResourceLimits: acidv1.ResourceDescription{
CPU: "1",
Memory: "500Mi",
},
},
},
{
subTest: "test HugePages are passed through to the postgres container",
config: config.Config{
Resources: configResources,
PodManagementPolicy: "ordered_ready",
},
pgSpec: acidv1.Postgresql{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
Namespace: namespace,
},
Spec: acidv1.PostgresSpec{
Resources: &acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{
HugePages2Mi: "128Mi",
HugePages1Gi: "1Gi",
},
ResourceLimits: acidv1.ResourceDescription{
HugePages2Mi: "256Mi",
HugePages1Gi: "2Gi",
},
},
TeamID: "acid",
Volume: acidv1.Volume{
Size: "1G",
},
},
},
expectedResources: acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{
CPU: "100m",
Memory: "100Mi",
HugePages2Mi: "128Mi",
HugePages1Gi: "1Gi",
},
ResourceLimits: acidv1.ResourceDescription{
CPU: "1",
Memory: "500Mi",
HugePages2Mi: "256Mi",
HugePages1Gi: "2Gi",
},
},
},
{
subTest: "test HugePages are passed through on sidecars",
config: config.Config{
Resources: configResources,
PodManagementPolicy: "ordered_ready",
},
pgSpec: acidv1.Postgresql{
ObjectMeta: metav1.ObjectMeta{
Name: clusterName,
Namespace: namespace,
},
Spec: acidv1.PostgresSpec{
Sidecars: []acidv1.Sidecar{
{
Name: "test-sidecar",
DockerImage: "test-image",
Resources: &acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{
HugePages2Mi: "128Mi",
HugePages1Gi: "1Gi",
},
ResourceLimits: acidv1.ResourceDescription{
HugePages2Mi: "256Mi",
HugePages1Gi: "2Gi",
},
},
},
},
TeamID: "acid",
Volume: acidv1.Volume{
Size: "1G",
},
},
},
expectedResources: acidv1.Resources{
ResourceRequests: acidv1.ResourceDescription{
CPU: "100m",
Memory: "100Mi",
HugePages2Mi: "128Mi",
HugePages1Gi: "1Gi",
},
ResourceLimits: acidv1.ResourceDescription{
CPU: "1",
Memory: "500Mi",
HugePages2Mi: "256Mi",
HugePages1Gi: "2Gi",
},
},
},
} }
for _, tt := range tests { for _, tt := range tests {