From 3cf68afeb59473a06839ad6b74bacf6e4d0e0278 Mon Sep 17 00:00:00 2001 From: Henning Jacobs Date: Tue, 7 Nov 2017 22:54:50 +0100 Subject: [PATCH 1/3] link to Patroni --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index eeea5e790..32646a3d1 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@ -# postgres operator +# Postgres Operator [![Build Status](https://travis-ci.org/zalando-incubator/postgres-operator.svg?branch=master)](https://travis-ci.org/zalando-incubator/postgres-operator) [![Coverage Status](https://coveralls.io/repos/github/zalando-incubator/postgres-operator/badge.svg)](https://coveralls.io/github/zalando-incubator/postgres-operator) [![Go Report Card](https://goreportcard.com/badge/github.com/zalando-incubator/postgres-operator)](https://goreportcard.com/report/github.com/zalando-incubator/postgres-operator) -The Postgres operator manages Postgres clusters in Kubernetes using the [operator pattern](https://coreos.com/blog/introducing-operators.html). +The Postgres operator manages PostgreSQL clusters on Kubernetes using the [operator pattern](https://coreos.com/blog/introducing-operators.html). During the initial run it registers the [Custom Resource Definition (CRD)](https://kubernetes.io/docs/concepts/api-extension/custom-resources/#customresourcedefinitions) for Postgres. -The Postgresql CRD is essentially the schema that describes the contents of the manifests for deploying individual Postgresql clusters using Statefulsets and Patroni. +The Postgresql CRD is essentially the schema that describes the contents of the manifests for deploying individual Postgresql clusters using Statefulsets and [Patroni](https://github.com/zalando/patroni). Once the operator is running, it performs the following actions: From 8c185e407c60f6b6b547e712fd4247d337a417c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A1s=20V=C3=A1czi?= Date: Wed, 8 Nov 2017 11:04:56 +0100 Subject: [PATCH 2/3] Stackeblockenize the first section of the readme --- README.md | 59 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 32646a3d1..baa17ef87 100644 --- a/README.md +++ b/README.md @@ -6,21 +6,25 @@ The Postgres operator manages PostgreSQL clusters on Kubernetes using the [operator pattern](https://coreos.com/blog/introducing-operators.html). During the initial run it registers the [Custom Resource Definition (CRD)](https://kubernetes.io/docs/concepts/api-extension/custom-resources/#customresourcedefinitions) for Postgres. -The Postgresql CRD is essentially the schema that describes the contents of the manifests for deploying individual Postgresql clusters using Statefulsets and [Patroni](https://github.com/zalando/patroni). +The PostgreSQL CRD is essentially the schema that describes the contents of the manifests for deploying individual +PostgreSQL clusters using StatefulSets and [Patroni](https://github.com/zalando/patroni). Once the operator is running, it performs the following actions: -* watches for new Postgres cluster manifests and deploys corresponding clusters. -* watches for updates to existing manifests and changes corresponding properties of the running clusters. -* watches for deletes of the existing manifests and deletes corresponding database clusters. -* acts on an update to the operator definition itself and changes the running clusters when necessary (i.e. when the docker image inside the operator definition has been updated.) -* periodically checks running clusters against the manifests and acts on the differences found. +* watches for new PostgreSQL cluster manifests and deploys corresponding clusters +* watches for updates to existing manifests and changes corresponding properties of the running clusters +* watches for deletes of the existing manifests and deletes corresponding clusters +* acts on an update to the operator definition itself and changes the running clusters when necessary + (i.e. when the docker image inside the operator definition has been updated) +* periodically checks running clusters against the manifests and acts on the differences found -For instance, when the user creates a new custom object of type postgresql by submitting a new manifest with kubectl, the operator fetches that object and creates the corresponding kubernetes structures (StatefulSets, Services, Secrets) according to its definition. +For instance, when the user creates a new custom object of type ``postgresql`` by submitting a new manifest with +``kubectl``, the operator fetches that object and creates the corresponding Kubernetes structures +(StatefulSets, Services, Secrets) according to its definition. -Another example is changing the docker image inside the operator. In this case, the operator first goes to all Statefulsets -it manages and updates them with the new docker images; afterwards, all pods from each Statefulset are killed one by one -(rolling upgrade) and the replacements are spawned automatically by each Statefulset with the new docker image. +Another example is changing the docker image inside the operator. In this case, the operator first goes to all StatefulSets +it manages and updates them with the new docker images; afterwards, all pods from each StatefulSet are killed one by one +(rolling upgrade) and the replacements are spawned automatically by each StatefulSet with the new docker image. ## Status @@ -29,42 +33,44 @@ Please, report any issues discovered to https://github.com/zalando-incubator/pos ## Running and testing the operator -The best way to test the operator is to run it in minikube. Minikube is a tool to run Kubernetes cluster locally. +The best way to test the operator is to run it in [minikube](https://kubernetes.io/docs/getting-started-guides/minikube/). +Minikube is a tool to run Kubernetes cluster locally. ### Installing and starting minikube See [minikube installation guide](https://github.com/kubernetes/minikube/releases) Make sure you use the latest version of Minikube. -After the installation, issue the + +After the installation, issue $ minikube start Note: if you are running on a Mac, make sure to use the [xhyve driver](https://github.com/kubernetes/minikube/blob/master/docs/drivers.md#xhyve-driver) instead of the default docker-machine one for performance reasons. -One you have it started successfully, use [the quickstart guide](https://github.com/kubernetes/minikube#quickstart) in order +Once you have it started successfully, use [the quickstart guide](https://github.com/kubernetes/minikube#quickstart) in order to test your that your setup is working. -Note: if you use multiple kubernetes clusters, you can switch to minikube with `kubectl config use-context minikube` +Note: if you use multiple Kubernetes clusters, you can switch to Minikube with `kubectl config use-context minikube` ### Create ConfigMap -ConfigMap is used to store configuration of the operator +ConfigMap is used to store the configuration of the operator $ kubectl --context minikube create -f manifests/configmap.yaml ### Deploying the operator -First you need to install the service account definition in your minikube cluster. +First you need to install the service account definition in your Minikube cluster. $ kubectl --context minikube create -f manifests/serviceaccount.yaml -Next deploy the postgers-operator from the Docker image Zalando is using: +Next deploy the postgres-operator from the docker image Zalando is using: $ kubectl --context minikube create -f manifests/postgres-operator.yaml -If you perfer to build the image yourself follow up down below. +If you prefer to build the image yourself follow up down below. ### Check if CustomResourceDefinition has been registered @@ -74,11 +80,11 @@ If you perfer to build the image yourself follow up down below. postgresqls.acid.zalan.do CustomResourceDefinition.v1beta1.apiextensions.k8s.io -### Create a new spilo cluster +### Create a new Spilo cluster $ kubectl --context minikube create -f manifests/minimal-postgres-manifest.yaml -### Watch Pods being created +### Watch pods being created $ kubectl --context minikube get pods -w --show-labels @@ -97,9 +103,11 @@ We can use the generated secret of the `postgres` robot user to connect to our ` The operator can be configured with the provided ConfigMap (`manifests/configmap.yaml`). -#### Use Taints and Tolerations for Dedicated Postgres Nodes +#### Use taints and tolerations for dedicated PostgreSQL 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. +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: @@ -107,7 +115,7 @@ As an example you can set following node taint: $ kubectl taint nodes postgres=:NoSchedule ``` -And configure the toleration for the Postgres pods by adding following line to the ConfigMap: +And configure the toleration for the PostgreSQL pods by adding following line to the ConfigMap: ``` apiVersion: v1 @@ -119,7 +127,7 @@ data: ... ``` -Or you can specify and/or overwrite the tolerations for each postgres instance in the postgres manifest: +Or you can specify and/or overwrite the tolerations for each PostgreSQL instance in the manifest: ``` apiVersion: "acid.zalan.do/v1" @@ -134,7 +142,8 @@ spec: 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. +Please be aware that the taint and toleration only ensures that no other pod gets scheduled to a PostgreSQL node +but not that PostgreSQL pods are placed on such a node. This can be achieved by setting a node affinity rule in the ConfigMap. # Setup development environment From c25e849fe4a89dbf7a81c89b1b18d83b1177c0d9 Mon Sep 17 00:00:00 2001 From: Oleksii Kliukin Date: Wed, 8 Nov 2017 18:10:48 +0100 Subject: [PATCH 3/3] Fix a failure to create new statefulset at sync. Also do a fmt run. --- pkg/cluster/cluster.go | 1 + pkg/cluster/k8sres.go | 2 +- pkg/cluster/sync.go | 37 ++++++++++++++++--------------------- pkg/util/config/config.go | 2 +- 4 files changed, 19 insertions(+), 23 deletions(-) diff --git a/pkg/cluster/cluster.go b/pkg/cluster/cluster.go index e7160ff01..6c39e4c01 100644 --- a/pkg/cluster/cluster.go +++ b/pkg/cluster/cluster.go @@ -495,6 +495,7 @@ func (c *Cluster) Update(oldSpec, newSpec *spec.Postgresql) error { if !reflect.DeepEqual(oldSs, newSs) { c.logger.Debugf("syncing statefulsets") + // TODO: avoid generating the StatefulSet object twice by passing it to syncStatefulSet if err := c.syncStatefulSet(); err != nil { c.logger.Errorf("could not sync statefulsets: %v", err) updateFailed = true diff --git a/pkg/cluster/k8sres.go b/pkg/cluster/k8sres.go index d0337c64b..426ed9012 100644 --- a/pkg/cluster/k8sres.go +++ b/pkg/cluster/k8sres.go @@ -262,7 +262,7 @@ func (c *Cluster) tolerations(tolerationsSpec *[]v1.Toleration) []v1.Toleration } podToleration := c.Config.OpConfig.PodToleration - if (len(podToleration["key"]) > 0 || len(podToleration["operator"]) > 0 || len(podToleration["value"]) > 0 || len(podToleration["effect"]) > 0) { + if len(podToleration["key"]) > 0 || len(podToleration["operator"]) > 0 || len(podToleration["value"]) > 0 || len(podToleration["effect"]) > 0 { return []v1.Toleration{ { Key: podToleration["key"], diff --git a/pkg/cluster/sync.go b/pkg/cluster/sync.go index 1d4649917..43b039888 100644 --- a/pkg/cluster/sync.go +++ b/pkg/cluster/sync.go @@ -238,29 +238,20 @@ func (c *Cluster) syncPodDisruptionBudget(isUpdate bool) error { } func (c *Cluster) syncStatefulSet() error { - var ( - err error - rollUpdate bool - ) - c.Statefulset, err = c.KubeClient.StatefulSets(c.Namespace).Get(c.statefulSetName(), metav1.GetOptions{}) - - if err != nil && !k8sutil.ResourceNotFound(err) { - return fmt.Errorf("could not get statefulset: %v", err) - } - if err != nil && k8sutil.ResourceNotFound(err) { + sset, err := c.KubeClient.StatefulSets(c.Namespace).Get(c.statefulSetName(), metav1.GetOptions{}) + if err != nil { + if !k8sutil.ResourceNotFound(err) { + return fmt.Errorf("could not get statefulset: %v", err) + } + // statefulset does not exist, try to re-create it c.logger.Infof("could not find the cluster's statefulset") pods, err := c.listPods() if err != nil { return fmt.Errorf("could not list pods of the statefulset: %v", err) } - if len(pods) > 0 { - c.logger.Infof("found pods without the statefulset: trigger rolling update") - rollUpdate = true - } - - ss, err := c.createStatefulSet() + sset, err = c.createStatefulSet() if err != nil { return fmt.Errorf("could not create missing statefulset: %v", err) } @@ -269,14 +260,16 @@ func (c *Cluster) syncStatefulSet() error { return fmt.Errorf("cluster is not ready: %v", err) } - c.logger.Infof("created missing statefulset %q", util.NameFromMeta(ss.ObjectMeta)) - if !rollUpdate { + c.logger.Infof("created missing statefulset %q", util.NameFromMeta(sset.ObjectMeta)) + if len(pods) <= 0 { return nil } - } + c.logger.Infof("found pods without the statefulset: trigger rolling update") + + } else { + // statefulset is alrady there, make sure we use its definition in order to compare with the spec. + c.Statefulset = sset - /* TODO: should check that we need to replace the statefulset */ - if !rollUpdate { desiredSS, err := c.generateStatefulSet(&c.Spec) if err != nil { return fmt.Errorf("could not generate statefulset: %v", err) @@ -303,6 +296,8 @@ func (c *Cluster) syncStatefulSet() error { return nil } } + // if we get here we also need to re-create the pods (either leftovers from the old + // statefulset or those that got their configuration from the outdated statefulset) c.logger.Debugln("performing rolling update") if err := c.recreatePods(); err != nil { return fmt.Errorf("could not recreate pods: %v", err) diff --git a/pkg/util/config/config.go b/pkg/util/config/config.go index caf617aea..b01494142 100644 --- a/pkg/util/config/config.go +++ b/pkg/util/config/config.go @@ -25,7 +25,7 @@ type Resources struct { ClusterLabels map[string]string `name:"cluster_labels" default:"application:spilo"` ClusterNameLabel string `name:"cluster_name_label" default:"cluster-name"` PodRoleLabel string `name:"pod_role_label" default:"spilo-role"` - PodToleration map[string]string `name:"toleration" default:""` + PodToleration map[string]string `name:"toleration" default:""` DefaultCPURequest string `name:"default_cpu_request" default:"100m"` DefaultMemoryRequest string `name:"default_memory_request" default:"100Mi"` DefaultCPULimit string `name:"default_cpu_limit" default:"3"`