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:
		
							parent
							
								
									ce960e892a
								
							
						
					
					
						commit
						47dd766fa7
					
				
							
								
								
									
										44
									
								
								README.md
								
								
								
								
							
							
						
						
									
										44
									
								
								README.md
								
								
								
								
							|  | @ -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. | ||||||
|  |  | ||||||
|  | @ -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) | ||||||
|  |  | ||||||
|  | @ -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.
 | ||||||
|  |  | ||||||
|  | @ -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"` | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue