Skip to content

Commit eba2327

Browse files
alexeyklyukinmkabilov
authored andcommitted
Kube cluster upgrade
1 parent 1dbf259 commit eba2327

File tree

19 files changed

+595
-73
lines changed

19 files changed

+595
-73
lines changed

glide.lock

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glide.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@ import:
1717
version: release-1.7
1818
subpackages:
1919
- pkg/api/errors
20-
- pkg/api/meta
2120
- pkg/api/resource
2221
- pkg/apis/meta/v1
23-
- pkg/fields
2422
- pkg/labels
2523
- pkg/runtime
2624
- pkg/runtime/schema
@@ -33,6 +31,10 @@ import:
3331
version: ^4.0.0
3432
subpackages:
3533
- kubernetes
34+
- kubernetes/scheme
35+
- kubernetes/typed/apps/v1beta1
36+
- kubernetes/typed/core/v1
37+
- kubernetes/typed/extensions/v1beta1
3638
- pkg/api
3739
- pkg/api/v1
3840
- pkg/apis/apps/v1beta1

manifests/configmap.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ data:
1212
dns_name_format: '{cluster}.{team}.staging.{hostedzone}'
1313
docker_image: registry.opensource.zalan.do/acid/spiloprivate-9.6:1.2-p4
1414
etcd_host: etcd-client.default.svc.cluster.local:2379
15-
secret_name_template: '{username}.{clustername}.credentials.{tprkind}.{tprgroup}'
15+
secret_name_template: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}'
1616
infrastructure_roles_secret_name: postgresql-infrastructure-roles
1717
oauth_token_secret_name: postgresql-operator
1818
pam_configuration: |
@@ -37,3 +37,5 @@ data:
3737
ring_log_lines: "100"
3838
cluster_history_entries: "1000"
3939
pod_terminate_grace_period: 5m
40+
pdb_name_format: "postgres-{cluster}-pdb"
41+
eol_node_label: "eol:true"

manifests/postgres-operator.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ spec:
1212
serviceAccountName: operator
1313
containers:
1414
- name: postgres-operator
15-
image: pierone.example.com/acid/postgres-operator:0.1
15+
image: pierone.stups.zalan.do/acid/postgres-operator:workerassgn
1616
imagePullPolicy: IfNotPresent
1717
env:
1818
- name: WATCH_NAMESPACE

manifests/testpostgresql.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ apiVersion: "acid.zalan.do/v1"
22
kind: postgresql
33

44
metadata:
5-
name: acid-testcluster
5+
name: acid-testcluster17
66
spec:
77
teamId: "ACID"
88
volume:

pkg/cluster/cluster.go

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"k8s.io/apimachinery/pkg/types"
1717
"k8s.io/client-go/pkg/api/v1"
1818
"k8s.io/client-go/pkg/apis/apps/v1beta1"
19+
policybeta1 "k8s.io/client-go/pkg/apis/policy/v1beta1"
1920
"k8s.io/client-go/rest"
2021
"k8s.io/client-go/tools/cache"
2122

@@ -44,10 +45,11 @@ type Config struct {
4445
}
4546

4647
type kubeResources struct {
47-
Services map[PostgresRole]*v1.Service
48-
Endpoint *v1.Endpoints
49-
Secrets map[types.UID]*v1.Secret
50-
Statefulset *v1beta1.StatefulSet
48+
Services map[PostgresRole]*v1.Service
49+
Endpoint *v1.Endpoints
50+
Secrets map[types.UID]*v1.Secret
51+
Statefulset *v1beta1.StatefulSet
52+
PodDisruptionBudget *policybeta1.PodDisruptionBudget
5153
//Pods are treated separately
5254
//PVCs are treated separately
5355
}
@@ -259,6 +261,12 @@ func (c *Cluster) Create() error {
259261
}
260262
}
261263

264+
pdb, err := c.createPodDisruptionBudget()
265+
if err != nil {
266+
return fmt.Errorf("could not create pod disruption budget: %v", err)
267+
}
268+
c.logger.Infof("pod disruption budget %q has been successfully created", util.NameFromMeta(pdb.ObjectMeta))
269+
262270
err = c.listResources()
263271
if err != nil {
264272
c.logger.Errorf("could not list resources: %v", err)
@@ -334,6 +342,12 @@ func (c *Cluster) compareStatefulSetWith(statefulSet *v1beta1.StatefulSet) *comp
334342
needsRollUpdate = true
335343
reasons = append(reasons, "new statefulset's terminationGracePeriodSeconds doesn't match the current one")
336344
}
345+
if !reflect.DeepEqual(c.Statefulset.Spec.Template.Spec.Affinity, statefulSet.Spec.Template.Spec.Affinity) {
346+
needsReplace = true
347+
needsRollUpdate = true
348+
reasons = append(reasons, "new statefulset's pod affinity doesn't match the current one")
349+
}
350+
337351
// Some generated fields like creationTimestamp make it not possible to use DeepCompare on Spec.Template.ObjectMeta
338352
if !reflect.DeepEqual(c.Statefulset.Spec.Template.Labels, statefulSet.Spec.Template.Labels) {
339353
needsReplace = true
@@ -522,6 +536,15 @@ func (c *Cluster) Update(newSpec *spec.Postgresql) error {
522536
c.logger.Infof("volumes have been updated successfully")
523537
}
524538

539+
newPDB := c.generatePodDisruptionBudget()
540+
if match, reason := c.samePDBWith(newPDB); !match {
541+
c.logPDBChanges(c.PodDisruptionBudget, newPDB, true, reason)
542+
if err := c.updatePodDisruptionBudget(newPDB); err != nil {
543+
c.setStatus(spec.ClusterStatusUpdateFailed)
544+
return fmt.Errorf("could not update pod disruption budget: %v", err)
545+
}
546+
}
547+
525548
c.setStatus(spec.ClusterStatusRunning)
526549

527550
return nil
@@ -555,6 +578,10 @@ func (c *Cluster) Delete() error {
555578
}
556579
}
557580

581+
if err := c.deletePodDisruptionBudget(); err != nil {
582+
return fmt.Errorf("could not delete pod disruption budget: %v", err)
583+
}
584+
558585
return nil
559586
}
560587

@@ -690,11 +717,12 @@ func (c *Cluster) GetStatus() *spec.ClusterStatus {
690717
Status: c.Status,
691718
Spec: c.Spec,
692719

693-
MasterService: c.GetServiceMaster(),
694-
ReplicaService: c.GetServiceReplica(),
695-
Endpoint: c.GetEndpoint(),
696-
StatefulSet: c.GetStatefulSet(),
697-
CurrentProcess: c.GetCurrentProcess(),
720+
MasterService: c.GetServiceMaster(),
721+
ReplicaService: c.GetServiceReplica(),
722+
Endpoint: c.GetEndpoint(),
723+
StatefulSet: c.GetStatefulSet(),
724+
PodDisruptionBudget: c.GetPodDisruptionBudget(),
725+
CurrentProcess: c.GetCurrentProcess(),
698726

699727
Error: c.Error,
700728
}
@@ -733,3 +761,13 @@ func (c *Cluster) ManualFailover(curMaster *v1.Pod, candidate spec.NamespacedNam
733761

734762
return nil
735763
}
764+
765+
// Lock locks the cluster
766+
func (c *Cluster) Lock() {
767+
c.mu.Lock()
768+
}
769+
770+
// Unlock unlocks the cluster
771+
func (c *Cluster) Unlock() {
772+
c.mu.Unlock()
773+
}

pkg/cluster/k8sres.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"k8s.io/apimachinery/pkg/util/intstr"
1111
"k8s.io/client-go/pkg/api/v1"
1212
"k8s.io/client-go/pkg/apis/apps/v1beta1"
13+
policybeta1 "k8s.io/client-go/pkg/apis/policy/v1beta1"
1314

1415
"github.com/zalando-incubator/postgres-operator/pkg/spec"
1516
"github.com/zalando-incubator/postgres-operator/pkg/util/constants"
@@ -67,6 +68,10 @@ func (c *Cluster) serviceName(role PostgresRole) string {
6768
return name
6869
}
6970

71+
func (c *Cluster) podDisruptionBudgetName() string {
72+
return c.OpConfig.PDBNameFormat.Format("cluster", c.Spec.ClusterName)
73+
}
74+
7075
func (c *Cluster) resourceRequirements(resources spec.Resources) (*v1.ResourceRequirements, error) {
7176
var err error
7277

@@ -226,6 +231,25 @@ PATRONI_INITDB_PARAMS:
226231
return string(result)
227232
}
228233

234+
func (c *Cluster) nodeAffinity() *v1.Affinity {
235+
matchExpressions := make([]v1.NodeSelectorRequirement, 0)
236+
for k, v := range c.OpConfig.EOLNodeLabel {
237+
matchExpressions = append(matchExpressions, v1.NodeSelectorRequirement{
238+
Key: k,
239+
Operator: v1.NodeSelectorOpNotIn,
240+
Values: []string{v},
241+
})
242+
}
243+
244+
return &v1.Affinity{
245+
NodeAffinity: &v1.NodeAffinity{
246+
RequiredDuringSchedulingIgnoredDuringExecution: &v1.NodeSelector{
247+
NodeSelectorTerms: []v1.NodeSelectorTerm{{MatchExpressions: matchExpressions}},
248+
},
249+
},
250+
}
251+
}
252+
229253
func (c *Cluster) generatePodTemplate(resourceRequirements *v1.ResourceRequirements,
230254
pgParameters *spec.PostgresqlParam,
231255
patroniParameters *spec.Patroni,
@@ -347,6 +371,7 @@ func (c *Cluster) generatePodTemplate(resourceRequirements *v1.ResourceRequireme
347371
ServiceAccountName: c.OpConfig.ServiceAccountName,
348372
TerminationGracePeriodSeconds: &terminateGracePeriodSeconds,
349373
Containers: []v1.Container{container},
374+
Affinity: c.nodeAffinity(),
350375
}
351376

352377
template := v1.PodTemplateSpec{
@@ -573,6 +598,25 @@ func (c *Cluster) generateCloneEnvironment(description *spec.CloneDescription) [
573598
return result
574599
}
575600

601+
func (c *Cluster) generatePodDisruptionBudget() *policybeta1.PodDisruptionBudget {
602+
minAvailable := intstr.FromInt(1)
603+
matchLabels := c.OpConfig.ClusterLabels
604+
matchLabels[c.OpConfig.ClusterNameLabel] = c.Name
605+
606+
return &policybeta1.PodDisruptionBudget{
607+
ObjectMeta: metav1.ObjectMeta{
608+
Name: c.podDisruptionBudgetName(),
609+
Namespace: c.Namespace,
610+
},
611+
Spec: policybeta1.PodDisruptionBudgetSpec{
612+
MinAvailable: &minAvailable,
613+
Selector: &metav1.LabelSelector{
614+
MatchLabels: matchLabels,
615+
},
616+
},
617+
}
618+
}
619+
576620
// getClusterServiceConnectionParameters fetches cluster host name and port
577621
// TODO: perhaps we need to query the service (i.e. if non-standard port is used?)
578622
// TODO: handle clusters in different namespaces

0 commit comments

Comments
 (0)