merged master

This commit is contained in:
Felix Kunde 2019-07-05 17:34:45 +02:00
commit 9b5e745086
15 changed files with 54 additions and 37 deletions

View File

@ -18,6 +18,7 @@ data:
docker_image: {{ .Values.docker_image }} docker_image: {{ .Values.docker_image }}
debug_logging: "{{ .Values.configDebug.debug_logging }}" debug_logging: "{{ .Values.configDebug.debug_logging }}"
enable_database_access: "{{ .Values.configDebug.enable_database_access }}" enable_database_access: "{{ .Values.configDebug.enable_database_access }}"
enable_shm_volume: "{{ .Values.enable_shm_volume }}"
repair_period: {{ .Values.repair_period }} repair_period: {{ .Values.repair_period }}
resync_period: {{ .Values.resync_period }} resync_period: {{ .Values.resync_period }}
ring_log_lines: "{{ .Values.configLoggingRestApi.ring_log_lines }}" ring_log_lines: "{{ .Values.configLoggingRestApi.ring_log_lines }}"

View File

@ -9,6 +9,7 @@ metadata:
app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/instance: {{ .Release.Name }}
configuration: configuration:
docker_image: {{ .Values.docker_image }} docker_image: {{ .Values.docker_image }}
enable_shm_volume: {{ .Values.enable_shm_volume }}
repair_period: {{ .Values.repair_period }} repair_period: {{ .Values.repair_period }}
resync_period: {{ .Values.resync_period }} resync_period: {{ .Values.resync_period }}
workers: {{ .Values.workers }} workers: {{ .Values.workers }}

View File

@ -15,6 +15,7 @@ podLabels: {}
# config shared from ConfigMap and CRD # config shared from ConfigMap and CRD
docker_image: registry.opensource.zalan.do/acid/spilo-11:1.5-p7 docker_image: registry.opensource.zalan.do/acid/spilo-11:1.5-p7
enable_shm_volume: true
repair_period: 5m repair_period: 5m
resync_period: 5m resync_period: 5m
spilo_privileged: false spilo_privileged: false

View File

@ -51,10 +51,12 @@ Please, report any issues discovered to https://github.com/zalando/postgres-oper
## Talks ## Talks
1. "PostgreSQL and Kubernetes: DBaaS without a vendor-lock" talk by Oleksii Kliukin, PostgreSQL Sessions 2018: [video](https://www.youtube.com/watch?v=q26U2rQcqMw) | [slides](https://speakerdeck.com/alexeyklyukin/postgresql-and-kubernetes-dbaas-without-a-vendor-lock) 1. "Building your own PostgreSQL-as-a-Service on Kubernetes" talk by Alexander Kukushkin, KubeCon NA 2018: [video](https://www.youtube.com/watch?v=G8MnpkbhClc) | [slides](https://static.sched.com/hosted_files/kccna18/1d/Building%20your%20own%20PostgreSQL-as-a-Service%20on%20Kubernetes.pdf)
2. "PostgreSQL High Availability on Kubernetes with Patroni" talk by Oleksii Kliukin, Atmosphere 2018: [video](https://www.youtube.com/watch?v=cFlwQOPPkeg) | [slides](https://speakerdeck.com/alexeyklyukin/postgresql-high-availability-on-kubernetes-with-patroni) 2. "PostgreSQL and Kubernetes: DBaaS without a vendor-lock" talk by Oleksii Kliukin, PostgreSQL Sessions 2018: [video](https://www.youtube.com/watch?v=q26U2rQcqMw) | [slides](https://speakerdeck.com/alexeyklyukin/postgresql-and-kubernetes-dbaas-without-a-vendor-lock)
2. "Blue elephant on-demand: Postgres + Kubernetes" talk by Oleksii Kliukin and Jan Mussler, FOSDEM 2018: [video](https://fosdem.org/2018/schedule/event/blue_elephant_on_demand_postgres_kubernetes/) | [slides (pdf)](https://www.postgresql.eu/events/fosdem2018/sessions/session/1735/slides/59/FOSDEM%202018_%20Blue_Elephant_On_Demand.pdf) 3. "PostgreSQL High Availability on Kubernetes with Patroni" talk by Oleksii Kliukin, Atmosphere 2018: [video](https://www.youtube.com/watch?v=cFlwQOPPkeg) | [slides](https://speakerdeck.com/alexeyklyukin/postgresql-high-availability-on-kubernetes-with-patroni)
4. "Blue elephant on-demand: Postgres + Kubernetes" talk by Oleksii Kliukin and Jan Mussler, FOSDEM 2018: [video](https://fosdem.org/2018/schedule/event/blue_elephant_on_demand_postgres_kubernetes/) | [slides (pdf)](https://www.postgresql.eu/events/fosdem2018/sessions/session/1735/slides/59/FOSDEM%202018_%20Blue_Elephant_On_Demand.pdf)
3. "Kube-Native Postgres" talk by Josh Berkus, KubeCon 2017: [video](https://www.youtube.com/watch?v=Zn1vd7sQ_bc) 3. "Kube-Native Postgres" talk by Josh Berkus, KubeCon 2017: [video](https://www.youtube.com/watch?v=Zn1vd7sQ_bc)

View File

@ -85,6 +85,14 @@ Those are top-level keys, containing both leaf keys and groups.
Spilo. In case of the name conflict with the definition in the cluster Spilo. In case of the name conflict with the definition in the cluster
manifest the cluster-specific one is preferred. manifest the cluster-specific one is preferred.
* **enable_shm_volume**
Instruct operator to start any new database pod without limitations on shm
memory. If this option is enabled, to the target database pod will be mounted
a new tmpfs volume to remove shm memory limitation (see e.g. the
[docker issue](https://github.com/docker-library/postgres/issues/416)).
This option is global for an operator object, and can be overwritten by
`enableShmVolume` parameter from Postgres manifest. The default is `true`.
* **workers** * **workers**
number of working routines the operator spawns to process requests to number of working routines the operator spawns to process requests to
create/update/delete/sync clusters concurrently. The default is `4`. create/update/delete/sync clusters concurrently. The default is `4`.
@ -298,14 +306,6 @@ CRD-based configuration.
container, change the [operator deployment manually](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml#L13). container, change the [operator deployment manually](https://github.com/zalando/postgres-operator/blob/master/manifests/postgres-operator.yaml#L13).
The default is `false`. The default is `false`.
* **enable_shm_volume**
Instruct operator to start any new database pod without limitations on shm
memory. If this option is enabled, to the target database pod will be mounted
a new tmpfs volume to remove shm memory limitation (see e.g. the [docker
issue](https://github.com/docker-library/postgres/issues/416)). This option
is global for an operator object, and can be overwritten by `enableShmVolume`
parameter from Postgres manifest. The default is `true`
## Operator timeouts ## Operator timeouts
This set of parameters define various timeouts related to some operator This set of parameters define various timeouts related to some operator
@ -405,7 +405,7 @@ yet officially supported.
empty. empty.
* **aws_region** * **aws_region**
AWS region used to store ESB volumes. The default is `eu-central-1`. AWS region used to store EBS volumes. The default is `eu-central-1`.
* **additional_secret_mount** * **additional_secret_mount**
Additional Secret (aws or gcp credentials) to mount in the pod. The default is empty. Additional Secret (aws or gcp credentials) to mount in the pod. The default is empty.

View File

@ -17,6 +17,7 @@ data:
super_username: postgres super_username: postgres
enable_teams_api: "false" enable_teams_api: "false"
spilo_privileged: "false" spilo_privileged: "false"
# enable_shm_volume: "true"
# custom_service_annotations: # custom_service_annotations:
# "keyx:valuez,keya:valuea" # "keyx:valuez,keya:valuea"
# set_memory_request_to_limit: "true" # set_memory_request_to_limit: "true"

View File

@ -10,6 +10,7 @@ configuration:
max_instances: -1 max_instances: -1
resync_period: 30m resync_period: 30m
repair_period: 5m repair_period: 5m
# enable_shm_volume: true
#sidecar_docker_images: #sidecar_docker_images:
# example: "exampleimage:exampletag" # example: "exampleimage:exampletag"

View File

@ -155,6 +155,7 @@ type OperatorConfigurationData struct {
MaxInstances int32 `json:"max_instances,omitempty"` MaxInstances int32 `json:"max_instances,omitempty"`
ResyncPeriod Duration `json:"resync_period,omitempty"` ResyncPeriod Duration `json:"resync_period,omitempty"`
RepairPeriod Duration `json:"repair_period,omitempty"` RepairPeriod Duration `json:"repair_period,omitempty"`
ShmVolume *bool `json:"enable_shm_volume,omitempty"`
Sidecars map[string]string `json:"sidecar_docker_images,omitempty"` Sidecars map[string]string `json:"sidecar_docker_images,omitempty"`
PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"` PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"`
Kubernetes KubernetesMetaConfiguration `json:"kubernetes"` Kubernetes KubernetesMetaConfiguration `json:"kubernetes"`

View File

@ -8,6 +8,7 @@ import (
"testing" "testing"
"time" "time"
"github.com/zalando/postgres-operator/pkg/util"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
) )
@ -217,6 +218,7 @@ var unmarshalCluster = []struct {
"clone" : { "clone" : {
"cluster": "acid-batman" "cluster": "acid-batman"
}, },
"enableShmVolume": false,
"patroni": { "patroni": {
"initdb": { "initdb": {
"encoding": "UTF8", "encoding": "UTF8",
@ -269,6 +271,7 @@ var unmarshalCluster = []struct {
StorageClass: "SSD", StorageClass: "SSD",
SubPath: "subdir", SubPath: "subdir",
}, },
ShmVolume: util.False(),
Patroni: Patroni{ Patroni: Patroni{
InitDB: map[string]string{ InitDB: map[string]string{
"encoding": "UTF8", "encoding": "UTF8",
@ -316,7 +319,7 @@ var unmarshalCluster = []struct {
}, },
Error: "", Error: "",
}, },
marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"9.6","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"ACID","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`), marshal: []byte(`{"kind":"Postgresql","apiVersion":"acid.zalan.do/v1","metadata":{"name":"acid-testcluster1","creationTimestamp":null},"spec":{"postgresql":{"version":"9.6","parameters":{"log_statement":"all","max_connections":"10","shared_buffers":"32MB"}},"pod_priority_class_name":"spilo-pod-priority","volume":{"size":"5Gi","storageClass":"SSD", "subPath": "subdir"},"enableShmVolume":false,"patroni":{"initdb":{"data-checksums":"true","encoding":"UTF8","locale":"en_US.UTF-8"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"],"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"slots":{"permanent_logical_1":{"database":"foo","plugin":"pgoutput","type":"logical"}}},"resources":{"requests":{"cpu":"10m","memory":"50Mi"},"limits":{"cpu":"300m","memory":"3000Mi"}},"teamId":"ACID","allowedSourceRanges":["127.0.0.1/32"],"numberOfInstances":2,"users":{"zalando":["superuser","createdb"]},"maintenanceWindows":["Mon:01:00-06:00","Sat:00:00-04:00","05:00-05:15"],"clone":{"cluster":"acid-batman"}},"status":{"PostgresClusterStatus":""}}`),
err: nil}, err: nil},
// example with teamId set in input // example with teamId set in input
{ {

View File

@ -209,6 +209,11 @@ func (in *OperatorConfiguration) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData) { func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData) {
*out = *in *out = *in
if in.ShmVolume != nil {
in, out := &in.ShmVolume, &out.ShmVolume
*out = new(bool)
**out = **in
}
if in.Sidecars != nil { if in.Sidecars != nil {
in, out := &in.Sidecars, &out.Sidecars in, out := &in.Sidecars, &out.Sidecars
*out = make(map[string]string, len(*in)) *out = make(map[string]string, len(*in))

View File

@ -360,8 +360,6 @@ func generateContainer(
volumeMounts []v1.VolumeMount, volumeMounts []v1.VolumeMount,
privilegedMode bool, privilegedMode bool,
) *v1.Container { ) *v1.Container {
falseBool := false
return &v1.Container{ return &v1.Container{
Name: name, Name: name,
Image: *dockerImage, Image: *dockerImage,
@ -385,7 +383,7 @@ func generateContainer(
Env: envVars, Env: envVars,
SecurityContext: &v1.SecurityContext{ SecurityContext: &v1.SecurityContext{
Privileged: &privilegedMode, Privileged: &privilegedMode,
ReadOnlyRootFilesystem: &falseBool, ReadOnlyRootFilesystem: util.False(),
}, },
} }
} }
@ -421,9 +419,9 @@ func generateSidecarContainers(sidecars []acidv1.Sidecar,
// Check whether or not we're requested to mount an shm volume, // Check whether or not we're requested to mount an shm volume,
// taking into account that PostgreSQL manifest has precedence. // taking into account that PostgreSQL manifest has precedence.
func mountShmVolumeNeeded(opConfig config.Config, pgSpec *acidv1.PostgresSpec) bool { func mountShmVolumeNeeded(opConfig config.Config, pgSpec *acidv1.PostgresSpec) *bool {
if pgSpec.ShmVolume != nil { if pgSpec.ShmVolume != nil && *pgSpec.ShmVolume {
return *pgSpec.ShmVolume return pgSpec.ShmVolume
} }
return opConfig.ShmVolume return opConfig.ShmVolume
@ -442,7 +440,7 @@ func generatePodTemplate(
podServiceAccountName string, podServiceAccountName string,
kubeIAMRole string, kubeIAMRole string,
priorityClassName string, priorityClassName string,
shmVolume bool, shmVolume *bool,
podAntiAffinity bool, podAntiAffinity bool,
podAntiAffinityTopologyKey string, podAntiAffinityTopologyKey string,
additionalSecretMount string, additionalSecretMount string,
@ -467,7 +465,7 @@ func generatePodTemplate(
SecurityContext: &securityContext, SecurityContext: &securityContext,
} }
if shmVolume { if shmVolume != nil && *shmVolume {
addShmVolume(&podSpec) addShmVolume(&podSpec)
} }
@ -1478,7 +1476,7 @@ func (c *Cluster) generateLogicalBackupJob() (*batchv1beta1.CronJob, error) {
c.OpConfig.PodServiceAccountName, c.OpConfig.PodServiceAccountName,
c.OpConfig.KubeIAMRole, c.OpConfig.KubeIAMRole,
"", "",
false, util.False(),
false, false,
"", "",
"", "",

View File

@ -8,6 +8,7 @@ import (
"testing" "testing"
acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" acidv1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
"github.com/zalando/postgres-operator/pkg/util"
"github.com/zalando/postgres-operator/pkg/util/config" "github.com/zalando/postgres-operator/pkg/util/config"
"github.com/zalando/postgres-operator/pkg/util/constants" "github.com/zalando/postgres-operator/pkg/util/constants"
"github.com/zalando/postgres-operator/pkg/util/k8sutil" "github.com/zalando/postgres-operator/pkg/util/k8sutil"
@ -17,16 +18,6 @@ import (
"k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/intstr"
) )
func True() *bool {
b := true
return &b
}
func False() *bool {
b := false
return &b
}
func toIntStr(val int) *intstr.IntOrString { func toIntStr(val int) *intstr.IntOrString {
b := intstr.FromInt(val) b := intstr.FromInt(val)
return &b return &b
@ -118,14 +109,14 @@ func TestCreateLoadBalancerLogic(t *testing.T) {
{ {
subtest: "new format, load balancer is enabled for replica", subtest: "new format, load balancer is enabled for replica",
role: Replica, role: Replica,
spec: &acidv1.PostgresSpec{EnableReplicaLoadBalancer: True()}, spec: &acidv1.PostgresSpec{EnableReplicaLoadBalancer: util.True()},
opConfig: config.Config{}, opConfig: config.Config{},
result: true, result: true,
}, },
{ {
subtest: "new format, load balancer is disabled for replica", subtest: "new format, load balancer is disabled for replica",
role: Replica, role: Replica,
spec: &acidv1.PostgresSpec{EnableReplicaLoadBalancer: False()}, spec: &acidv1.PostgresSpec{EnableReplicaLoadBalancer: util.False()},
opConfig: config.Config{}, opConfig: config.Config{},
result: false, result: false,
}, },
@ -208,7 +199,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
// With PodDisruptionBudget disabled. // With PodDisruptionBudget disabled.
{ {
New( New(
Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-pdb", EnablePodDisruptionBudget: False()}}, Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-pdb", EnablePodDisruptionBudget: util.False()}},
k8sutil.KubernetesClient{}, k8sutil.KubernetesClient{},
acidv1.Postgresql{ acidv1.Postgresql{
ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"}, ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"},
@ -231,7 +222,7 @@ func TestGeneratePodDisruptionBudget(t *testing.T) {
// With non-default PDBNameFormat and PodDisruptionBudget explicitly enabled. // With non-default PDBNameFormat and PodDisruptionBudget explicitly enabled.
{ {
New( New(
Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-databass-budget", EnablePodDisruptionBudget: True()}}, Config{OpConfig: config.Config{Resources: config.Resources{ClusterNameLabel: "cluster-name", PodRoleLabel: "spilo-role"}, PDBNameFormat: "postgres-{cluster}-databass-budget", EnablePodDisruptionBudget: util.True()}},
k8sutil.KubernetesClient{}, k8sutil.KubernetesClient{},
acidv1.Postgresql{ acidv1.Postgresql{
ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"}, ObjectMeta: metav1.ObjectMeta{Name: "myapp-database", Namespace: "myapp"},

View File

@ -31,6 +31,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
result.MaxInstances = fromCRD.MaxInstances result.MaxInstances = fromCRD.MaxInstances
result.ResyncPeriod = time.Duration(fromCRD.ResyncPeriod) result.ResyncPeriod = time.Duration(fromCRD.ResyncPeriod)
result.RepairPeriod = time.Duration(fromCRD.RepairPeriod) result.RepairPeriod = time.Duration(fromCRD.RepairPeriod)
result.ShmVolume = fromCRD.ShmVolume
result.Sidecars = fromCRD.Sidecars result.Sidecars = fromCRD.Sidecars
result.SuperUsername = fromCRD.PostgresUsersConfiguration.SuperUsername result.SuperUsername = fromCRD.PostgresUsersConfiguration.SuperUsername

View File

@ -42,7 +42,7 @@ type Resources struct {
NodeReadinessLabel map[string]string `name:"node_readiness_label" default:""` NodeReadinessLabel map[string]string `name:"node_readiness_label" default:""`
MaxInstances int32 `name:"max_instances" default:"-1"` MaxInstances int32 `name:"max_instances" default:"-1"`
MinInstances int32 `name:"min_instances" default:"-1"` MinInstances int32 `name:"min_instances" default:"-1"`
ShmVolume bool `name:"enable_shm_volume" default:"true"` ShmVolume *bool `name:"enable_shm_volume" default:"true"`
} }
// Auth describes authentication specific configuration parameters // Auth describes authentication specific configuration parameters

View File

@ -26,6 +26,17 @@ func init() {
rand.Seed(time.Now().Unix()) rand.Seed(time.Now().Unix())
} }
// helper function to get bool pointers
func True() *bool {
b := true
return &b
}
func False() *bool {
b := false
return &b
}
// RandomPassword generates random alphanumeric password of a given length. // RandomPassword generates random alphanumeric password of a given length.
func RandomPassword(n int) string { func RandomPassword(n int) string {
b := make([]byte, n) b := make([]byte, n)