Merge branch 'master' into delete-volume-on-scale-down

This commit is contained in:
Sergey Dudoladov 2020-04-08 07:18:49 +02:00
commit a562a6ed59
20 changed files with 104 additions and 30 deletions

View File

@ -68,6 +68,8 @@ spec:
type: boolean type: boolean
etcd_host: etcd_host:
type: string type: string
kubernetes_use_configmaps:
type: boolean
max_instances: max_instances:
type: integer type: integer
minimum: -1 # -1 = disabled minimum: -1 # -1 = disabled

View File

@ -218,6 +218,10 @@ spec:
type: integer type: integer
retry_timeout: retry_timeout:
type: integer type: integer
synchronous_mode:
type: boolean
synchronous_mode_strict:
type: boolean
maximum_lag_on_failover: maximum_lag_on_failover:
type: integer type: integer
podAnnotations: podAnnotations:

View File

@ -25,6 +25,8 @@ configGeneral:
enable_unused_pvc_deletion: false enable_unused_pvc_deletion: false
# etcd connection string for Patroni. Empty uses K8s-native DCS. # etcd connection string for Patroni. Empty uses K8s-native DCS.
etcd_host: "" etcd_host: ""
# Select if setup uses endpoints (default), or configmaps to manage leader (DCS=k8s)
# kubernetes_use_configmaps: false
# Spilo docker image # Spilo docker image
docker_image: registry.opensource.zalan.do/acid/spilo-12:1.6-p2 docker_image: registry.opensource.zalan.do/acid/spilo-12:1.6-p2
# max number of instances in Postgres cluster. -1 = no limit # max number of instances in Postgres cluster. -1 = no limit

View File

@ -25,6 +25,8 @@ configGeneral:
enable_unused_pvc_deletion: "false" enable_unused_pvc_deletion: "false"
# etcd connection string for Patroni. Empty uses K8s-native DCS. # etcd connection string for Patroni. Empty uses K8s-native DCS.
etcd_host: "" etcd_host: ""
# Select if setup uses endpoints (default), or configmaps to manage leader (DCS=k8s)
# kubernetes_use_configmaps: "false"
# Spilo docker image # Spilo docker image
docker_image: registry.opensource.zalan.do/acid/spilo-12:1.6-p2 docker_image: registry.opensource.zalan.do/acid/spilo-12:1.6-p2
# max number of instances in Postgres cluster. -1 = no limit # max number of instances in Postgres cluster. -1 = no limit

View File

@ -217,6 +217,12 @@ explanation of `ttl` and `loop_wait` parameters.
automatically created by Patroni for cluster members and permanent replication automatically created by Patroni for cluster members and permanent replication
slots. Optional. slots. Optional.
* **synchronous_mode**
Patroni `synchronous_mode` parameter value. The default is set to `false`. Optional.
* **synchronous_mode_strict**
Patroni `synchronous_mode_strict` parameter value. Can be used in addition to `synchronous_mode`. The default is set to `false`. Optional.
## Postgres container resources ## Postgres container resources
Those parameters define [CPU and memory requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/) Those parameters define [CPU and memory requests and limits](https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/)
@ -376,10 +382,11 @@ present.
How many instances of connection pooler to create. How many instances of connection pooler to create.
* **schema** * **schema**
Schema to create for credentials lookup function. Database schema to create for credentials lookup function.
* **user** * **user**
User to create for connection pooler to be able to connect to a database. User to create for connection pooler to be able to connect to a database.
You can also choose a role from the `users` section or a system user role.
* **dockerImage** * **dockerImage**
Which docker image to use for connection pooler deployment. Which docker image to use for connection pooler deployment.

View File

@ -80,6 +80,12 @@ Those are top-level keys, containing both leaf keys and groups.
Patroni native Kubernetes support is used. The default is empty (use Patroni native Kubernetes support is used. The default is empty (use
Kubernetes-native DCS). Kubernetes-native DCS).
* **kubernetes_use_configmaps**
Select if setup uses endpoints (default), or configmaps to manage leader when
DCS is kubernetes (not etcd or similar). In OpenShift it is not possible to
use endpoints option, and configmaps is required. By default,
`kubernetes_use_configmaps: false`, meaning endpoints will be used.
* **docker_image** * **docker_image**
Spilo Docker image for Postgres instances. For production, don't rely on the Spilo Docker image for Postgres instances. For production, don't rely on the
default image, as it might be not the most up-to-date one. Instead, build default image, as it might be not the most up-to-date one. Instead, build
@ -613,11 +619,14 @@ operator being able to provide some reasonable defaults.
the required minimum. the required minimum.
* **connection_pooler_schema** * **connection_pooler_schema**
Schema to create for credentials lookup function. Default is `pooler`. Database schema to create for credentials lookup function to be used by the
connection pooler. Is is created in every database of the Postgres cluster.
You can also choose an existing schema. Default schema is `pooler`.
* **connection_pooler_user** * **connection_pooler_user**
User to create for connection pooler to be able to connect to a database. User to create for connection pooler to be able to connect to a database.
Default is `pooler`. You can also choose an existing role, but make sure it has the `LOGIN`
privilege. Default role is `pooler`.
* **connection_pooler_image** * **connection_pooler_image**
Docker image to use for connection pooler deployment. Docker image to use for connection pooler deployment.

View File

@ -527,7 +527,7 @@ spec:
This will tell the operator to create a connection pooler with default This will tell the operator to create a connection pooler with default
configuration, through which one can access the master via a separate service configuration, through which one can access the master via a separate service
`{cluster-name}-pooler`. In most of the cases the `{cluster-name}-pooler`. In most of the cases the
[default configuration](reference/operator_parameters.md#connection-pool-configuration) [default configuration](reference/operator_parameters.md#connection-pooler-configuration)
should be good enough. To configure a new connection pooler individually for should be good enough. To configure a new connection pooler individually for
each Postgres cluster, specify: each Postgres cluster, specify:
@ -540,7 +540,8 @@ spec:
# in which mode to run, session or transaction # in which mode to run, session or transaction
mode: "transaction" mode: "transaction"
# schema, which operator will create to install credentials lookup function # schema, which operator will create in each database
# to install credentials lookup function for connection pooler
schema: "pooler" schema: "pooler"
# user, which operator will create for connection pooler # user, which operator will create for connection pooler
@ -560,11 +561,11 @@ The `enableConnectionPooler` flag is not required when the `connectionPooler`
section is present in the manifest. But, it can be used to disable/remove the section is present in the manifest. But, it can be used to disable/remove the
pooler while keeping its configuration. pooler while keeping its configuration.
By default, `pgbouncer` is used as connection pooler. To find out about pooler By default, [`PgBouncer`](https://www.pgbouncer.org/) is used as connection pooler.
modes read the `pgbouncer` [docs](https://www.pgbouncer.org/config.html#pooler_mode) To find out about pool modes read the `PgBouncer` [docs](https://www.pgbouncer.org/config.html#pooler_mode)
(but it should be the general approach between different implementation). (but it should be the general approach between different implementation).
Note, that using `pgbouncer` a meaningful resource CPU limit should be 1 core Note, that using `PgBouncer` a meaningful resource CPU limit should be 1 core
or less (there is a way to utilize more than one, but in K8s it's easier just to or less (there is a way to utilize more than one, but in K8s it's easier just to
spin up more instances). spin up more instances).

View File

@ -67,6 +67,8 @@ spec:
ttl: 30 ttl: 30
loop_wait: &loop_wait 10 loop_wait: &loop_wait 10
retry_timeout: 10 retry_timeout: 10
synchronous_mode: false
synchronous_mode_strict: false
maximum_lag_on_failover: 33554432 maximum_lag_on_failover: 33554432
# restore a Postgres DB with point-in-time-recovery # restore a Postgres DB with point-in-time-recovery

View File

@ -15,7 +15,7 @@ data:
# connection_pooler_default_cpu_request: "500m" # connection_pooler_default_cpu_request: "500m"
# connection_pooler_default_memory_limit: 100Mi # connection_pooler_default_memory_limit: 100Mi
# connection_pooler_default_memory_request: 100Mi # connection_pooler_default_memory_request: 100Mi
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-5" connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-6"
# connection_pooler_max_db_connections: 60 # connection_pooler_max_db_connections: 60
# connection_pooler_mode: "transaction" # connection_pooler_mode: "transaction"
# connection_pooler_number_of_instances: 2 # connection_pooler_number_of_instances: 2
@ -43,6 +43,7 @@ data:
# enable_team_superuser: "false" # enable_team_superuser: "false"
enable_teams_api: "false" enable_teams_api: "false"
# etcd_host: "" # etcd_host: ""
# kubernetes_use_configmaps: "false"
# infrastructure_roles_secret_name: postgresql-infrastructure-roles # infrastructure_roles_secret_name: postgresql-infrastructure-roles
# inherited_labels: application,environment # inherited_labels: application,environment
# kube_iam_role: "" # kube_iam_role: ""

View File

@ -44,6 +44,8 @@ spec:
type: boolean type: boolean
etcd_host: etcd_host:
type: string type: string
kubernetes_use_configmaps:
type: boolean
max_instances: max_instances:
type: integer type: integer
minimum: -1 # -1 = disabled minimum: -1 # -1 = disabled

View File

@ -5,6 +5,7 @@ metadata:
configuration: configuration:
# enable_crd_validation: true # enable_crd_validation: true
etcd_host: "" etcd_host: ""
# kubernetes_use_configmaps: false
docker_image: registry.opensource.zalan.do/acid/spilo-12:1.6-p2 docker_image: registry.opensource.zalan.do/acid/spilo-12:1.6-p2
# enable_shm_volume: true # enable_shm_volume: true
# enable_unused_pvc_deletion: false # enable_unused_pvc_deletion: false
@ -127,7 +128,7 @@ configuration:
connection_pooler_default_cpu_request: "500m" connection_pooler_default_cpu_request: "500m"
connection_pooler_default_memory_limit: 100Mi connection_pooler_default_memory_limit: 100Mi
connection_pooler_default_memory_request: 100Mi connection_pooler_default_memory_request: 100Mi
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-5" connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-6"
# connection_pooler_max_db_connections: 60 # connection_pooler_max_db_connections: 60
connection_pooler_mode: "transaction" connection_pooler_mode: "transaction"
connection_pooler_number_of_instances: 2 connection_pooler_number_of_instances: 2

View File

@ -184,6 +184,10 @@ spec:
type: integer type: integer
maximum_lag_on_failover: maximum_lag_on_failover:
type: integer type: integer
synchronous_mode:
type: boolean
synchronous_mode_strict:
type: boolean
podAnnotations: podAnnotations:
type: object type: object
additionalProperties: additionalProperties:

View File

@ -358,6 +358,12 @@ var PostgresCRDResourceValidation = apiextv1beta1.CustomResourceValidation{
"maximum_lag_on_failover": { "maximum_lag_on_failover": {
Type: "integer", Type: "integer",
}, },
"synchronous_mode": {
Type: "boolean",
},
"synchronous_mode_strict": {
Type: "boolean",
},
}, },
}, },
"podAnnotations": { "podAnnotations": {
@ -727,6 +733,9 @@ var OperatorConfigCRDResourceValidation = apiextv1beta1.CustomResourceValidation
"etcd_host": { "etcd_host": {
Type: "string", Type: "string",
}, },
"kubernetes_use_configmaps": {
Type: "boolean",
},
"max_instances": { "max_instances": {
Type: "integer", Type: "integer",
Description: "-1 = disabled", Description: "-1 = disabled",

View File

@ -183,6 +183,7 @@ type OperatorLogicalBackupConfiguration struct {
type OperatorConfigurationData struct { type OperatorConfigurationData struct {
EnableCRDValidation *bool `json:"enable_crd_validation,omitempty"` EnableCRDValidation *bool `json:"enable_crd_validation,omitempty"`
EtcdHost string `json:"etcd_host,omitempty"` EtcdHost string `json:"etcd_host,omitempty"`
KubernetesUseConfigMaps bool `json:"kubernetes_use_configmaps,omitempty"`
DockerImage string `json:"docker_image,omitempty"` DockerImage string `json:"docker_image,omitempty"`
Workers uint32 `json:"workers,omitempty"` Workers uint32 `json:"workers,omitempty"`
MinInstances int32 `json:"min_instances,omitempty"` MinInstances int32 `json:"min_instances,omitempty"`

View File

@ -125,6 +125,8 @@ type Patroni struct {
RetryTimeout uint32 `json:"retry_timeout"` RetryTimeout uint32 `json:"retry_timeout"`
MaximumLagOnFailover float32 `json:"maximum_lag_on_failover"` // float32 because https://github.com/kubernetes/kubernetes/issues/30213 MaximumLagOnFailover float32 `json:"maximum_lag_on_failover"` // float32 because https://github.com/kubernetes/kubernetes/issues/30213
Slots map[string]map[string]string `json:"slots"` Slots map[string]map[string]string `json:"slots"`
SynchronousMode bool `json:"synchronous_mode"`
SynchronousModeStrict bool `json:"synchronous_mode_strict"`
} }
//StandbyCluster //StandbyCluster

View File

@ -49,6 +49,8 @@ type patroniDCS struct {
LoopWait uint32 `json:"loop_wait,omitempty"` LoopWait uint32 `json:"loop_wait,omitempty"`
RetryTimeout uint32 `json:"retry_timeout,omitempty"` RetryTimeout uint32 `json:"retry_timeout,omitempty"`
MaximumLagOnFailover float32 `json:"maximum_lag_on_failover,omitempty"` MaximumLagOnFailover float32 `json:"maximum_lag_on_failover,omitempty"`
SynchronousMode bool `json:"synchronous_mode,omitempty"`
SynchronousModeStrict bool `json:"synchronous_mode_strict,omitempty"`
PGBootstrapConfiguration map[string]interface{} `json:"postgresql,omitempty"` PGBootstrapConfiguration map[string]interface{} `json:"postgresql,omitempty"`
Slots map[string]map[string]string `json:"slots,omitempty"` Slots map[string]map[string]string `json:"slots,omitempty"`
} }
@ -283,6 +285,12 @@ PatroniInitDBParams:
if patroni.Slots != nil { if patroni.Slots != nil {
config.Bootstrap.DCS.Slots = patroni.Slots config.Bootstrap.DCS.Slots = patroni.Slots
} }
if patroni.SynchronousMode {
config.Bootstrap.DCS.SynchronousMode = patroni.SynchronousMode
}
if patroni.SynchronousModeStrict != false {
config.Bootstrap.DCS.SynchronousModeStrict = patroni.SynchronousModeStrict
}
config.PgLocalConfiguration = make(map[string]interface{}) config.PgLocalConfiguration = make(map[string]interface{})
config.PgLocalConfiguration[patroniPGBinariesParameterName] = fmt.Sprintf(pgBinariesLocationTemplate, pg.PgVersion) config.PgLocalConfiguration[patroniPGBinariesParameterName] = fmt.Sprintf(pgBinariesLocationTemplate, pg.PgVersion)
@ -672,6 +680,10 @@ func (c *Cluster) generateSpiloPodEnvVars(uid types.UID, spiloConfiguration stri
envVars = append(envVars, v1.EnvVar{Name: "ETCD_HOST", Value: c.OpConfig.EtcdHost}) envVars = append(envVars, v1.EnvVar{Name: "ETCD_HOST", Value: c.OpConfig.EtcdHost})
} }
if c.patroniKubernetesUseConfigMaps() {
envVars = append(envVars, v1.EnvVar{Name: "KUBERNETES_USE_CONFIGMAPS", Value: "true"})
}
if cloneDescription.ClusterName != "" { if cloneDescription.ClusterName != "" {
envVars = append(envVars, c.generateCloneEnvironment(cloneDescription)...) envVars = append(envVars, c.generateCloneEnvironment(cloneDescription)...)
} }
@ -1406,7 +1418,7 @@ func (c *Cluster) generateService(role PostgresRole, spec *acidv1.PostgresSpec)
Type: v1.ServiceTypeClusterIP, Type: v1.ServiceTypeClusterIP,
} }
if role == Replica { if role == Replica || c.patroniKubernetesUseConfigMaps() {
serviceSpec.Selector = c.roleLabelsSet(false, role) serviceSpec.Selector = c.roleLabelsSet(false, role)
} }

View File

@ -70,11 +70,13 @@ func TestGenerateSpiloJSONConfiguration(t *testing.T) {
LoopWait: 10, LoopWait: 10,
RetryTimeout: 10, RetryTimeout: 10,
MaximumLagOnFailover: 33554432, MaximumLagOnFailover: 33554432,
SynchronousMode: true,
SynchronousModeStrict: true,
Slots: map[string]map[string]string{"permanent_logical_1": {"type": "logical", "database": "foo", "plugin": "pgoutput"}}, Slots: map[string]map[string]string{"permanent_logical_1": {"type": "logical", "database": "foo", "plugin": "pgoutput"}},
}, },
role: "zalandos", role: "zalandos",
opConfig: config.Config{}, opConfig: config.Config{},
result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/11/bin","pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"zalandos":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}}}}`, result: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/11/bin","pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"zalandos":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"synchronous_mode":true,"synchronous_mode_strict":true,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}}}}`,
}, },
} }
for _, tt := range tests { for _, tt := range tests {

View File

@ -510,6 +510,15 @@ func (c *Cluster) patroniUsesKubernetes() bool {
return c.OpConfig.EtcdHost == "" return c.OpConfig.EtcdHost == ""
} }
func (c *Cluster) patroniKubernetesUseConfigMaps() bool {
if !c.patroniUsesKubernetes() {
return false
}
// otherwise, follow the operator configuration
return c.OpConfig.KubernetesUseConfigMaps
}
func (c *Cluster) needConnectionPoolerWorker(spec *acidv1.PostgresSpec) bool { func (c *Cluster) needConnectionPoolerWorker(spec *acidv1.PostgresSpec) bool {
if spec.EnableConnectionPooler == nil { if spec.EnableConnectionPooler == nil {
return spec.ConnectionPooler != nil return spec.ConnectionPooler != nil

View File

@ -35,6 +35,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
// general config // general config
result.EnableCRDValidation = fromCRD.EnableCRDValidation result.EnableCRDValidation = fromCRD.EnableCRDValidation
result.EtcdHost = fromCRD.EtcdHost result.EtcdHost = fromCRD.EtcdHost
result.KubernetesUseConfigMaps = fromCRD.KubernetesUseConfigMaps
result.DockerImage = fromCRD.DockerImage result.DockerImage = fromCRD.DockerImage
result.Workers = fromCRD.Workers result.Workers = fromCRD.Workers
result.MinInstances = fromCRD.MinInstances result.MinInstances = fromCRD.MinInstances

View File

@ -108,6 +108,7 @@ type Config struct {
ConnectionPooler ConnectionPooler
WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to' WatchedNamespace string `name:"watched_namespace"` // special values: "*" means 'watch all namespaces', the empty string "" means 'watch a namespace where operator is deployed to'
KubernetesUseConfigMaps bool `name:"kubernetes_use_configmaps" default:"false"`
EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS EtcdHost string `name:"etcd_host" default:""` // special values: the empty string "" means Patroni will use K8s as a DCS
DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spilo-12:1.6-p2"` DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spilo-12:1.6-p2"`
Sidecars map[string]string `name:"sidecar_docker_images"` Sidecars map[string]string `name:"sidecar_docker_images"`