From 9bf80afa6b1fc8f75582967ee373fefca1b007fb Mon Sep 17 00:00:00 2001 From: Oleksii Kliukin Date: Fri, 6 Apr 2018 13:58:47 +0200 Subject: [PATCH] Remove team from statefulset selector (#271) * Remove 'team' label from the statefulset selector. I was never supposed to be there, but implicitely statefulset creates a selector out of meta.labels field. That is the problem with recent Kubernetes, since statefulset cannot pick up pods with non-matching label selectors, and we rely on statefulset picking up old pods after statefulset replacement. Make sure selector changes trigger replacement of the statefulset. In the case new selector has more labels than the old one nothing should be done with a statefulset, otherwise the new statefulset won't see orphaned pods from the old one, as they won't match the selector. See https://github.com/kubernetes/kubernetes/issues/46901#issuecomment-356418393 --- pkg/cluster/cluster.go | 14 ++++++++++++++ pkg/cluster/k8sres.go | 1 + pkg/cluster/util.go | 4 ++++ 3 files changed, 19 insertions(+) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index 627238415..e059759dd 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -340,6 +340,20 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *v1beta1.StatefulSet) *comp needsRollUpdate = true reasons = append(reasons, "new statefulset's metadata labels doesn't match the current one") } + if (c.Statefulset.Spec.Selector != nil) && (statefulSet.Spec.Selector != nil) { + if !reflect.DeepEqual(c.Statefulset.Spec.Selector.MatchLabels, statefulSet.Spec.Selector.MatchLabels) { + // forbid introducing new labels in the selector on the new statefulset, as it would cripple replacements + // due to the fact that the new statefulset won't be able to pick up old pods with non-matching labels. + if !util.MapContains(c.Statefulset.Spec.Selector.MatchLabels, statefulSet.Spec.Selector.MatchLabels) { + c.logger.Warningf("new statefulset introduces extra labels in the label selector, cannot continue") + return &compareStatefulsetResult{} + } + } + needsReplace = true + needsRollUpdate = true + reasons = append(reasons, "new statefulset's selector doesn't match the current one") + } + if !reflect.DeepEqual(c.Statefulset.Spec.Template.Annotations, statefulSet.Spec.Template.Annotations) { needsRollUpdate = true needsReplace = true diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index 843578293..cf16bb39a 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -564,6 +564,7 @@ func (c *Cluster) generateStatefulSet(spec *spec.PostgresSpec) (*v1beta1.Statefu }, Spec: v1beta1.StatefulSetSpec{ Replicas: &numberOfInstances, + Selector: c.labelsSelector(), ServiceName: c.serviceName(Master), Template: *podTemplate, VolumeClaimTemplates: []v1.PersistentVolumeClaim{*volumeClaimTemplate}, diff --git a/pkg/cluster/util.go b/pkg/cluster/util.go index dd996ccd1..4a4f4e04a 100644 --- a/pkg/cluster/util.go +++ b/pkg/cluster/util.go @@ -355,6 +355,10 @@ func (c *Cluster) labelsSet(shouldAddExtraLabels bool) labels.Set { return labels.Set(lbls) } +func (c *Cluster) labelsSelector() *metav1.LabelSelector { + return &metav1.LabelSelector{c.labelsSet(false), nil} +} + func (c *Cluster) roleLabelsSet(role PostgresRole) labels.Set { lbls := c.labelsSet(false) lbls[c.OpConfig.PodRoleLabel] = string(role)