Make PodDisruptionBudget master label selector optional (#2364)

* Make PDB master label selector optional

* Update pkg/apis/acid.zalan.do/v1/crds.go

---------

Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This commit is contained in:
Davide Bizzarri 2024-01-04 15:58:24 +01:00 committed by GitHub
parent 182a6d9b65
commit 3ca26d0dc8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 52 additions and 5 deletions

View File

@ -323,6 +323,11 @@ configuration they are grouped under the `kubernetes` key.
replaced by the cluster name. Only the `{cluster}` placeholders is allowed in replaced by the cluster name. Only the `{cluster}` placeholders is allowed in
the template. the template.
* **pdb_master_label_selector**
By default the PDB will match the master role hence preventing nodes to be
drained if the node_readiness_label is not used. This option if set to `false`
will not add the `spilo-role=master` selector to the PDB.
* **enable_pod_disruption_budget** * **enable_pod_disruption_budget**
PDB is enabled by default to protect the cluster from voluntarily disruptions PDB is enabled by default to protect the cluster from voluntarily disruptions
and hence unwanted DB downtime. However, on some cloud providers it could be and hence unwanted DB downtime. However, on some cloud providers it could be
@ -431,7 +436,7 @@ configuration they are grouped under the `kubernetes` key.
environment if they not if conflict with the environment variables generated environment if they not if conflict with the environment variables generated
by the operator. The WAL location (bucket path) can be overridden, though. by the operator. The WAL location (bucket path) can be overridden, though.
The default is empty. The default is empty.
* **pod_environment_secret** * **pod_environment_secret**
similar to pod_environment_configmap but referencing a secret with custom similar to pod_environment_configmap but referencing a secret with custom
environment variables. Because the secret is not allowed to exist in a environment variables. Because the secret is not allowed to exist in a
@ -577,7 +582,7 @@ effect, and the parameters are grouped under the `timeouts` key in the
CRD-based configuration. CRD-based configuration.
* **PatroniAPICheckInterval** * **PatroniAPICheckInterval**
the interval between consecutive attempts waiting for the return of the interval between consecutive attempts waiting for the return of
Patroni Api. The default is `1s`. Patroni Api. The default is `1s`.
* **PatroniAPICheckTimeout** * **PatroniAPICheckTimeout**
@ -651,7 +656,7 @@ In the CRD-based configuration they are grouped under the `load_balancer` key.
balancers. Allowed values are `Cluster` (default) and `Local`. balancers. Allowed values are `Cluster` (default) and `Local`.
* **master_dns_name_format** * **master_dns_name_format**
defines the DNS name string template for the master load balancer cluster. defines the DNS name string template for the master load balancer cluster.
The default is `{cluster}.{namespace}.{hostedzone}`, where `{cluster}` is The default is `{cluster}.{namespace}.{hostedzone}`, where `{cluster}` is
replaced by the cluster name, `{namespace}` is replaced with the namespace replaced by the cluster name, `{namespace}` is replaced with the namespace
and `{hostedzone}` is replaced with the hosted zone (the value of the and `{hostedzone}` is replaced with the hosted zone (the value of the
@ -816,7 +821,7 @@ grouped under the `logical_backup` key.
is specified, no argument will be passed to `aws s3` command. Default: "AES256". is specified, no argument will be passed to `aws s3` command. Default: "AES256".
* **logical_backup_s3_retention_time** * **logical_backup_s3_retention_time**
Specify a retention time for logical backups stored in S3. Backups older than the specified retention Specify a retention time for logical backups stored in S3. Backups older than the specified retention
time will be deleted after a new backup was uploaded. If empty, all backups will be kept. Example values are time will be deleted after a new backup was uploaded. If empty, all backups will be kept. Example values are
"3 days", "2 weeks", or "1 month". The default is empty. "3 days", "2 weeks", or "1 month". The default is empty.

View File

@ -1394,6 +1394,9 @@ var OperatorConfigCRDResourceValidation = apiextv1.CustomResourceValidation{
"pdb_name_format": { "pdb_name_format": {
Type: "string", Type: "string",
}, },
"pdb_master_label_selector": {
Type: "boolean",
},
"persistent_volume_claim_retention_policy": { "persistent_volume_claim_retention_policy": {
Type: "object", Type: "object",
Properties: map[string]apiextv1.JSONSchemaProps{ Properties: map[string]apiextv1.JSONSchemaProps{

View File

@ -68,6 +68,7 @@ type KubernetesMetaConfiguration struct {
AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"` AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"`
WatchedNamespace string `json:"watched_namespace,omitempty"` WatchedNamespace string `json:"watched_namespace,omitempty"`
PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"` PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"`
PDBMasterLabelSelector *bool `json:"pdb_master_label_selector,omitempty"`
EnablePodDisruptionBudget *bool `json:"enable_pod_disruption_budget,omitempty"` EnablePodDisruptionBudget *bool `json:"enable_pod_disruption_budget,omitempty"`
StorageResizeMode string `json:"storage_resize_mode,omitempty"` StorageResizeMode string `json:"storage_resize_mode,omitempty"`
EnableInitContainers *bool `json:"enable_init_containers,omitempty"` EnableInitContainers *bool `json:"enable_init_containers,omitempty"`

View File

@ -178,6 +178,11 @@ func (in *KubernetesMetaConfiguration) DeepCopyInto(out *KubernetesMetaConfigura
*out = make([]string, len(*in)) *out = make([]string, len(*in))
copy(*out, *in) copy(*out, *in)
} }
if in.PDBMasterLabelSelector != nil {
in, out := &in.PDBMasterLabelSelector, &out.PDBMasterLabelSelector
*out = new(bool)
**out = **in
}
if in.EnablePodDisruptionBudget != nil { if in.EnablePodDisruptionBudget != nil {
in, out := &in.EnablePodDisruptionBudget, &out.EnablePodDisruptionBudget in, out := &in.EnablePodDisruptionBudget, &out.EnablePodDisruptionBudget
*out = new(bool) *out = new(bool)

View File

@ -2150,12 +2150,19 @@ func (c *Cluster) generateStandbyEnvironment(description *acidv1.StandbyDescript
func (c *Cluster) generatePodDisruptionBudget() *policyv1.PodDisruptionBudget { func (c *Cluster) generatePodDisruptionBudget() *policyv1.PodDisruptionBudget {
minAvailable := intstr.FromInt(1) minAvailable := intstr.FromInt(1)
pdbEnabled := c.OpConfig.EnablePodDisruptionBudget pdbEnabled := c.OpConfig.EnablePodDisruptionBudget
pdbMasterLabelSelector := c.OpConfig.PDBMasterLabelSelector
// if PodDisruptionBudget is disabled or if there are no DB pods, set the budget to 0. // if PodDisruptionBudget is disabled or if there are no DB pods, set the budget to 0.
if (pdbEnabled != nil && !(*pdbEnabled)) || c.Spec.NumberOfInstances <= 0 { if (pdbEnabled != nil && !(*pdbEnabled)) || c.Spec.NumberOfInstances <= 0 {
minAvailable = intstr.FromInt(0) minAvailable = intstr.FromInt(0)
} }
// define label selector and add the master role selector if enabled
labels := c.labelsSet(false)
if pdbMasterLabelSelector == nil || *c.OpConfig.PDBMasterLabelSelector {
labels[c.OpConfig.PodRoleLabel] = string(Master)
}
return &policyv1.PodDisruptionBudget{ return &policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: c.podDisruptionBudgetName(), Name: c.podDisruptionBudgetName(),
@ -2166,7 +2173,7 @@ func (c *Cluster) generatePodDisruptionBudget() *policyv1.PodDisruptionBudget {
Spec: policyv1.PodDisruptionBudgetSpec{ Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: &minAvailable, MinAvailable: &minAvailable,
Selector: &metav1.LabelSelector{ Selector: &metav1.LabelSelector{
MatchLabels: c.roleLabelsSet(false, Master), MatchLabels: labels,
}, },
}, },
} }

View File

@ -2379,6 +2379,30 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
}, },
}, },
}, },
// With PDBMasterLabelSelector disabled.
{
New(
Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-pdb", PDBMasterLabelSelector: util.False()}},
k8sutil.KubernetesClient{},
acidv1.Postgresql{
ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"},
Spec: acidv1.PostgresSpec{TeamID: "myapp", NumberOfInstances: 3}},
logger,
eventRecorder),
policyv1.PodDisruptionBudget{
ObjectMeta: metav1.ObjectMeta{
Name: "postgres-myapp-database-pdb",
Namespace: "myapp",
Labels: map[string]string{"team": "myapp", "cluster-name": "myapp-database"},
},
Spec: policyv1.PodDisruptionBudgetSpec{
MinAvailable: util.ToIntStr(1),
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{"cluster-name": "myapp-database"},
},
},
},
},
} }
for _, tt := range tests { for _, tt := range tests {

View File

@ -82,6 +82,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.ClusterDomain = util.Coalesce(fromCRD.Kubernetes.ClusterDomain, "cluster.local") result.ClusterDomain = util.Coalesce(fromCRD.Kubernetes.ClusterDomain, "cluster.local")
result.WatchedNamespace = fromCRD.Kubernetes.WatchedNamespace result.WatchedNamespace = fromCRD.Kubernetes.WatchedNamespace
result.PDBNameFormat = fromCRD.Kubernetes.PDBNameFormat result.PDBNameFormat = fromCRD.Kubernetes.PDBNameFormat
result.PDBMasterLabelSelector = util.CoalesceBool(fromCRD.Kubernetes.PDBMasterLabelSelector, util.True())
result.EnablePodDisruptionBudget = util.CoalesceBool(fromCRD.Kubernetes.EnablePodDisruptionBudget, util.True()) result.EnablePodDisruptionBudget = util.CoalesceBool(fromCRD.Kubernetes.EnablePodDisruptionBudget, util.True())
result.StorageResizeMode = util.Coalesce(fromCRD.Kubernetes.StorageResizeMode, "pvc") result.StorageResizeMode = util.Coalesce(fromCRD.Kubernetes.StorageResizeMode, "pvc")
result.EnableInitContainers = util.CoalesceBool(fromCRD.Kubernetes.EnableInitContainers, util.True()) result.EnableInitContainers = util.CoalesceBool(fromCRD.Kubernetes.EnableInitContainers, util.True())

View File

@ -220,6 +220,7 @@ type Config struct {
ReplicaDNSNameFormat StringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{namespace}.{hostedzone}"` ReplicaDNSNameFormat StringTemplate `name:"replica_dns_name_format" default:"{cluster}-repl.{namespace}.{hostedzone}"`
ReplicaLegacyDNSNameFormat StringTemplate `name:"replica_legacy_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"` ReplicaLegacyDNSNameFormat StringTemplate `name:"replica_legacy_dns_name_format" default:"{cluster}-repl.{team}.{hostedzone}"`
PDBNameFormat StringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"` PDBNameFormat StringTemplate `name:"pdb_name_format" default:"postgres-{cluster}-pdb"`
PDBMasterLabelSelector *bool `name:"pdb_master_label_selector" default:"true"`
EnablePodDisruptionBudget *bool `name:"enable_pod_disruption_budget" default:"true"` EnablePodDisruptionBudget *bool `name:"enable_pod_disruption_budget" default:"true"`
EnableInitContainers *bool `name:"enable_init_containers" default:"true"` EnableInitContainers *bool `name:"enable_init_containers" default:"true"`
EnableSidecars *bool `name:"enable_sidecars" default:"true"` EnableSidecars *bool `name:"enable_sidecars" default:"true"`