Add node toleration config to PodSpec (#151)

* Add node toleration config to PodSpec

This allows to taint nodes dedicated to Postgres and prevents other pods from running on these nodes.

* Document taint and toleration setup

And remove setting from default operator ConfigMap

* Allow to overwrite tolerations with Postgres manifest
This commit is contained in:
Georg Kunz 2017-11-02 19:10:44 +01:00 committed by Jan Mussler
parent ce960e892a
commit 47dd766fa7
4 changed files with 71 additions and 1 deletions

View File

@ -93,6 +93,50 @@ We can use the generated secret of the `postgres` robot user to connect to our `
$ psql -U postgres $ psql -U postgres
### Configuration Options
The operator can be configured with the provided ConfigMap (`manifests/configmap.yaml`).
#### Use Taints and Tolerations for Dedicated Postgres Nodes
To ensure Postgres pods are running on nodes without any other application pods, you can use [taints and tolerations](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) and configure the required toleration in the operator ConfigMap.
As an example you can set following node taint:
```
$ kubectl taint nodes <nodeName> postgres=:NoSchedule
```
And configure the toleration for the Postgres pods by adding following line to the ConfigMap:
```
apiVersion: v1
kind: ConfigMap
metadata:
name: postgres-operator
data:
toleration: "key:postgres,operator:Exists,effect:NoSchedule"
...
```
Or you can specify and/or overwrite the tolerations for each postgres instance in the postgres manifest:
```
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
name: acid-minimal-cluster
spec:
teamId: "ACID"
tolerations:
- key: postgres
operator: Exists
effect: NoSchedule
```
Please be ware that the taint and toleration only ensures that no other pod gets scheduled to the "postgres" node but not that Postgres pods are placed on such a node. This can be achieved by setting a node affinity rule in the ConfigMap.
# Setup development environment # Setup development environment
The following steps guide you through the setup to work on the operator itself. The following steps guide you through the setup to work on the operator itself.

View File

@ -250,7 +250,29 @@ func (c *Cluster) nodeAffinity() *v1.Affinity {
} }
} }
func (c *Cluster) tolerations(tolerationsSpec *[]v1.Toleration) []v1.Toleration {
// allow to override tolerations by postgresql manifest
if len(*tolerationsSpec) > 0 {
return *tolerationsSpec
}
podToleration := c.Config.OpConfig.PodToleration
if (len(podToleration["key"]) > 0 || len(podToleration["operator"]) > 0 || len(podToleration["value"]) > 0 || len(podToleration["effect"]) > 0) {
return []v1.Toleration{
{
Key: podToleration["key"],
Operator: v1.TolerationOperator(podToleration["operator"]),
Value: podToleration["value"],
Effect: v1.TaintEffect(podToleration["effect"]),
},
}
} else {
return []v1.Toleration{}
}
}
func (c *Cluster) generatePodTemplate(resourceRequirements *v1.ResourceRequirements, func (c *Cluster) generatePodTemplate(resourceRequirements *v1.ResourceRequirements,
tolerationsSpec *[]v1.Toleration,
pgParameters *spec.PostgresqlParam, pgParameters *spec.PostgresqlParam,
patroniParameters *spec.Patroni, patroniParameters *spec.Patroni,
cloneDescription *spec.CloneDescription) *v1.PodTemplateSpec { cloneDescription *spec.CloneDescription) *v1.PodTemplateSpec {
@ -372,6 +394,7 @@ func (c *Cluster) generatePodTemplate(resourceRequirements *v1.ResourceRequireme
TerminationGracePeriodSeconds: &terminateGracePeriodSeconds, TerminationGracePeriodSeconds: &terminateGracePeriodSeconds,
Containers: []v1.Container{container}, Containers: []v1.Container{container},
Affinity: c.nodeAffinity(), Affinity: c.nodeAffinity(),
Tolerations: c.tolerations(tolerationsSpec),
} }
template := v1.PodTemplateSpec{ template := v1.PodTemplateSpec{
@ -394,7 +417,7 @@ func (c *Cluster) generateStatefulSet(spec spec.PostgresSpec) (*v1beta1.Stateful
return nil, fmt.Errorf("could not generate resource requirements: %v", err) return nil, fmt.Errorf("could not generate resource requirements: %v", err)
} }
podTemplate := c.generatePodTemplate(resourceRequirements, &spec.PostgresqlParam, &spec.Patroni, &spec.Clone) podTemplate := c.generatePodTemplate(resourceRequirements, &spec.Tolerations, &spec.PostgresqlParam, &spec.Patroni, &spec.Clone)
volumeClaimTemplate, err := generatePersistentVolumeClaimTemplate(spec.Volume.Size, spec.Volume.StorageClass) volumeClaimTemplate, err := generatePersistentVolumeClaimTemplate(spec.Volume.Size, spec.Volume.StorageClass)
if err != nil { if err != nil {
return nil, fmt.Errorf("could not generate volume claim template: %v", err) return nil, fmt.Errorf("could not generate volume claim template: %v", err)

View File

@ -7,6 +7,7 @@ import (
"time" "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/pkg/api/v1"
) )
// MaintenanceWindow describes the time window when the operator is allowed to do maintenance on a cluster. // MaintenanceWindow describes the time window when the operator is allowed to do maintenance on a cluster.
@ -102,6 +103,7 @@ type PostgresSpec struct {
Clone CloneDescription `json:"clone"` Clone CloneDescription `json:"clone"`
ClusterName string `json:"-"` ClusterName string `json:"-"`
Databases map[string]string `json:"databases,omitempty"` Databases map[string]string `json:"databases,omitempty"`
Tolerations []v1.Toleration `json:"tolerations,omitempty"`
} }
// PostgresqlList defines a list of PostgreSQL clusters. // PostgresqlList defines a list of PostgreSQL clusters.

View File

@ -25,6 +25,7 @@ type Resources struct {
ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"` ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"`
ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"` ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"`
PodRoleLabel string `name:"pod_role_label" default:"spilo-role"` PodRoleLabel string `name:"pod_role_label" default:"spilo-role"`
PodToleration map[string]string `name:"toleration" default:""`
DefaultCPURequest string `name:"default_cpu_request" default:"100m"` DefaultCPURequest string `name:"default_cpu_request" default:"100m"`
DefaultMemoryRequest string `name:"default_memory_request" default:"100Mi"` DefaultMemoryRequest string `name:"default_memory_request" default:"100Mi"`
DefaultCPULimit string `name:"default_cpu_limit" default:"3"` DefaultCPULimit string `name:"default_cpu_limit" default:"3"`