Merge branch 'master' into fes-support
This commit is contained in:
commit
79bd69d3ab
|
|
@ -9,7 +9,7 @@ assignees: ''
|
||||||
|
|
||||||
Please, answer some short questions which should help us to understand your problem / question better?
|
Please, answer some short questions which should help us to understand your problem / question better?
|
||||||
|
|
||||||
- **Which image of the operator are you using?** e.g. registry.opensource.zalan.do/acid/postgres-operator:v1.6.3
|
- **Which image of the operator are you using?** e.g. registry.opensource.zalan.do/acid/postgres-operator:v1.7.0
|
||||||
- **Where do you run it - cloud or metal? Kubernetes or OpenShift?** [AWS K8s | GCP ... | Bare Metal K8s]
|
- **Where do you run it - cloud or metal? Kubernetes or OpenShift?** [AWS K8s | GCP ... | Bare Metal K8s]
|
||||||
- **Are you running Postgres Operator in production?** [yes | no]
|
- **Are you running Postgres Operator in production?** [yes | no]
|
||||||
- **Type of issue?** [Bug report, question, feature request, etc.]
|
- **Type of issue?** [Bug report, question, feature request, etc.]
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ We introduce the major version into the backup path to smoothen the [major versi
|
||||||
The new operator configuration can set a compatibility flag *enable_spilo_wal_path_compat* to make Spilo look for wal segments in the current path but also old format paths.
|
The new operator configuration can set a compatibility flag *enable_spilo_wal_path_compat* to make Spilo look for wal segments in the current path but also old format paths.
|
||||||
This comes at potential performance costs and should be disabled after a few days.
|
This comes at potential performance costs and should be disabled after a few days.
|
||||||
|
|
||||||
The newest Spilo 13 image is: `registry.opensource.zalan.do/acid/spilo-13:2.0-p7`
|
The newest Spilo 13 image is: `registry.opensource.zalan.do/acid/spilo-13:2.1-p1`
|
||||||
|
|
||||||
The last Spilo 12 image is: `registry.opensource.zalan.do/acid/spilo-12:1.6-p5`
|
The last Spilo 12 image is: `registry.opensource.zalan.do/acid/spilo-12:1.6-p5`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
name: postgres-operator-ui
|
name: postgres-operator-ui
|
||||||
version: 1.6.3
|
version: 1.7.0
|
||||||
appVersion: 1.6.3
|
appVersion: 1.7.0
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
||||||
keywords:
|
keywords:
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,34 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
entries:
|
entries:
|
||||||
postgres-operator-ui:
|
postgres-operator-ui:
|
||||||
|
- apiVersion: v1
|
||||||
|
appVersion: 1.7.0
|
||||||
|
created: "2021-08-27T10:23:17.723412079+02:00"
|
||||||
|
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||||
|
database-as-a-service user experience
|
||||||
|
digest: ad08ee5fe31bb2e7c3cc1299c2e778511a3c05305bc17357404b2615b32ea92a
|
||||||
|
home: https://github.com/zalando/postgres-operator
|
||||||
|
keywords:
|
||||||
|
- postgres
|
||||||
|
- operator
|
||||||
|
- ui
|
||||||
|
- cloud-native
|
||||||
|
- patroni
|
||||||
|
- spilo
|
||||||
|
maintainers:
|
||||||
|
- email: opensource@zalando.de
|
||||||
|
name: Zalando
|
||||||
|
name: postgres-operator-ui
|
||||||
|
sources:
|
||||||
|
- https://github.com/zalando/postgres-operator
|
||||||
|
urls:
|
||||||
|
- postgres-operator-ui-1.7.0.tgz
|
||||||
|
version: 1.7.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.3
|
appVersion: 1.6.3
|
||||||
created: "2021-05-27T19:04:33.425637932+02:00"
|
created: "2021-08-27T10:23:17.722255571+02:00"
|
||||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||||
|
database-as-a-service user experience
|
||||||
digest: 08b810aa632dcc719e4785ef184e391267f7c460caa99677f2d00719075aac78
|
digest: 08b810aa632dcc719e4785ef184e391267f7c460caa99677f2d00719075aac78
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -25,8 +49,9 @@ entries:
|
||||||
version: 1.6.3
|
version: 1.6.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.2
|
appVersion: 1.6.2
|
||||||
created: "2021-05-27T19:04:33.422124263+02:00"
|
created: "2021-08-27T10:23:17.721712848+02:00"
|
||||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||||
|
database-as-a-service user experience
|
||||||
digest: 14d1559bb0bd1e1e828f2daaaa6f6ac9ffc268d79824592c3589b55dd39241f6
|
digest: 14d1559bb0bd1e1e828f2daaaa6f6ac9ffc268d79824592c3589b55dd39241f6
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -47,8 +72,9 @@ entries:
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.1
|
appVersion: 1.6.1
|
||||||
created: "2021-05-27T19:04:33.419640902+02:00"
|
created: "2021-08-27T10:23:17.721175629+02:00"
|
||||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||||
|
database-as-a-service user experience
|
||||||
digest: 3d321352f2f1e7bb7450aa8876e3d818aa9f9da9bd4250507386f0490f2c1969
|
digest: 3d321352f2f1e7bb7450aa8876e3d818aa9f9da9bd4250507386f0490f2c1969
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -69,8 +95,9 @@ entries:
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.0
|
appVersion: 1.6.0
|
||||||
created: "2021-05-27T19:04:33.41788193+02:00"
|
created: "2021-08-27T10:23:17.720655498+02:00"
|
||||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||||
|
database-as-a-service user experience
|
||||||
digest: 1e0aa1e7db3c1daa96927ffbf6fdbcdb434562f961833cb5241ddbe132220ee4
|
digest: 1e0aa1e7db3c1daa96927ffbf6fdbcdb434562f961833cb5241ddbe132220ee4
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -91,8 +118,9 @@ entries:
|
||||||
version: 1.6.0
|
version: 1.6.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.5.0
|
appVersion: 1.5.0
|
||||||
created: "2021-05-27T19:04:33.416056821+02:00"
|
created: "2021-08-27T10:23:17.720112359+02:00"
|
||||||
description: Postgres Operator UI provides a graphical interface for a convenient database-as-a-service user experience
|
description: Postgres Operator UI provides a graphical interface for a convenient
|
||||||
|
database-as-a-service user experience
|
||||||
digest: c91ea39e6d51d57f4048fb1b6ec53b40823f2690eb88e4e4f1a036367b9fdd61
|
digest: c91ea39e6d51d57f4048fb1b6ec53b40823f2690eb88e4e4f1a036367b9fdd61
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -111,4 +139,4 @@ entries:
|
||||||
urls:
|
urls:
|
||||||
- postgres-operator-ui-1.5.0.tgz
|
- postgres-operator-ui-1.5.0.tgz
|
||||||
version: 1.5.0
|
version: 1.5.0
|
||||||
generated: "2021-05-27T19:04:33.41380858+02:00"
|
generated: "2021-08-27T10:23:17.719397521+02:00"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -76,3 +76,6 @@ spec:
|
||||||
"11"
|
"11"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
{{- if .Values.extraEnvs }}
|
||||||
|
{{- .Values.extraEnvs | toYaml | nindent 12 }}
|
||||||
|
{{- end }}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
{{- if .Values.ingress.enabled -}}
|
{{- if .Values.ingress.enabled -}}
|
||||||
{{- $fullName := include "postgres-operator-ui.fullname" . -}}
|
{{- $fullName := include "postgres-operator-ui.fullname" . -}}
|
||||||
{{- $svcPort := .Values.service.port -}}
|
{{- $svcPort := .Values.service.port -}}
|
||||||
{{- if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
|
||||||
|
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
|
||||||
apiVersion: networking.k8s.io/v1beta1
|
apiVersion: networking.k8s.io/v1beta1
|
||||||
{{- else -}}
|
{{- else -}}
|
||||||
apiVersion: extensions/v1beta1
|
apiVersion: extensions/v1beta1
|
||||||
|
|
@ -37,9 +40,18 @@ spec:
|
||||||
paths:
|
paths:
|
||||||
{{- range .paths }}
|
{{- range .paths }}
|
||||||
- path: {{ . }}
|
- path: {{ . }}
|
||||||
|
{{ if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion -}}
|
||||||
|
pathType: ImplementationSpecific
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: {{ $fullName }}
|
||||||
|
port:
|
||||||
|
number: {{ $svcPort }}
|
||||||
|
{{- else -}}
|
||||||
backend:
|
backend:
|
||||||
serviceName: {{ $fullName }}
|
serviceName: {{ $fullName }}
|
||||||
servicePort: {{ $svcPort }}
|
servicePort: {{ $svcPort }}
|
||||||
|
{{- end -}}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ replicaCount: 1
|
||||||
image:
|
image:
|
||||||
registry: registry.opensource.zalan.do
|
registry: registry.opensource.zalan.do
|
||||||
repository: acid/postgres-operator-ui
|
repository: acid/postgres-operator-ui
|
||||||
tag: v1.6.3
|
tag: v1.7.0
|
||||||
pullPolicy: "IfNotPresent"
|
pullPolicy: "IfNotPresent"
|
||||||
|
|
||||||
# Optionally specify an array of imagePullSecrets.
|
# Optionally specify an array of imagePullSecrets.
|
||||||
|
|
@ -48,6 +48,36 @@ envs:
|
||||||
teams:
|
teams:
|
||||||
- "acid"
|
- "acid"
|
||||||
|
|
||||||
|
# configure extra UI ENVs
|
||||||
|
# Extra ENVs are writen in kubenertes format and added "as is" to the pod's env variables
|
||||||
|
# https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/
|
||||||
|
# https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1/#environment-variables
|
||||||
|
# UI specific env variables can be found here: https://github.com/zalando/postgres-operator/blob/master/ui/operator_ui/main.py
|
||||||
|
extraEnvs:
|
||||||
|
[]
|
||||||
|
# Exemple of settings to make snapshot view working in the ui when using AWS
|
||||||
|
# - name: WALE_S3_ENDPOINT
|
||||||
|
# value: https+path://s3.us-east-1.amazonaws.com:443
|
||||||
|
# - name: SPILO_S3_BACKUP_PREFIX
|
||||||
|
# value: spilo/
|
||||||
|
# - name: AWS_ACCESS_KEY_ID
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: <postgres operator secret with AWS token>
|
||||||
|
# key: AWS_ACCESS_KEY_ID
|
||||||
|
# - name: AWS_SECRET_ACCESS_KEY
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: <postgres operator secret with AWS token>
|
||||||
|
# key: AWS_SECRET_ACCESS_KEY
|
||||||
|
# - name: AWS_DEFAULT_REGION
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: <postgres operator secret with AWS token>
|
||||||
|
# key: AWS_DEFAULT_REGION
|
||||||
|
# - name: SPILO_S3_BACKUP_BUCKET
|
||||||
|
# value: <s3 bucket used by the operator>
|
||||||
|
|
||||||
# configure UI service
|
# configure UI service
|
||||||
service:
|
service:
|
||||||
type: "ClusterIP"
|
type: "ClusterIP"
|
||||||
|
|
@ -59,7 +89,8 @@ service:
|
||||||
# configure UI ingress. If needed: "enabled: true"
|
# configure UI ingress. If needed: "enabled: true"
|
||||||
ingress:
|
ingress:
|
||||||
enabled: false
|
enabled: false
|
||||||
annotations: {}
|
annotations:
|
||||||
|
{}
|
||||||
# kubernetes.io/ingress.class: nginx
|
# kubernetes.io/ingress.class: nginx
|
||||||
# kubernetes.io/tls-acme: "true"
|
# kubernetes.io/tls-acme: "true"
|
||||||
hosts:
|
hosts:
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
name: postgres-operator
|
name: postgres-operator
|
||||||
version: 1.6.3
|
version: 1.7.0
|
||||||
appVersion: 1.6.3
|
appVersion: 1.7.0
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
||||||
keywords:
|
keywords:
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ spec:
|
||||||
properties:
|
properties:
|
||||||
docker_image:
|
docker_image:
|
||||||
type: string
|
type: string
|
||||||
default: "registry.opensource.zalan.do/acid/spilo-13:2.0-p7"
|
default: "registry.opensource.zalan.do/acid/spilo-13:2.1-p1"
|
||||||
enable_crd_validation:
|
enable_crd_validation:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
|
|
@ -395,12 +395,14 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
wal_s3_bucket:
|
wal_s3_bucket:
|
||||||
type: string
|
type: string
|
||||||
|
wal_az_storage_account:
|
||||||
|
type: string
|
||||||
logical_backup:
|
logical_backup:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
logical_backup_docker_image:
|
logical_backup_docker_image:
|
||||||
type: string
|
type: string
|
||||||
default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.3"
|
default: "registry.opensource.zalan.do/acid/logical-backup:v1.7.0"
|
||||||
logical_backup_google_application_credentials:
|
logical_backup_google_application_credentials:
|
||||||
type: string
|
type: string
|
||||||
logical_backup_job_prefix:
|
logical_backup_job_prefix:
|
||||||
|
|
@ -535,7 +537,7 @@ spec:
|
||||||
default: "pooler"
|
default: "pooler"
|
||||||
connection_pooler_image:
|
connection_pooler_image:
|
||||||
type: string
|
type: string
|
||||||
default: "registry.opensource.zalan.do/acid/pgbouncer:master-16"
|
default: "registry.opensource.zalan.do/acid/pgbouncer:master-18"
|
||||||
connection_pooler_max_db_connections:
|
connection_pooler_max_db_connections:
|
||||||
type: integer
|
type: integer
|
||||||
default: 60
|
default: 60
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,8 @@ spec:
|
||||||
type: boolean
|
type: boolean
|
||||||
defaultRoles:
|
defaultRoles:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
secretNamespace:
|
||||||
|
type: string
|
||||||
replicaLoadBalancer: # deprecated
|
replicaLoadBalancer: # deprecated
|
||||||
type: boolean
|
type: boolean
|
||||||
resources:
|
resources:
|
||||||
|
|
@ -591,6 +593,24 @@ spec:
|
||||||
properties:
|
properties:
|
||||||
iops:
|
iops:
|
||||||
type: integer
|
type: integer
|
||||||
|
selector:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
matchLabels:
|
||||||
|
type: object
|
||||||
size:
|
size:
|
||||||
type: string
|
type: string
|
||||||
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
|
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,33 @@
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
entries:
|
entries:
|
||||||
postgres-operator:
|
postgres-operator:
|
||||||
|
- apiVersion: v1
|
||||||
|
appVersion: 1.7.0
|
||||||
|
created: "2021-08-27T10:21:42.643185124+02:00"
|
||||||
|
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||||
|
in Kubernetes
|
||||||
|
digest: 1c4a1d289188ef72e409892fd2b86c008a37420af04a9796a8829ff84ab09e61
|
||||||
|
home: https://github.com/zalando/postgres-operator
|
||||||
|
keywords:
|
||||||
|
- postgres
|
||||||
|
- operator
|
||||||
|
- cloud-native
|
||||||
|
- patroni
|
||||||
|
- spilo
|
||||||
|
maintainers:
|
||||||
|
- email: opensource@zalando.de
|
||||||
|
name: Zalando
|
||||||
|
name: postgres-operator
|
||||||
|
sources:
|
||||||
|
- https://github.com/zalando/postgres-operator
|
||||||
|
urls:
|
||||||
|
- postgres-operator-1.7.0.tgz
|
||||||
|
version: 1.7.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.3
|
appVersion: 1.6.3
|
||||||
created: "2021-05-27T19:04:25.199523943+02:00"
|
created: "2021-08-27T10:21:42.640069574+02:00"
|
||||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||||
|
in Kubernetes
|
||||||
digest: ea08f991bf23c9ad114bca98ebcbe3e2fa15beab163061399394905eaee89b35
|
digest: ea08f991bf23c9ad114bca98ebcbe3e2fa15beab163061399394905eaee89b35
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -24,8 +47,9 @@ entries:
|
||||||
version: 1.6.3
|
version: 1.6.3
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.2
|
appVersion: 1.6.2
|
||||||
created: "2021-05-27T19:04:25.198182197+02:00"
|
created: "2021-08-27T10:21:42.638502739+02:00"
|
||||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||||
|
in Kubernetes
|
||||||
digest: d886f8a0879ca07d1e5246ee7bc55710e1c872f3977280fe495db6fc2057a7f4
|
digest: d886f8a0879ca07d1e5246ee7bc55710e1c872f3977280fe495db6fc2057a7f4
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -45,8 +69,9 @@ entries:
|
||||||
version: 1.6.2
|
version: 1.6.2
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.1
|
appVersion: 1.6.1
|
||||||
created: "2021-05-27T19:04:25.19687586+02:00"
|
created: "2021-08-27T10:21:42.636936467+02:00"
|
||||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||||
|
in Kubernetes
|
||||||
digest: 4ba5972cd486dcaa2d11c5613a6f97f6b7b831822e610fe9e10a57ea1db23556
|
digest: 4ba5972cd486dcaa2d11c5613a6f97f6b7b831822e610fe9e10a57ea1db23556
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -66,8 +91,9 @@ entries:
|
||||||
version: 1.6.1
|
version: 1.6.1
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.6.0
|
appVersion: 1.6.0
|
||||||
created: "2021-05-27T19:04:25.195600766+02:00"
|
created: "2021-08-27T10:21:42.63533527+02:00"
|
||||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||||
|
in Kubernetes
|
||||||
digest: f52149718ea364f46b4b9eec9a65f6253ad182bb78df541d14cd5277b9c8a8c3
|
digest: f52149718ea364f46b4b9eec9a65f6253ad182bb78df541d14cd5277b9c8a8c3
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -87,8 +113,9 @@ entries:
|
||||||
version: 1.6.0
|
version: 1.6.0
|
||||||
- apiVersion: v1
|
- apiVersion: v1
|
||||||
appVersion: 1.5.0
|
appVersion: 1.5.0
|
||||||
created: "2021-05-27T19:04:25.193985032+02:00"
|
created: "2021-08-27T10:21:42.632932257+02:00"
|
||||||
description: Postgres Operator creates and manages PostgreSQL clusters running in Kubernetes
|
description: Postgres Operator creates and manages PostgreSQL clusters running
|
||||||
|
in Kubernetes
|
||||||
digest: 198351d5db52e65cdf383d6f3e1745d91ac1e2a01121f8476f8b1be728b09531
|
digest: 198351d5db52e65cdf383d6f3e1745d91ac1e2a01121f8476f8b1be728b09531
|
||||||
home: https://github.com/zalando/postgres-operator
|
home: https://github.com/zalando/postgres-operator
|
||||||
keywords:
|
keywords:
|
||||||
|
|
@ -106,4 +133,4 @@ entries:
|
||||||
urls:
|
urls:
|
||||||
- postgres-operator-1.5.0.tgz
|
- postgres-operator-1.5.0.tgz
|
||||||
version: 1.5.0
|
version: 1.5.0
|
||||||
generated: "2021-05-27T19:04:25.191897769+02:00"
|
generated: "2021-08-27T10:21:42.631372502+02:00"
|
||||||
|
|
|
||||||
Binary file not shown.
|
|
@ -57,18 +57,16 @@ Flatten nested config options when ConfigMap is used as ConfigTarget
|
||||||
*/}}
|
*/}}
|
||||||
{{- define "flattenValuesForConfigMap" }}
|
{{- define "flattenValuesForConfigMap" }}
|
||||||
{{- range $key, $value := . }}
|
{{- range $key, $value := . }}
|
||||||
{{- if or (kindIs "string" $value) (kindIs "int" $value) }}
|
|
||||||
{{ $key }}: {{ $value | quote }}
|
|
||||||
{{- end }}
|
|
||||||
{{- if kindIs "slice" $value }}
|
{{- if kindIs "slice" $value }}
|
||||||
{{ $key }}: {{ join "," $value | quote }}
|
{{ $key }}: {{ join "," $value | quote }}
|
||||||
{{- end }}
|
{{- else if kindIs "map" $value }}
|
||||||
{{- if kindIs "map" $value }}
|
|
||||||
{{- $list := list }}
|
{{- $list := list }}
|
||||||
{{- range $subKey, $subValue := $value }}
|
{{- range $subKey, $subValue := $value }}
|
||||||
{{- $list = append $list (printf "%s:%s" $subKey $subValue) }}
|
{{- $list = append $list (printf "%s:%s" $subKey $subValue) }}
|
||||||
{{ $key }}: {{ join "," $list | quote }}
|
{{ $key }}: {{ join "," $list | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{- else }}
|
||||||
|
{{ $key }}: {{ $value | quote }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
image:
|
image:
|
||||||
registry: registry.opensource.zalan.do
|
registry: registry.opensource.zalan.do
|
||||||
repository: acid/postgres-operator
|
repository: acid/postgres-operator
|
||||||
tag: v1.6.3
|
tag: v1.7.0
|
||||||
pullPolicy: "IfNotPresent"
|
pullPolicy: "IfNotPresent"
|
||||||
|
|
||||||
# Optionally specify an array of imagePullSecrets.
|
# Optionally specify an array of imagePullSecrets.
|
||||||
|
|
@ -35,7 +35,7 @@ configGeneral:
|
||||||
# Select if setup uses endpoints (default), or configmaps to manage leader (DCS=k8s)
|
# Select if setup uses endpoints (default), or configmaps to manage leader (DCS=k8s)
|
||||||
# kubernetes_use_configmaps: false
|
# kubernetes_use_configmaps: false
|
||||||
# Spilo docker image
|
# Spilo docker image
|
||||||
docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p7
|
docker_image: registry.opensource.zalan.do/acid/spilo-13:2.1-p1
|
||||||
# min number of instances in Postgres cluster. -1 = no limit
|
# min number of instances in Postgres cluster. -1 = no limit
|
||||||
min_instances: -1
|
min_instances: -1
|
||||||
# max number of instances in Postgres cluster. -1 = no limit
|
# max number of instances in Postgres cluster. -1 = no limit
|
||||||
|
|
@ -268,10 +268,13 @@ configAwsOrGcp:
|
||||||
# GCS bucket to use for shipping WAL segments with WAL-E
|
# GCS bucket to use for shipping WAL segments with WAL-E
|
||||||
# wal_gs_bucket: ""
|
# wal_gs_bucket: ""
|
||||||
|
|
||||||
|
# Azure Storage Account to use for shipping WAL segments with WAL-G
|
||||||
|
# wal_az_storage_account: ""
|
||||||
|
|
||||||
# configure K8s cron job managed by the operator
|
# configure K8s cron job managed by the operator
|
||||||
configLogicalBackup:
|
configLogicalBackup:
|
||||||
# image for pods of the logical backup job (example runs pg_dumpall)
|
# image for pods of the logical backup job (example runs pg_dumpall)
|
||||||
logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.3"
|
logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.7.0"
|
||||||
# path of google cloud service account json file
|
# path of google cloud service account json file
|
||||||
# logical_backup_google_application_credentials: ""
|
# logical_backup_google_application_credentials: ""
|
||||||
|
|
||||||
|
|
@ -336,7 +339,7 @@ configConnectionPooler:
|
||||||
# db user for pooler to use
|
# db user for pooler to use
|
||||||
connection_pooler_user: "pooler"
|
connection_pooler_user: "pooler"
|
||||||
# docker image
|
# docker image
|
||||||
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-16"
|
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-18"
|
||||||
# max db connections the pooler should hold
|
# max db connections the pooler should hold
|
||||||
connection_pooler_max_db_connections: 60
|
connection_pooler_max_db_connections: 60
|
||||||
# default pooling mode
|
# default pooling mode
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,21 @@
|
||||||
Learn how to configure and manage the Postgres Operator in your Kubernetes (K8s)
|
Learn how to configure and manage the Postgres Operator in your Kubernetes (K8s)
|
||||||
environment.
|
environment.
|
||||||
|
|
||||||
|
## Upgrading the operator
|
||||||
|
|
||||||
|
The Postgres Operator is upgraded by changing the docker image within the
|
||||||
|
deployment. Before doing so, it is recommended to check the release notes
|
||||||
|
for new configuration options or changed behavior you might want to reflect
|
||||||
|
in the ConfigMap or config CRD. E.g. a new feature might get introduced which
|
||||||
|
is enabled or disabled by default and you want to change it to the opposite
|
||||||
|
with the corresponding flag option.
|
||||||
|
|
||||||
|
When using helm, be aware that installing the new chart will not update the
|
||||||
|
`Postgresql` and `OperatorConfiguration` CRD. Make sure to update them before
|
||||||
|
with the provided manifests in the `crds` folder. Otherwise, you might face
|
||||||
|
errors about new Postgres manifest or configuration options being unknown
|
||||||
|
to the CRD schema validation.
|
||||||
|
|
||||||
## Minor and major version upgrade
|
## Minor and major version upgrade
|
||||||
|
|
||||||
Minor version upgrades for PostgreSQL are handled via updating the Spilo Docker
|
Minor version upgrades for PostgreSQL are handled via updating the Spilo Docker
|
||||||
|
|
@ -157,20 +172,26 @@ from numerous escape characters in the latter log entry, view it in CLI with
|
||||||
`PodTemplate` used by the operator is yet to be updated with the default values
|
`PodTemplate` used by the operator is yet to be updated with the default values
|
||||||
used internally in K8s.
|
used internally in K8s.
|
||||||
|
|
||||||
The operator also support lazy updates of the Spilo image. That means the pod
|
The StatefulSet is replaced if the following properties change:
|
||||||
template of a PG cluster's stateful set is updated immediately with the new
|
- annotations
|
||||||
image, but no rolling update follows. This feature saves you a switchover - and
|
- volumeClaimTemplates
|
||||||
hence downtime - when you know pods are re-started later anyway, for instance
|
- template volumes
|
||||||
due to the node rotation. To force a rolling update, disable this mode by
|
|
||||||
setting the `enable_lazy_spilo_upgrade` to `false` in the operator configuration
|
|
||||||
and restart the operator pod. With the standard eager rolling updates the
|
|
||||||
operator checks during Sync all pods run images specified in their respective
|
|
||||||
statefulsets. The operator triggers a rolling upgrade for PG clusters that
|
|
||||||
violate this condition.
|
|
||||||
|
|
||||||
Changes in $SPILO\_CONFIGURATION under path bootstrap.dcs are ignored when
|
The StatefulSet is replaced and a rolling updates is triggered if the following
|
||||||
StatefulSets are being compared, if there are changes under this path, they are
|
properties differ between the old and new state:
|
||||||
applied through rest api interface and following restart of patroni instance
|
- container name, ports, image, resources, env, envFrom, securityContext and volumeMounts
|
||||||
|
- template labels, annotations, service account, securityContext, affinity, priority class and termination grace period
|
||||||
|
|
||||||
|
Note that, changes in `SPILO_CONFIGURATION` env variable under `bootstrap.dcs`
|
||||||
|
path are ignored for the diff. They will be applied through Patroni's rest api
|
||||||
|
interface, following a restart of all instances.
|
||||||
|
|
||||||
|
The operator also support lazy updates of the Spilo image. In this case the
|
||||||
|
StatefulSet is only updated, but no rolling update follows. This feature saves
|
||||||
|
you a switchover - and hence downtime - when you know pods are re-started later
|
||||||
|
anyway, for instance due to the node rotation. To force a rolling update,
|
||||||
|
disable this mode by setting the `enable_lazy_spilo_upgrade` to `false` in the
|
||||||
|
operator configuration and restart the operator pod.
|
||||||
|
|
||||||
## Delete protection via annotations
|
## Delete protection via annotations
|
||||||
|
|
||||||
|
|
@ -667,6 +688,12 @@ if it ends up in your specified WAL backup path:
|
||||||
envdir "/run/etc/wal-e.d/env" /scripts/postgres_backup.sh "/home/postgres/pgdata/pgroot/data"
|
envdir "/run/etc/wal-e.d/env" /scripts/postgres_backup.sh "/home/postgres/pgdata/pgroot/data"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also check if Spilo is able to find any backups:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
envdir "/run/etc/wal-e.d/env" wal-g backup-list
|
||||||
|
```
|
||||||
|
|
||||||
Depending on the cloud storage provider different [environment variables](https://github.com/zalando/spilo/blob/master/ENVIRONMENT.rst)
|
Depending on the cloud storage provider different [environment variables](https://github.com/zalando/spilo/blob/master/ENVIRONMENT.rst)
|
||||||
have to be set for Spilo. Not all of them are generated automatically by the
|
have to be set for Spilo. Not all of them are generated automatically by the
|
||||||
operator by changing its configuration. In this case you have to use an
|
operator by changing its configuration. In this case you have to use an
|
||||||
|
|
@ -734,8 +761,15 @@ WALE_S3_ENDPOINT='https+path://s3.eu-central-1.amazonaws.com:443'
|
||||||
WALE_S3_PREFIX=$WAL_S3_BUCKET/spilo/{WAL_BUCKET_SCOPE_PREFIX}{SCOPE}{WAL_BUCKET_SCOPE_SUFFIX}/wal/{PGVERSION}
|
WALE_S3_PREFIX=$WAL_S3_BUCKET/spilo/{WAL_BUCKET_SCOPE_PREFIX}{SCOPE}{WAL_BUCKET_SCOPE_SUFFIX}/wal/{PGVERSION}
|
||||||
```
|
```
|
||||||
|
|
||||||
If the prefix is not specified Spilo will generate it from `WAL_S3_BUCKET`.
|
The operator sets the prefix to an empty string so that spilo will generate it
|
||||||
When the `AWS_REGION` is set `AWS_ENDPOINT` and `WALE_S3_ENDPOINT` are
|
from the configured `WAL_S3_BUCKET`.
|
||||||
|
|
||||||
|
:warning: When you overwrite the configuration by defining `WAL_S3_BUCKET` in
|
||||||
|
the [pod_environment_configmap](#custom-pod-environment-variables) you have
|
||||||
|
to set `WAL_BUCKET_SCOPE_PREFIX = ""`, too. Otherwise Spilo will not find
|
||||||
|
the physical backups on restore (next chapter).
|
||||||
|
|
||||||
|
When the `AWS_REGION` is set, `AWS_ENDPOINT` and `WALE_S3_ENDPOINT` are
|
||||||
generated automatically. `WALG_S3_PREFIX` is identical to `WALE_S3_PREFIX`.
|
generated automatically. `WALG_S3_PREFIX` is identical to `WALE_S3_PREFIX`.
|
||||||
`SCOPE` is the Postgres cluster name.
|
`SCOPE` is the Postgres cluster name.
|
||||||
|
|
||||||
|
|
@ -808,6 +842,63 @@ pod_environment_configmap: "postgres-operator-system/pod-env-overrides"
|
||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Azure setup
|
||||||
|
|
||||||
|
To configure the operator on Azure these prerequisites are needed:
|
||||||
|
|
||||||
|
* A storage account in the same region as the Kubernetes cluster.
|
||||||
|
|
||||||
|
The configuration parameters that we will be using are:
|
||||||
|
|
||||||
|
* `pod_environment_secret`
|
||||||
|
* `wal_az_storage_account`
|
||||||
|
|
||||||
|
1. Generate the K8s secret resource that will contain your storage account's
|
||||||
|
access key. You will need a copy of this secret in every namespace you want to
|
||||||
|
create postgresql clusters.
|
||||||
|
|
||||||
|
The latest version of WAL-G (v1.0) supports the use of a SASS token, but you'll
|
||||||
|
have to make due with using the primary or secondary access token until the
|
||||||
|
version of WAL-G is updated in the postgres-operator.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Secret
|
||||||
|
metadata:
|
||||||
|
name: psql-backup-creds
|
||||||
|
namespace: default
|
||||||
|
type: Opaque
|
||||||
|
stringData:
|
||||||
|
AZURE_STORAGE_ACCESS_KEY: <primary or secondary access key>
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Setup pod environment configmap that instructs the operator to use WAL-G,
|
||||||
|
instead of WAL-E, for backup and restore.
|
||||||
|
```yml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: pod-env-overrides
|
||||||
|
namespace: postgres-operator-system
|
||||||
|
data:
|
||||||
|
# Any env variable used by spilo can be added
|
||||||
|
USE_WALG_BACKUP: "true"
|
||||||
|
USE_WALG_RESTORE: "true"
|
||||||
|
CLONE_USE_WALG_RESTORE: "true"
|
||||||
|
```
|
||||||
|
|
||||||
|
3. Setup your operator configuration values. With the `psql-backup-creds`
|
||||||
|
and `pod-env-overrides` resources applied to your cluster, ensure that the operator's configuration
|
||||||
|
is set up like the following:
|
||||||
|
```yml
|
||||||
|
...
|
||||||
|
aws_or_gcp:
|
||||||
|
pod_environment_secret: "pgsql-backup-creds"
|
||||||
|
pod_environment_configmap: "postgres-operator-system/pod-env-overrides"
|
||||||
|
wal_az_storage_account: "postgresbackupsbucket28302F2" # name of storage account to save the WAL-G logs
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
### Restoring physical backups
|
### Restoring physical backups
|
||||||
|
|
||||||
If cluster members have to be (re)initialized restoring physical backups
|
If cluster members have to be (re)initialized restoring physical backups
|
||||||
|
|
@ -817,6 +908,36 @@ on one of the other running instances (preferably replicas if they do not lag
|
||||||
behind). You can test restoring backups by [cloning](user.md#how-to-clone-an-existing-postgresql-cluster)
|
behind). You can test restoring backups by [cloning](user.md#how-to-clone-an-existing-postgresql-cluster)
|
||||||
clusters.
|
clusters.
|
||||||
|
|
||||||
|
If you need to provide a [custom clone environment](#custom-pod-environment-variables)
|
||||||
|
copy existing variables about your setup (backup location, prefix, access
|
||||||
|
keys etc.) and prepend the `CLONE_` prefix to get them copied to the correct
|
||||||
|
directory within Spilo.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: v1
|
||||||
|
kind: ConfigMap
|
||||||
|
metadata:
|
||||||
|
name: postgres-pod-config
|
||||||
|
data:
|
||||||
|
AWS_REGION: "eu-west-1"
|
||||||
|
AWS_ACCESS_KEY_ID: "****"
|
||||||
|
AWS_SECRET_ACCESS_KEY: "****"
|
||||||
|
...
|
||||||
|
CLONE_AWS_REGION: "eu-west-1"
|
||||||
|
CLONE_AWS_ACCESS_KEY_ID: "****"
|
||||||
|
CLONE_AWS_SECRET_ACCESS_KEY: "****"
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Standby clusters
|
||||||
|
|
||||||
|
The setup for [standby clusters](user.md#setting-up-a-standby-cluster) is very
|
||||||
|
similar to cloning. At the moment, the operator only allows for streaming from
|
||||||
|
the S3 WAL archive of the master specified in the manifest. Like with cloning,
|
||||||
|
if you are using [additional environment variables](#custom-pod-environment-variables)
|
||||||
|
to access your backup location you have to copy those variables and prepend the
|
||||||
|
`STANDBY_` prefix for Spilo to find the backups and WAL files to stream.
|
||||||
|
|
||||||
## Logical backups
|
## Logical backups
|
||||||
|
|
||||||
The operator can manage K8s cron jobs to run logical backups (SQL dumps) of
|
The operator can manage K8s cron jobs to run logical backups (SQL dumps) of
|
||||||
|
|
@ -954,7 +1075,7 @@ make docker
|
||||||
|
|
||||||
# build in image in minikube docker env
|
# build in image in minikube docker env
|
||||||
eval $(minikube docker-env)
|
eval $(minikube docker-env)
|
||||||
docker build -t registry.opensource.zalan.do/acid/postgres-operator-ui:v1.6.3 .
|
docker build -t registry.opensource.zalan.do/acid/postgres-operator-ui:v1.7.0 .
|
||||||
|
|
||||||
# apply UI manifests next to a running Postgres Operator
|
# apply UI manifests next to a running Postgres Operator
|
||||||
kubectl apply -f manifests/
|
kubectl apply -f manifests/
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,11 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
||||||
`SUPERUSER`, `REPLICATION`, `INHERIT`, `LOGIN`, `NOLOGIN`, `CREATEROLE`,
|
`SUPERUSER`, `REPLICATION`, `INHERIT`, `LOGIN`, `NOLOGIN`, `CREATEROLE`,
|
||||||
`CREATEDB`, `BYPASSURL`. A login user is created by default unless NOLOGIN is
|
`CREATEDB`, `BYPASSURL`. A login user is created by default unless NOLOGIN is
|
||||||
specified, in which case the operator creates a role. One can specify empty
|
specified, in which case the operator creates a role. One can specify empty
|
||||||
flags by providing a JSON empty array '*[]*'. Optional.
|
flags by providing a JSON empty array '*[]*'. If the config option
|
||||||
|
`enable_cross_namespace_secrets` is enabled you can specify the namespace in
|
||||||
|
the user name in the form `{namespace}.{username}` and the operator will
|
||||||
|
create the K8s secret in that namespace. The part after the first `.` is
|
||||||
|
considered to be the user name. Optional.
|
||||||
|
|
||||||
* **databases**
|
* **databases**
|
||||||
a map of database names to database owners for the databases that should be
|
a map of database names to database owners for the databases that should be
|
||||||
|
|
@ -185,6 +189,35 @@ These parameters are grouped directly under the `spec` key in the manifest.
|
||||||
If you set the `all` special item, it will be mounted in all containers (postgres + sidecars).
|
If you set the `all` special item, it will be mounted in all containers (postgres + sidecars).
|
||||||
Else you can set the list of target containers in which the additional volumes will be mounted (eg : postgres, telegraf)
|
Else you can set the list of target containers in which the additional volumes will be mounted (eg : postgres, telegraf)
|
||||||
|
|
||||||
|
## Prepared Databases
|
||||||
|
|
||||||
|
The operator can create databases with default owner, reader and writer roles
|
||||||
|
without the need to specifiy them under `users` or `databases` sections. Those
|
||||||
|
parameters are grouped under the `preparedDatabases` top-level key. For more
|
||||||
|
information, see [user docs](../user.md#prepared-databases-with-roles-and-default-privileges).
|
||||||
|
|
||||||
|
* **defaultUsers**
|
||||||
|
The operator will always create default `NOLOGIN` roles for defined prepared
|
||||||
|
databases, but if `defaultUsers` is set to `true` three additional `LOGIN`
|
||||||
|
roles with `_user` suffix will get created. Default is `false`.
|
||||||
|
|
||||||
|
* **extensions**
|
||||||
|
map of extensions with target database schema that the operator will install
|
||||||
|
in the database. Optional.
|
||||||
|
|
||||||
|
* **schemas**
|
||||||
|
map of schemas that the operator will create. Optional - if no schema is
|
||||||
|
listed, the operator will create a schema called `data`. Under each schema
|
||||||
|
key, it can be defined if `defaultRoles` (NOLOGIN) and `defaultUsers` (LOGIN)
|
||||||
|
roles shall be created that have schema-exclusive privileges. Both flags are
|
||||||
|
set to `false` by default.
|
||||||
|
|
||||||
|
* **secretNamespace**
|
||||||
|
for each default LOGIN role the operator will create a secret. You can
|
||||||
|
specify the namespace in which these secrets will get created, if
|
||||||
|
`enable_cross_namespace_secrets` is set to `true` in the config. Otherwise,
|
||||||
|
the cluster namespace is used.
|
||||||
|
|
||||||
## Postgres parameters
|
## Postgres parameters
|
||||||
|
|
||||||
Those parameters are grouped under the `postgresql` top-level key, which is
|
Those parameters are grouped under the `postgresql` top-level key, which is
|
||||||
|
|
@ -258,7 +291,9 @@ explanation of `ttl` and `loop_wait` parameters.
|
||||||
|
|
||||||
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/)
|
||||||
for the Postgres container. They are grouped under the `resources` top-level
|
for the Postgres container. They are grouped under the `resources` top-level
|
||||||
key with subgroups `requests` and `limits`.
|
key with subgroups `requests` and `limits`. The whole section is optional,
|
||||||
|
however if you specify a request or limit you have to define everything
|
||||||
|
(unless you are not modifying the default CRD schema validation).
|
||||||
|
|
||||||
### Requests
|
### Requests
|
||||||
|
|
||||||
|
|
@ -266,11 +301,11 @@ CPU and memory requests for the Postgres container.
|
||||||
|
|
||||||
* **cpu**
|
* **cpu**
|
||||||
CPU requests for the Postgres container. Optional, overrides the
|
CPU requests for the Postgres container. Optional, overrides the
|
||||||
`default_cpu_requests` operator configuration parameter. Optional.
|
`default_cpu_requests` operator configuration parameter.
|
||||||
|
|
||||||
* **memory**
|
* **memory**
|
||||||
memory requests for the Postgres container. Optional, overrides the
|
memory requests for the Postgres container. Optional, overrides the
|
||||||
`default_memory_request` operator configuration parameter. Optional.
|
`default_memory_request` operator configuration parameter.
|
||||||
|
|
||||||
### Limits
|
### Limits
|
||||||
|
|
||||||
|
|
@ -278,11 +313,11 @@ CPU and memory limits for the Postgres container.
|
||||||
|
|
||||||
* **cpu**
|
* **cpu**
|
||||||
CPU limits for the Postgres container. Optional, overrides the
|
CPU limits for the Postgres container. Optional, overrides the
|
||||||
`default_cpu_limits` operator configuration parameter. Optional.
|
`default_cpu_limits` operator configuration parameter.
|
||||||
|
|
||||||
* **memory**
|
* **memory**
|
||||||
memory limits for the Postgres container. Optional, overrides the
|
memory limits for the Postgres container. Optional, overrides the
|
||||||
`default_memory_limits` operator configuration parameter. Optional.
|
`default_memory_limits` operator configuration parameter.
|
||||||
|
|
||||||
## Parameters defining how to clone the cluster from another one
|
## Parameters defining how to clone the cluster from another one
|
||||||
|
|
||||||
|
|
@ -364,6 +399,11 @@ properties of the persistent storage that stores Postgres data.
|
||||||
When running the operator on AWS the latest generation of EBS volumes (`gp3`)
|
When running the operator on AWS the latest generation of EBS volumes (`gp3`)
|
||||||
allows for configuring the throughput in MB/s. Maximum is 1000. Optional.
|
allows for configuring the throughput in MB/s. Maximum is 1000. Optional.
|
||||||
|
|
||||||
|
* **selector**
|
||||||
|
A label query over PVs to consider for binding. See the [Kubernetes
|
||||||
|
documentation](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/)
|
||||||
|
for details on using `matchLabels` and `matchExpressions`. Optional
|
||||||
|
|
||||||
## Sidecar definitions
|
## Sidecar definitions
|
||||||
|
|
||||||
Those parameters are defined under the `sidecars` key. They consist of a list
|
Those parameters are defined under the `sidecars` key. They consist of a list
|
||||||
|
|
|
||||||
|
|
@ -267,9 +267,7 @@ configuration they are grouped under the `kubernetes` key.
|
||||||
* **enable_cross_namespace_secrets**
|
* **enable_cross_namespace_secrets**
|
||||||
To allow secrets in a different namespace other than the Postgres cluster
|
To allow secrets in a different namespace other than the Postgres cluster
|
||||||
namespace. Once enabled, specify the namespace in the user name under the
|
namespace. Once enabled, specify the namespace in the user name under the
|
||||||
`users` section in the form `{namespace}.{username}`. The operator will then
|
`users` section in the form `{namespace}.{username}`. The default is `false`.
|
||||||
create the user secret in that namespace. The part after the first `.` is
|
|
||||||
considered to be the user name. The default is `false`.
|
|
||||||
|
|
||||||
* **enable_init_containers**
|
* **enable_init_containers**
|
||||||
global option to allow for creating init containers in the cluster manifest to
|
global option to allow for creating init containers in the cluster manifest to
|
||||||
|
|
@ -559,6 +557,12 @@ yet officially supported.
|
||||||
[service accounts](https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform).
|
[service accounts](https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform).
|
||||||
The default is empty
|
The default is empty
|
||||||
|
|
||||||
|
* **wal_az_storage_account**
|
||||||
|
Azure Storage Account to use for shipping WAL segments with WAL-G. The
|
||||||
|
storage account must exist and be accessible by Postgres pods. Note, only the
|
||||||
|
name of the storage account is required.
|
||||||
|
The default is empty.
|
||||||
|
|
||||||
* **log_s3_bucket**
|
* **log_s3_bucket**
|
||||||
S3 bucket to use for shipping Postgres daily logs. Works only with S3 on AWS.
|
S3 bucket to use for shipping Postgres daily logs. Works only with S3 on AWS.
|
||||||
The bucket has to be present and accessible by Postgres pods. The default is
|
The bucket has to be present and accessible by Postgres pods. The default is
|
||||||
|
|
@ -602,7 +606,7 @@ grouped under the `logical_backup` key.
|
||||||
runs `pg_dumpall` on a replica if possible and uploads compressed results to
|
runs `pg_dumpall` on a replica if possible and uploads compressed results to
|
||||||
an S3 bucket under the key `/spilo/pg_cluster_name/cluster_k8s_uuid/logical_backups`.
|
an S3 bucket under the key `/spilo/pg_cluster_name/cluster_k8s_uuid/logical_backups`.
|
||||||
The default image is the same image built with the Zalando-internal CI
|
The default image is the same image built with the Zalando-internal CI
|
||||||
pipeline. Default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.3"
|
pipeline. Default: "registry.opensource.zalan.do/acid/logical-backup:v1.7.0"
|
||||||
|
|
||||||
* **logical_backup_google_application_credentials**
|
* **logical_backup_google_application_credentials**
|
||||||
Specifies the path of the google cloud service account json file. Default is empty.
|
Specifies the path of the google cloud service account json file. Default is empty.
|
||||||
|
|
|
||||||
35
docs/user.md
35
docs/user.md
|
|
@ -139,9 +139,9 @@ secret, without ever sharing it outside of the cluster.
|
||||||
At the moment it is not possible to define membership of the manifest role in
|
At the moment it is not possible to define membership of the manifest role in
|
||||||
other roles.
|
other roles.
|
||||||
|
|
||||||
To define the secrets for the users in a different namespace than that of the cluster,
|
To define the secrets for the users in a different namespace than that of the
|
||||||
one can set `enable_cross_namespace_secret` and declare the namespace for the
|
cluster, one can set `enable_cross_namespace_secret` and declare the namespace
|
||||||
secrets in the manifest in the following manner,
|
for the secrets in the manifest in the following manner,
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
spec:
|
spec:
|
||||||
|
|
@ -150,7 +150,8 @@ spec:
|
||||||
appspace.db_user:
|
appspace.db_user:
|
||||||
- createdb
|
- createdb
|
||||||
```
|
```
|
||||||
Here, anything before the first dot is taken as the namespace and the text after
|
|
||||||
|
Here, anything before the first dot is considered the namespace and the text after
|
||||||
the first dot is the username. Also, the postgres roles of these usernames would
|
the first dot is the username. Also, the postgres roles of these usernames would
|
||||||
be in the form of `namespace.username`.
|
be in the form of `namespace.username`.
|
||||||
|
|
||||||
|
|
@ -520,7 +521,7 @@ Then, the schemas are owned by the database owner, too.
|
||||||
|
|
||||||
The roles described in the previous paragraph can be granted to LOGIN roles from
|
The roles described in the previous paragraph can be granted to LOGIN roles from
|
||||||
the `users` section in the manifest. Optionally, the Postgres Operator can also
|
the `users` section in the manifest. Optionally, the Postgres Operator can also
|
||||||
create default LOGIN roles for the database an each schema individually. These
|
create default LOGIN roles for the database and each schema individually. These
|
||||||
roles will get the `_user` suffix and they inherit all rights from their NOLOGIN
|
roles will get the `_user` suffix and they inherit all rights from their NOLOGIN
|
||||||
counterparts. Therefore, you cannot have `defaultRoles` set to `false` and enable
|
counterparts. Therefore, you cannot have `defaultRoles` set to `false` and enable
|
||||||
`defaultUsers` at the same time.
|
`defaultUsers` at the same time.
|
||||||
|
|
@ -550,6 +551,19 @@ Default access privileges are also defined for LOGIN roles on database and
|
||||||
schema creation. This means they are currently not set when `defaultUsers`
|
schema creation. This means they are currently not set when `defaultUsers`
|
||||||
(or `defaultRoles` for schemas) are enabled at a later point in time.
|
(or `defaultRoles` for schemas) are enabled at a later point in time.
|
||||||
|
|
||||||
|
For all LOGIN roles the operator will create K8s secrets in the namespace
|
||||||
|
specified in `secretNamespace`, if `enable_cross_namespace_secret` is set to
|
||||||
|
`true` in the config. Otherwise, they are created in the same namespace like
|
||||||
|
the Postgres cluster.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
spec:
|
||||||
|
preparedDatabases:
|
||||||
|
foo:
|
||||||
|
defaultUsers: true
|
||||||
|
secretNamespace: appspace
|
||||||
|
```
|
||||||
|
|
||||||
### Schema `search_path` for default roles
|
### Schema `search_path` for default roles
|
||||||
|
|
||||||
The schema [`search_path`](https://www.postgresql.org/docs/13/ddl-schemas.html#DDL-SCHEMAS-PATH)
|
The schema [`search_path`](https://www.postgresql.org/docs/13/ddl-schemas.html#DDL-SCHEMAS-PATH)
|
||||||
|
|
@ -719,20 +733,21 @@ spec:
|
||||||
uid: "efd12e58-5786-11e8-b5a7-06148230260c"
|
uid: "efd12e58-5786-11e8-b5a7-06148230260c"
|
||||||
cluster: "acid-batman"
|
cluster: "acid-batman"
|
||||||
timestamp: "2017-12-19T12:40:33+01:00"
|
timestamp: "2017-12-19T12:40:33+01:00"
|
||||||
|
s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
|
||||||
```
|
```
|
||||||
|
|
||||||
Here `cluster` is a name of a source cluster that is going to be cloned. A new
|
Here `cluster` is a name of a source cluster that is going to be cloned. A new
|
||||||
cluster will be cloned from S3, using the latest backup before the `timestamp`.
|
cluster will be cloned from S3, using the latest backup before the `timestamp`.
|
||||||
Note, that a time zone is required for `timestamp` in the format of +00:00 which
|
Note, that a time zone is required for `timestamp` in the format of +00:00 which
|
||||||
is UTC. The `uid` field is also mandatory. The operator will use it to find a
|
is UTC. You can specify the `s3_wal_path` of the source cluster or let the
|
||||||
correct key inside an S3 bucket. You can find this field in the metadata of the
|
operator try to find it based on the configured `wal_[s3|gs]_bucket` and the
|
||||||
source cluster:
|
specified `uid`. You can find the UID of the source cluster in its metadata:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
apiVersion: acid.zalan.do/v1
|
apiVersion: acid.zalan.do/v1
|
||||||
kind: postgresql
|
kind: postgresql
|
||||||
metadata:
|
metadata:
|
||||||
name: acid-test-cluster
|
name: acid-batman
|
||||||
uid: efd12e58-5786-11e8-b5a7-06148230260c
|
uid: efd12e58-5786-11e8-b5a7-06148230260c
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -785,7 +800,7 @@ no statefulset will be created.
|
||||||
```yaml
|
```yaml
|
||||||
spec:
|
spec:
|
||||||
standby:
|
standby:
|
||||||
s3_wal_path: "s3 bucket path to the master"
|
s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
|
||||||
```
|
```
|
||||||
|
|
||||||
At the moment, the operator only allows to stream from the WAL archive of the
|
At the moment, the operator only allows to stream from the WAL archive of the
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ metadata:
|
||||||
# "delete-date": "2020-08-31" # can only be deleted on that day if "delete-date "key is configured
|
# "delete-date": "2020-08-31" # can only be deleted on that day if "delete-date "key is configured
|
||||||
# "delete-clustername": "acid-test-cluster" # can only be deleted when name matches if "delete-clustername" key is configured
|
# "delete-clustername": "acid-test-cluster" # can only be deleted when name matches if "delete-clustername" key is configured
|
||||||
spec:
|
spec:
|
||||||
dockerImage: registry.opensource.zalan.do/acid/spilo-13:2.0-p7
|
dockerImage: registry.opensource.zalan.do/acid/spilo-13:2.1-p1
|
||||||
teamId: "acid"
|
teamId: "acid"
|
||||||
numberOfInstances: 2
|
numberOfInstances: 2
|
||||||
users: # Application/Robot users
|
users: # Application/Robot users
|
||||||
|
|
@ -46,6 +46,12 @@ spec:
|
||||||
# storageClass: my-sc
|
# storageClass: my-sc
|
||||||
# iops: 1000 # for EBS gp3
|
# iops: 1000 # for EBS gp3
|
||||||
# throughput: 250 # in MB/s for EBS gp3
|
# throughput: 250 # in MB/s for EBS gp3
|
||||||
|
# selector:
|
||||||
|
# matchExpressions:
|
||||||
|
# - { key: flavour, operator: In, values: [ "banana", "chocolate" ] }
|
||||||
|
# matchLabels:
|
||||||
|
# environment: dev
|
||||||
|
# service: postgres
|
||||||
additionalVolumes:
|
additionalVolumes:
|
||||||
- name: empty
|
- name: empty
|
||||||
mountPath: /opt/empty
|
mountPath: /opt/empty
|
||||||
|
|
@ -151,7 +157,7 @@ spec:
|
||||||
# - name: "telegraf-sidecar"
|
# - name: "telegraf-sidecar"
|
||||||
# image: "telegraf:latest"
|
# image: "telegraf:latest"
|
||||||
# ports:
|
# ports:
|
||||||
# name: metrics
|
# - name: metrics
|
||||||
# containerPort: 8094
|
# containerPort: 8094
|
||||||
# protocol: TCP
|
# protocol: TCP
|
||||||
# resources:
|
# resources:
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,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-16"
|
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-18"
|
||||||
# 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
|
||||||
|
|
@ -32,7 +32,7 @@ data:
|
||||||
# default_memory_request: 100Mi
|
# default_memory_request: 100Mi
|
||||||
# delete_annotation_date_key: delete-date
|
# delete_annotation_date_key: delete-date
|
||||||
# delete_annotation_name_key: delete-clustername
|
# delete_annotation_name_key: delete-clustername
|
||||||
docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p7
|
docker_image: registry.opensource.zalan.do/acid/spilo-13:2.1-p1
|
||||||
# downscaler_annotations: "deployment-time,downscaler/*"
|
# downscaler_annotations: "deployment-time,downscaler/*"
|
||||||
# enable_admin_role_for_users: "true"
|
# enable_admin_role_for_users: "true"
|
||||||
# enable_crd_validation: "true"
|
# enable_crd_validation: "true"
|
||||||
|
|
@ -65,7 +65,7 @@ data:
|
||||||
# inherited_labels: application,environment
|
# inherited_labels: application,environment
|
||||||
# kube_iam_role: ""
|
# kube_iam_role: ""
|
||||||
# log_s3_bucket: ""
|
# log_s3_bucket: ""
|
||||||
logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.3"
|
logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.7.0"
|
||||||
# logical_backup_google_application_credentials: ""
|
# logical_backup_google_application_credentials: ""
|
||||||
logical_backup_job_prefix: "logical-backup-"
|
logical_backup_job_prefix: "logical-backup-"
|
||||||
logical_backup_provider: "s3"
|
logical_backup_provider: "s3"
|
||||||
|
|
@ -129,6 +129,7 @@ data:
|
||||||
# team_api_role_configuration: "log_statement:all"
|
# team_api_role_configuration: "log_statement:all"
|
||||||
# teams_api_url: http://fake-teams-api.default.svc.cluster.local
|
# teams_api_url: http://fake-teams-api.default.svc.cluster.local
|
||||||
# toleration: ""
|
# toleration: ""
|
||||||
|
# wal_az_storage_account: ""
|
||||||
# wal_gs_bucket: ""
|
# wal_gs_bucket: ""
|
||||||
# wal_s3_bucket: ""
|
# wal_s3_bucket: ""
|
||||||
watched_namespace: "*" # listen to all namespaces
|
watched_namespace: "*" # listen to all namespaces
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ spec:
|
||||||
serviceAccountName: postgres-operator
|
serviceAccountName: postgres-operator
|
||||||
containers:
|
containers:
|
||||||
- name: postgres-operator
|
- name: postgres-operator
|
||||||
image: registry.opensource.zalan.do/acid/pgbouncer:master-16
|
image: registry.opensource.zalan.do/acid/pgbouncer:master-18
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ spec:
|
||||||
properties:
|
properties:
|
||||||
docker_image:
|
docker_image:
|
||||||
type: string
|
type: string
|
||||||
default: "registry.opensource.zalan.do/acid/spilo-13:2.0-p7"
|
default: "registry.opensource.zalan.do/acid/spilo-13:2.1-p1"
|
||||||
enable_crd_validation:
|
enable_crd_validation:
|
||||||
type: boolean
|
type: boolean
|
||||||
default: true
|
default: true
|
||||||
|
|
@ -384,6 +384,8 @@ spec:
|
||||||
type: string
|
type: string
|
||||||
log_s3_bucket:
|
log_s3_bucket:
|
||||||
type: string
|
type: string
|
||||||
|
wal_az_storage_account:
|
||||||
|
type: string
|
||||||
wal_gs_bucket:
|
wal_gs_bucket:
|
||||||
type: string
|
type: string
|
||||||
wal_s3_bucket:
|
wal_s3_bucket:
|
||||||
|
|
@ -393,7 +395,7 @@ spec:
|
||||||
properties:
|
properties:
|
||||||
logical_backup_docker_image:
|
logical_backup_docker_image:
|
||||||
type: string
|
type: string
|
||||||
default: "registry.opensource.zalan.do/acid/logical-backup:v1.6.3"
|
default: "registry.opensource.zalan.do/acid/logical-backup:v1.7.0"
|
||||||
logical_backup_google_application_credentials:
|
logical_backup_google_application_credentials:
|
||||||
type: string
|
type: string
|
||||||
logical_backup_job_prefix:
|
logical_backup_job_prefix:
|
||||||
|
|
@ -528,7 +530,7 @@ spec:
|
||||||
default: "pooler"
|
default: "pooler"
|
||||||
connection_pooler_image:
|
connection_pooler_image:
|
||||||
type: string
|
type: string
|
||||||
default: "registry.opensource.zalan.do/acid/pgbouncer:master-16"
|
default: "registry.opensource.zalan.do/acid/pgbouncer:master-18"
|
||||||
connection_pooler_max_db_connections:
|
connection_pooler_max_db_connections:
|
||||||
type: integer
|
type: integer
|
||||||
default: 60
|
default: 60
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ spec:
|
||||||
serviceAccountName: postgres-operator
|
serviceAccountName: postgres-operator
|
||||||
containers:
|
containers:
|
||||||
- name: postgres-operator
|
- name: postgres-operator
|
||||||
image: registry.opensource.zalan.do/acid/postgres-operator:v1.6.3
|
image: registry.opensource.zalan.do/acid/postgres-operator:v1.7.0
|
||||||
imagePullPolicy: IfNotPresent
|
imagePullPolicy: IfNotPresent
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ kind: OperatorConfiguration
|
||||||
metadata:
|
metadata:
|
||||||
name: postgresql-operator-default-configuration
|
name: postgresql-operator-default-configuration
|
||||||
configuration:
|
configuration:
|
||||||
docker_image: registry.opensource.zalan.do/acid/spilo-13:2.0-p7
|
docker_image: registry.opensource.zalan.do/acid/spilo-13:2.1-p1
|
||||||
# enable_crd_validation: true
|
# enable_crd_validation: true
|
||||||
# enable_lazy_spilo_upgrade: false
|
# enable_lazy_spilo_upgrade: false
|
||||||
enable_pgversion_env_var: true
|
enable_pgversion_env_var: true
|
||||||
|
|
@ -121,10 +121,11 @@ configuration:
|
||||||
# gcp_credentials: ""
|
# gcp_credentials: ""
|
||||||
# kube_iam_role: ""
|
# kube_iam_role: ""
|
||||||
# log_s3_bucket: ""
|
# log_s3_bucket: ""
|
||||||
|
# wal_az_storage_account: ""
|
||||||
# wal_gs_bucket: ""
|
# wal_gs_bucket: ""
|
||||||
# wal_s3_bucket: ""
|
# wal_s3_bucket: ""
|
||||||
logical_backup:
|
logical_backup:
|
||||||
logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.6.3"
|
logical_backup_docker_image: "registry.opensource.zalan.do/acid/logical-backup:v1.7.0"
|
||||||
# logical_backup_google_application_credentials: ""
|
# logical_backup_google_application_credentials: ""
|
||||||
logical_backup_job_prefix: "logical-backup-"
|
logical_backup_job_prefix: "logical-backup-"
|
||||||
logical_backup_provider: "s3"
|
logical_backup_provider: "s3"
|
||||||
|
|
@ -165,7 +166,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-16"
|
connection_pooler_image: "registry.opensource.zalan.do/acid/pgbouncer:master-18"
|
||||||
# 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
|
||||||
|
|
|
||||||
|
|
@ -390,6 +390,8 @@ spec:
|
||||||
type: boolean
|
type: boolean
|
||||||
defaultRoles:
|
defaultRoles:
|
||||||
type: boolean
|
type: boolean
|
||||||
|
secretNamespace:
|
||||||
|
type: string
|
||||||
replicaLoadBalancer: # deprecated
|
replicaLoadBalancer: # deprecated
|
||||||
type: boolean
|
type: boolean
|
||||||
resources:
|
resources:
|
||||||
|
|
@ -587,6 +589,24 @@ spec:
|
||||||
properties:
|
properties:
|
||||||
iops:
|
iops:
|
||||||
type: integer
|
type: integer
|
||||||
|
selector:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
matchExpressions:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
operator:
|
||||||
|
type: string
|
||||||
|
values:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
matchLabels:
|
||||||
|
type: object
|
||||||
size:
|
size:
|
||||||
type: string
|
type: string
|
||||||
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
|
pattern: '^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$'
|
||||||
|
|
|
||||||
|
|
@ -573,6 +573,9 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"secretNamespace": {
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
@ -894,6 +897,54 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{
|
||||||
"iops": {
|
"iops": {
|
||||||
Type: "integer",
|
Type: "integer",
|
||||||
},
|
},
|
||||||
|
"selector": {
|
||||||
|
Type: "object",
|
||||||
|
Properties: map[string]apiextv1.JSONSchemaProps{
|
||||||
|
"matchExpressions": {
|
||||||
|
Type: "array",
|
||||||
|
Items: &apiextv1.JSONSchemaPropsOrArray{
|
||||||
|
Schema: &apiextv1.JSONSchemaProps{
|
||||||
|
Type: "object",
|
||||||
|
Required: []string{"key", "operator", "values"},
|
||||||
|
Properties: map[string]apiextv1.JSONSchemaProps{
|
||||||
|
"key": {
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
"operator": {
|
||||||
|
Type: "string",
|
||||||
|
Enum: []apiextv1.JSON{
|
||||||
|
{
|
||||||
|
Raw: []byte(`"In"`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Raw: []byte(`"NotIn"`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Raw: []byte(`"Exists"`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Raw: []byte(`"DoesNotExist"`),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"values": {
|
||||||
|
Type: "array",
|
||||||
|
Items: &apiextv1.JSONSchemaPropsOrArray{
|
||||||
|
Schema: &apiextv1.JSONSchemaProps{
|
||||||
|
Type: "string",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"matchLabels": {
|
||||||
|
Type: "object",
|
||||||
|
XPreserveUnknownFields: util.True(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
"size": {
|
"size": {
|
||||||
Type: "string",
|
Type: "string",
|
||||||
Description: "Value must not be zero",
|
Description: "Value must not be zero",
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,7 @@ type AWSGCPConfiguration struct {
|
||||||
AWSRegion string `json:"aws_region,omitempty"`
|
AWSRegion string `json:"aws_region,omitempty"`
|
||||||
WALGSBucket string `json:"wal_gs_bucket,omitempty"`
|
WALGSBucket string `json:"wal_gs_bucket,omitempty"`
|
||||||
GCPCredentials string `json:"gcp_credentials,omitempty"`
|
GCPCredentials string `json:"gcp_credentials,omitempty"`
|
||||||
|
WALAZStorageAccount string `json:"wal_az_storage_account,omitempty"`
|
||||||
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
|
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
|
||||||
KubeIAMRole string `json:"kube_iam_role,omitempty"`
|
KubeIAMRole string `json:"kube_iam_role,omitempty"`
|
||||||
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`
|
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ type PreparedDatabase struct {
|
||||||
PreparedSchemas map[string]PreparedSchema `json:"schemas,omitempty"`
|
PreparedSchemas map[string]PreparedSchema `json:"schemas,omitempty"`
|
||||||
DefaultUsers bool `json:"defaultUsers,omitempty" defaults:"false"`
|
DefaultUsers bool `json:"defaultUsers,omitempty" defaults:"false"`
|
||||||
Extensions map[string]string `json:"extensions,omitempty"`
|
Extensions map[string]string `json:"extensions,omitempty"`
|
||||||
|
SecretNamespace string `json:"secretNamespace,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PreparedSchema describes elements to be bootstrapped per schema
|
// PreparedSchema describes elements to be bootstrapped per schema
|
||||||
|
|
@ -114,12 +115,13 @@ type MaintenanceWindow struct {
|
||||||
|
|
||||||
// Volume describes a single volume in the manifest.
|
// Volume describes a single volume in the manifest.
|
||||||
type Volume struct {
|
type Volume struct {
|
||||||
Size string `json:"size"`
|
Selector *metav1.LabelSelector `json:"selector,omitempty"`
|
||||||
StorageClass string `json:"storageClass,omitempty"`
|
Size string `json:"size"`
|
||||||
SubPath string `json:"subPath,omitempty"`
|
StorageClass string `json:"storageClass,omitempty"`
|
||||||
Iops *int64 `json:"iops,omitempty"`
|
SubPath string `json:"subPath,omitempty"`
|
||||||
Throughput *int64 `json:"throughput,omitempty"`
|
Iops *int64 `json:"iops,omitempty"`
|
||||||
VolumeType string `json:"type,omitempty"`
|
Throughput *int64 `json:"throughput,omitempty"`
|
||||||
|
VolumeType string `json:"type,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// AdditionalVolume specs additional optional volumes for statefulset
|
// AdditionalVolume specs additional optional volumes for statefulset
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,7 @@ package v1
|
||||||
import (
|
import (
|
||||||
config "github.com/zalando/postgres-operator/pkg/util/config"
|
config "github.com/zalando/postgres-operator/pkg/util/config"
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
runtime "k8s.io/apimachinery/pkg/runtime"
|
runtime "k8s.io/apimachinery/pkg/runtime"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -314,22 +315,6 @@ func (in *MaintenanceWindow) DeepCopy() *MaintenanceWindow {
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
||||||
func (in *MajorVersionUpgradeConfiguration) DeepCopyInto(out *MajorVersionUpgradeConfiguration) {
|
|
||||||
*out = *in
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MajorVersionUpgradeConfiguration.
|
|
||||||
func (in *MajorVersionUpgradeConfiguration) DeepCopy() *MajorVersionUpgradeConfiguration {
|
|
||||||
if in == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
out := new(MajorVersionUpgradeConfiguration)
|
|
||||||
in.DeepCopyInto(out)
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 *OperatorConfiguration) DeepCopyInto(out *OperatorConfiguration) {
|
func (in *OperatorConfiguration) DeepCopyInto(out *OperatorConfiguration) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
|
@ -385,7 +370,6 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
out.PostgresUsersConfiguration = in.PostgresUsersConfiguration
|
out.PostgresUsersConfiguration = in.PostgresUsersConfiguration
|
||||||
out.MajorVersionUpgrade = in.MajorVersionUpgrade
|
|
||||||
in.Kubernetes.DeepCopyInto(&out.Kubernetes)
|
in.Kubernetes.DeepCopyInto(&out.Kubernetes)
|
||||||
out.PostgresPodResources = in.PostgresPodResources
|
out.PostgresPodResources = in.PostgresPodResources
|
||||||
out.Timeouts = in.Timeouts
|
out.Timeouts = in.Timeouts
|
||||||
|
|
@ -1234,6 +1218,11 @@ func (in UserFlags) DeepCopy() UserFlags {
|
||||||
// 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 *Volume) DeepCopyInto(out *Volume) {
|
func (in *Volume) DeepCopyInto(out *Volume) {
|
||||||
*out = *in
|
*out = *in
|
||||||
|
if in.Selector != nil {
|
||||||
|
in, out := &in.Selector, &out.Selector
|
||||||
|
*out = new(metav1.LabelSelector)
|
||||||
|
(*in).DeepCopyInto(*out)
|
||||||
|
}
|
||||||
if in.Iops != nil {
|
if in.Iops != nil {
|
||||||
in, out := &in.Iops, &out.Iops
|
in, out := &in.Iops, &out.Iops
|
||||||
*out = new(int64)
|
*out = new(int64)
|
||||||
|
|
|
||||||
|
|
@ -1019,9 +1019,9 @@ func (c *Cluster) initSystemUsers() {
|
||||||
// Connection pooler user is an exception, if requested it's going to be
|
// Connection pooler user is an exception, if requested it's going to be
|
||||||
// created by operator as a normal pgUser
|
// created by operator as a normal pgUser
|
||||||
if needConnectionPooler(&c.Spec) {
|
if needConnectionPooler(&c.Spec) {
|
||||||
// initialize empty connection pooler if not done yet
|
connectionPoolerSpec := c.Spec.ConnectionPooler
|
||||||
if c.Spec.ConnectionPooler == nil {
|
if connectionPoolerSpec == nil {
|
||||||
c.Spec.ConnectionPooler = &acidv1.ConnectionPooler{}
|
connectionPoolerSpec = &acidv1.ConnectionPooler{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Using superuser as pooler user is not a good idea. First of all it's
|
// Using superuser as pooler user is not a good idea. First of all it's
|
||||||
|
|
@ -1029,13 +1029,13 @@ func (c *Cluster) initSystemUsers() {
|
||||||
// and second it's a bad practice.
|
// and second it's a bad practice.
|
||||||
username := c.OpConfig.ConnectionPooler.User
|
username := c.OpConfig.ConnectionPooler.User
|
||||||
|
|
||||||
isSuperUser := c.Spec.ConnectionPooler.User == c.OpConfig.SuperUsername
|
isSuperUser := connectionPoolerSpec.User == c.OpConfig.SuperUsername
|
||||||
isProtectedUser := c.shouldAvoidProtectedOrSystemRole(
|
isProtectedUser := c.shouldAvoidProtectedOrSystemRole(
|
||||||
c.Spec.ConnectionPooler.User, "connection pool role")
|
connectionPoolerSpec.User, "connection pool role")
|
||||||
|
|
||||||
if !isSuperUser && !isProtectedUser {
|
if !isSuperUser && !isProtectedUser {
|
||||||
username = util.Coalesce(
|
username = util.Coalesce(
|
||||||
c.Spec.ConnectionPooler.User,
|
connectionPoolerSpec.User,
|
||||||
c.OpConfig.ConnectionPooler.User)
|
c.OpConfig.ConnectionPooler.User)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1107,11 +1107,11 @@ func (c *Cluster) initPreparedDatabaseRoles() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// default roles per database
|
// default roles per database
|
||||||
if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String()); err != nil {
|
if err := c.initDefaultRoles(defaultRoles, "admin", preparedDbName, searchPath.String(), preparedDB.SecretNamespace); err != nil {
|
||||||
return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err)
|
return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err)
|
||||||
}
|
}
|
||||||
if preparedDB.DefaultUsers {
|
if preparedDB.DefaultUsers {
|
||||||
if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String()); err != nil {
|
if err := c.initDefaultRoles(defaultUsers, "admin", preparedDbName, searchPath.String(), preparedDB.SecretNamespace); err != nil {
|
||||||
return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err)
|
return fmt.Errorf("could not initialize default roles for database %s: %v", preparedDbName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1122,14 +1122,14 @@ func (c *Cluster) initPreparedDatabaseRoles() error {
|
||||||
if err := c.initDefaultRoles(defaultRoles,
|
if err := c.initDefaultRoles(defaultRoles,
|
||||||
preparedDbName+constants.OwnerRoleNameSuffix,
|
preparedDbName+constants.OwnerRoleNameSuffix,
|
||||||
preparedDbName+"_"+preparedSchemaName,
|
preparedDbName+"_"+preparedSchemaName,
|
||||||
constants.DefaultSearchPath+", "+preparedSchemaName); err != nil {
|
constants.DefaultSearchPath+", "+preparedSchemaName, preparedDB.SecretNamespace); err != nil {
|
||||||
return fmt.Errorf("could not initialize default roles for database schema %s: %v", preparedSchemaName, err)
|
return fmt.Errorf("could not initialize default roles for database schema %s: %v", preparedSchemaName, err)
|
||||||
}
|
}
|
||||||
if preparedSchema.DefaultUsers {
|
if preparedSchema.DefaultUsers {
|
||||||
if err := c.initDefaultRoles(defaultUsers,
|
if err := c.initDefaultRoles(defaultUsers,
|
||||||
preparedDbName+constants.OwnerRoleNameSuffix,
|
preparedDbName+constants.OwnerRoleNameSuffix,
|
||||||
preparedDbName+"_"+preparedSchemaName,
|
preparedDbName+"_"+preparedSchemaName,
|
||||||
constants.DefaultSearchPath+", "+preparedSchemaName); err != nil {
|
constants.DefaultSearchPath+", "+preparedSchemaName, preparedDB.SecretNamespace); err != nil {
|
||||||
return fmt.Errorf("could not initialize default users for database schema %s: %v", preparedSchemaName, err)
|
return fmt.Errorf("could not initialize default users for database schema %s: %v", preparedSchemaName, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1139,10 +1139,19 @@ func (c *Cluster) initPreparedDatabaseRoles() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix string, searchPath string) error {
|
func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix, searchPath, secretNamespace string) error {
|
||||||
|
|
||||||
for defaultRole, inherits := range defaultRoles {
|
for defaultRole, inherits := range defaultRoles {
|
||||||
|
|
||||||
|
namespace := c.Namespace
|
||||||
|
//if namespaced secrets are allowed
|
||||||
|
if secretNamespace != "" {
|
||||||
|
if c.Config.OpConfig.EnableCrossNamespaceSecret {
|
||||||
|
namespace = secretNamespace
|
||||||
|
} else {
|
||||||
|
c.logger.Warn("secretNamespace ignored because enable_cross_namespace_secret set to false. Creating secrets in cluster namespace.")
|
||||||
|
}
|
||||||
|
}
|
||||||
roleName := prefix + defaultRole
|
roleName := prefix + defaultRole
|
||||||
|
|
||||||
flags := []string{constants.RoleFlagNoLogin}
|
flags := []string{constants.RoleFlagNoLogin}
|
||||||
|
|
@ -1165,7 +1174,7 @@ func (c *Cluster) initDefaultRoles(defaultRoles map[string]string, admin, prefix
|
||||||
newRole := spec.PgUser{
|
newRole := spec.PgUser{
|
||||||
Origin: spec.RoleOriginBootstrap,
|
Origin: spec.RoleOriginBootstrap,
|
||||||
Name: roleName,
|
Name: roleName,
|
||||||
Namespace: c.Namespace,
|
Namespace: namespace,
|
||||||
Password: util.RandomPassword(constants.PasswordLength),
|
Password: util.RandomPassword(constants.PasswordLength),
|
||||||
Flags: flags,
|
Flags: flags,
|
||||||
MemberOf: memberOf,
|
MemberOf: memberOf,
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ package cluster
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/r3labs/diff"
|
"github.com/r3labs/diff"
|
||||||
|
|
@ -60,7 +61,7 @@ func needMasterConnectionPooler(spec *acidv1.PostgresSpec) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func needMasterConnectionPoolerWorker(spec *acidv1.PostgresSpec) bool {
|
func needMasterConnectionPoolerWorker(spec *acidv1.PostgresSpec) bool {
|
||||||
return (nil != spec.EnableConnectionPooler && *spec.EnableConnectionPooler) ||
|
return (spec.EnableConnectionPooler != nil && *spec.EnableConnectionPooler) ||
|
||||||
(spec.ConnectionPooler != nil && spec.EnableConnectionPooler == nil)
|
(spec.ConnectionPooler != nil && spec.EnableConnectionPooler == nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -114,7 +115,7 @@ func (c *Cluster) createConnectionPooler(LookupFunction InstallFunction) (SyncRe
|
||||||
c.setProcessName("creating connection pooler")
|
c.setProcessName("creating connection pooler")
|
||||||
|
|
||||||
//this is essentially sync with nil as oldSpec
|
//this is essentially sync with nil as oldSpec
|
||||||
if reason, err := c.syncConnectionPooler(nil, &c.Postgresql, LookupFunction); err != nil {
|
if reason, err := c.syncConnectionPooler(&acidv1.Postgresql{}, &c.Postgresql, LookupFunction); err != nil {
|
||||||
return reason, err
|
return reason, err
|
||||||
}
|
}
|
||||||
return reason, nil
|
return reason, nil
|
||||||
|
|
@ -140,11 +141,15 @@ func (c *Cluster) createConnectionPooler(LookupFunction InstallFunction) (SyncRe
|
||||||
// RESERVE_SIZE is how many additional connections to allow for a pooler.
|
// RESERVE_SIZE is how many additional connections to allow for a pooler.
|
||||||
func (c *Cluster) getConnectionPoolerEnvVars() []v1.EnvVar {
|
func (c *Cluster) getConnectionPoolerEnvVars() []v1.EnvVar {
|
||||||
spec := &c.Spec
|
spec := &c.Spec
|
||||||
|
connectionPoolerSpec := spec.ConnectionPooler
|
||||||
|
if connectionPoolerSpec == nil {
|
||||||
|
connectionPoolerSpec = &acidv1.ConnectionPooler{}
|
||||||
|
}
|
||||||
effectiveMode := util.Coalesce(
|
effectiveMode := util.Coalesce(
|
||||||
spec.ConnectionPooler.Mode,
|
connectionPoolerSpec.Mode,
|
||||||
c.OpConfig.ConnectionPooler.Mode)
|
c.OpConfig.ConnectionPooler.Mode)
|
||||||
|
|
||||||
numberOfInstances := spec.ConnectionPooler.NumberOfInstances
|
numberOfInstances := connectionPoolerSpec.NumberOfInstances
|
||||||
if numberOfInstances == nil {
|
if numberOfInstances == nil {
|
||||||
numberOfInstances = util.CoalesceInt32(
|
numberOfInstances = util.CoalesceInt32(
|
||||||
c.OpConfig.ConnectionPooler.NumberOfInstances,
|
c.OpConfig.ConnectionPooler.NumberOfInstances,
|
||||||
|
|
@ -152,7 +157,7 @@ func (c *Cluster) getConnectionPoolerEnvVars() []v1.EnvVar {
|
||||||
}
|
}
|
||||||
|
|
||||||
effectiveMaxDBConn := util.CoalesceInt32(
|
effectiveMaxDBConn := util.CoalesceInt32(
|
||||||
spec.ConnectionPooler.MaxDBConnections,
|
connectionPoolerSpec.MaxDBConnections,
|
||||||
c.OpConfig.ConnectionPooler.MaxDBConnections)
|
c.OpConfig.ConnectionPooler.MaxDBConnections)
|
||||||
|
|
||||||
if effectiveMaxDBConn == nil {
|
if effectiveMaxDBConn == nil {
|
||||||
|
|
@ -201,17 +206,21 @@ func (c *Cluster) getConnectionPoolerEnvVars() []v1.EnvVar {
|
||||||
func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
|
func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
|
||||||
*v1.PodTemplateSpec, error) {
|
*v1.PodTemplateSpec, error) {
|
||||||
spec := &c.Spec
|
spec := &c.Spec
|
||||||
|
connectionPoolerSpec := spec.ConnectionPooler
|
||||||
|
if connectionPoolerSpec == nil {
|
||||||
|
connectionPoolerSpec = &acidv1.ConnectionPooler{}
|
||||||
|
}
|
||||||
gracePeriod := int64(c.OpConfig.PodTerminateGracePeriod.Seconds())
|
gracePeriod := int64(c.OpConfig.PodTerminateGracePeriod.Seconds())
|
||||||
resources, err := generateResourceRequirements(
|
resources, err := generateResourceRequirements(
|
||||||
spec.ConnectionPooler.Resources,
|
connectionPoolerSpec.Resources,
|
||||||
makeDefaultConnectionPoolerResources(&c.OpConfig))
|
makeDefaultConnectionPoolerResources(&c.OpConfig))
|
||||||
|
|
||||||
effectiveDockerImage := util.Coalesce(
|
effectiveDockerImage := util.Coalesce(
|
||||||
spec.ConnectionPooler.DockerImage,
|
connectionPoolerSpec.DockerImage,
|
||||||
c.OpConfig.ConnectionPooler.Image)
|
c.OpConfig.ConnectionPooler.Image)
|
||||||
|
|
||||||
effectiveSchema := util.Coalesce(
|
effectiveSchema := util.Coalesce(
|
||||||
spec.ConnectionPooler.Schema,
|
connectionPoolerSpec.Schema,
|
||||||
c.OpConfig.ConnectionPooler.Schema)
|
c.OpConfig.ConnectionPooler.Schema)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -220,7 +229,7 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
|
||||||
|
|
||||||
secretSelector := func(key string) *v1.SecretKeySelector {
|
secretSelector := func(key string) *v1.SecretKeySelector {
|
||||||
effectiveUser := util.Coalesce(
|
effectiveUser := util.Coalesce(
|
||||||
spec.ConnectionPooler.User,
|
connectionPoolerSpec.User,
|
||||||
c.OpConfig.ConnectionPooler.User)
|
c.OpConfig.ConnectionPooler.User)
|
||||||
|
|
||||||
return &v1.SecretKeySelector{
|
return &v1.SecretKeySelector{
|
||||||
|
|
@ -285,6 +294,8 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tolerationsSpec := tolerations(&spec.Tolerations, c.OpConfig.PodToleration)
|
||||||
|
|
||||||
podTemplate := &v1.PodTemplateSpec{
|
podTemplate := &v1.PodTemplateSpec{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Labels: c.connectionPoolerLabels(role, true).MatchLabels,
|
Labels: c.connectionPoolerLabels(role, true).MatchLabels,
|
||||||
|
|
@ -294,12 +305,18 @@ func (c *Cluster) generateConnectionPoolerPodTemplate(role PostgresRole) (
|
||||||
Spec: v1.PodSpec{
|
Spec: v1.PodSpec{
|
||||||
TerminationGracePeriodSeconds: &gracePeriod,
|
TerminationGracePeriodSeconds: &gracePeriod,
|
||||||
Containers: []v1.Container{poolerContainer},
|
Containers: []v1.Container{poolerContainer},
|
||||||
// TODO: add tolerations to scheduler pooler on the same node
|
Tolerations: tolerationsSpec,
|
||||||
// as database
|
|
||||||
//Tolerations: *tolerationsSpec,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeAffinity := nodeAffinity(c.OpConfig.NodeReadinessLabel, spec.NodeAffinity)
|
||||||
|
if c.OpConfig.EnablePodAntiAffinity {
|
||||||
|
labelsSet := labels.Set(c.connectionPoolerLabels(role, false).MatchLabels)
|
||||||
|
podTemplate.Spec.Affinity = generatePodAffinity(labelsSet, c.OpConfig.PodAntiAffinityTopologyKey, nodeAffinity)
|
||||||
|
} else if nodeAffinity != nil {
|
||||||
|
podTemplate.Spec.Affinity = nodeAffinity
|
||||||
|
}
|
||||||
|
|
||||||
return podTemplate, nil
|
return podTemplate, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -313,12 +330,13 @@ func (c *Cluster) generateConnectionPoolerDeployment(connectionPooler *Connectio
|
||||||
// default values, initialize it to an empty structure. It could be done
|
// default values, initialize it to an empty structure. It could be done
|
||||||
// anywhere, but here is the earliest common entry point between sync and
|
// anywhere, but here is the earliest common entry point between sync and
|
||||||
// create code, so init here.
|
// create code, so init here.
|
||||||
if spec.ConnectionPooler == nil {
|
connectionPoolerSpec := spec.ConnectionPooler
|
||||||
spec.ConnectionPooler = &acidv1.ConnectionPooler{}
|
if connectionPoolerSpec == nil {
|
||||||
|
connectionPoolerSpec = &acidv1.ConnectionPooler{}
|
||||||
}
|
}
|
||||||
podTemplate, err := c.generateConnectionPoolerPodTemplate(connectionPooler.Role)
|
podTemplate, err := c.generateConnectionPoolerPodTemplate(connectionPooler.Role)
|
||||||
|
|
||||||
numberOfInstances := spec.ConnectionPooler.NumberOfInstances
|
numberOfInstances := connectionPoolerSpec.NumberOfInstances
|
||||||
if numberOfInstances == nil {
|
if numberOfInstances == nil {
|
||||||
numberOfInstances = util.CoalesceInt32(
|
numberOfInstances = util.CoalesceInt32(
|
||||||
c.OpConfig.ConnectionPooler.NumberOfInstances,
|
c.OpConfig.ConnectionPooler.NumberOfInstances,
|
||||||
|
|
@ -363,16 +381,6 @@ func (c *Cluster) generateConnectionPoolerDeployment(connectionPooler *Connectio
|
||||||
func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPoolerObjects) *v1.Service {
|
func (c *Cluster) generateConnectionPoolerService(connectionPooler *ConnectionPoolerObjects) *v1.Service {
|
||||||
|
|
||||||
spec := &c.Spec
|
spec := &c.Spec
|
||||||
// there are two ways to enable connection pooler, either to specify a
|
|
||||||
// connectionPooler section or enableConnectionPooler. In the second case
|
|
||||||
// spec.connectionPooler will be nil, so to make it easier to calculate
|
|
||||||
// default values, initialize it to an empty structure. It could be done
|
|
||||||
// anywhere, but here is the earliest common entry point between sync and
|
|
||||||
// create code, so init here.
|
|
||||||
if spec.ConnectionPooler == nil {
|
|
||||||
spec.ConnectionPooler = &acidv1.ConnectionPooler{}
|
|
||||||
}
|
|
||||||
|
|
||||||
serviceSpec := v1.ServiceSpec{
|
serviceSpec := v1.ServiceSpec{
|
||||||
Ports: []v1.ServicePort{
|
Ports: []v1.ServicePort{
|
||||||
{
|
{
|
||||||
|
|
@ -660,12 +668,14 @@ func makeDefaultConnectionPoolerResources(config *config.Config) acidv1.Resource
|
||||||
|
|
||||||
func logPoolerEssentials(log *logrus.Entry, oldSpec, newSpec *acidv1.Postgresql) {
|
func logPoolerEssentials(log *logrus.Entry, oldSpec, newSpec *acidv1.Postgresql) {
|
||||||
var v []string
|
var v []string
|
||||||
|
|
||||||
var input []*bool
|
var input []*bool
|
||||||
|
|
||||||
|
newMasterConnectionPoolerEnabled := needMasterConnectionPoolerWorker(&newSpec.Spec)
|
||||||
if oldSpec == nil {
|
if oldSpec == nil {
|
||||||
input = []*bool{nil, nil, newSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableReplicaConnectionPooler}
|
input = []*bool{nil, nil, &newMasterConnectionPoolerEnabled, newSpec.Spec.EnableReplicaConnectionPooler}
|
||||||
} else {
|
} else {
|
||||||
input = []*bool{oldSpec.Spec.EnableConnectionPooler, oldSpec.Spec.EnableReplicaConnectionPooler, newSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableReplicaConnectionPooler}
|
oldMasterConnectionPoolerEnabled := needMasterConnectionPoolerWorker(&oldSpec.Spec)
|
||||||
|
input = []*bool{&oldMasterConnectionPoolerEnabled, oldSpec.Spec.EnableReplicaConnectionPooler, &newMasterConnectionPoolerEnabled, newSpec.Spec.EnableReplicaConnectionPooler}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, b := range input {
|
for _, b := range input {
|
||||||
|
|
@ -676,25 +686,16 @@ func logPoolerEssentials(log *logrus.Entry, oldSpec, newSpec *acidv1.Postgresql)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("syncing connection pooler from (%v, %v) to (%v, %v)", v[0], v[1], v[2], v[3])
|
log.Debugf("syncing connection pooler (master, replica) from (%v, %v) to (%v, %v)", v[0], v[1], v[2], v[3])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, LookupFunction InstallFunction) (SyncReason, error) {
|
func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, LookupFunction InstallFunction) (SyncReason, error) {
|
||||||
|
|
||||||
var reason SyncReason
|
var reason SyncReason
|
||||||
var err error
|
var err error
|
||||||
var newNeedConnectionPooler, oldNeedConnectionPooler bool
|
var connectionPoolerNeeded bool
|
||||||
oldNeedConnectionPooler = false
|
|
||||||
|
|
||||||
if oldSpec == nil {
|
needSync := !reflect.DeepEqual(oldSpec.Spec.ConnectionPooler, newSpec.Spec.ConnectionPooler)
|
||||||
oldSpec = &acidv1.Postgresql{
|
|
||||||
Spec: acidv1.PostgresSpec{
|
|
||||||
ConnectionPooler: &acidv1.ConnectionPooler{},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
needSync, _ := needSyncConnectionPoolerSpecs(oldSpec.Spec.ConnectionPooler, newSpec.Spec.ConnectionPooler, c.logger)
|
|
||||||
masterChanges, err := diff.Diff(oldSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableConnectionPooler)
|
masterChanges, err := diff.Diff(oldSpec.Spec.EnableConnectionPooler, newSpec.Spec.EnableConnectionPooler)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.logger.Error("Error in getting diff of master connection pooler changes")
|
c.logger.Error("Error in getting diff of master connection pooler changes")
|
||||||
|
|
@ -704,15 +705,14 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
|
||||||
c.logger.Error("Error in getting diff of replica connection pooler changes")
|
c.logger.Error("Error in getting diff of replica connection pooler changes")
|
||||||
}
|
}
|
||||||
|
|
||||||
// skip pooler sync only
|
// skip pooler sync when theres no diff or it's deactivated
|
||||||
// 1. if there is no diff in spec, AND
|
// but, handling the case when connectionPooler is not there but it is required
|
||||||
// 2. if connection pooler is already there and is also required as per newSpec
|
|
||||||
//
|
|
||||||
// Handling the case when connectionPooler is not there but it is required
|
|
||||||
// as per spec, hence do not skip syncing in that case, even though there
|
// as per spec, hence do not skip syncing in that case, even though there
|
||||||
// is no diff in specs
|
// is no diff in specs
|
||||||
if (!needSync && len(masterChanges) <= 0 && len(replicaChanges) <= 0) &&
|
if (!needSync && len(masterChanges) <= 0 && len(replicaChanges) <= 0) &&
|
||||||
(c.ConnectionPooler != nil && (needConnectionPooler(&newSpec.Spec))) {
|
((!needConnectionPooler(&newSpec.Spec) && (c.ConnectionPooler == nil || !needConnectionPooler(&oldSpec.Spec))) ||
|
||||||
|
(c.ConnectionPooler != nil && needConnectionPooler(&newSpec.Spec) &&
|
||||||
|
(c.ConnectionPooler[Master].LookupFunction || c.ConnectionPooler[Replica].LookupFunction))) {
|
||||||
c.logger.Debugln("syncing pooler is not required")
|
c.logger.Debugln("syncing pooler is not required")
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -723,15 +723,9 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
|
||||||
for _, role := range [2]PostgresRole{Master, Replica} {
|
for _, role := range [2]PostgresRole{Master, Replica} {
|
||||||
|
|
||||||
if role == Master {
|
if role == Master {
|
||||||
newNeedConnectionPooler = needMasterConnectionPoolerWorker(&newSpec.Spec)
|
connectionPoolerNeeded = needMasterConnectionPoolerWorker(&newSpec.Spec)
|
||||||
if oldSpec != nil {
|
|
||||||
oldNeedConnectionPooler = needMasterConnectionPoolerWorker(&oldSpec.Spec)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
newNeedConnectionPooler = needReplicaConnectionPoolerWorker(&newSpec.Spec)
|
connectionPoolerNeeded = needReplicaConnectionPoolerWorker(&newSpec.Spec)
|
||||||
if oldSpec != nil {
|
|
||||||
oldNeedConnectionPooler = needReplicaConnectionPoolerWorker(&oldSpec.Spec)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the call is via createConnectionPooler, then it is required to initialize
|
// if the call is via createConnectionPooler, then it is required to initialize
|
||||||
|
|
@ -751,24 +745,22 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if newNeedConnectionPooler {
|
if connectionPoolerNeeded {
|
||||||
// Try to sync in any case. If we didn't needed connection pooler before,
|
// Try to sync in any case. If we didn't needed connection pooler before,
|
||||||
// it means we want to create it. If it was already present, still sync
|
// it means we want to create it. If it was already present, still sync
|
||||||
// since it could happen that there is no difference in specs, and all
|
// since it could happen that there is no difference in specs, and all
|
||||||
// the resources are remembered, but the deployment was manually deleted
|
// the resources are remembered, but the deployment was manually deleted
|
||||||
// in between
|
// in between
|
||||||
|
|
||||||
// in this case also do not forget to install lookup function as for
|
// in this case also do not forget to install lookup function
|
||||||
// creating cluster
|
if !c.ConnectionPooler[role].LookupFunction {
|
||||||
if !oldNeedConnectionPooler || !c.ConnectionPooler[role].LookupFunction {
|
connectionPooler := c.Spec.ConnectionPooler
|
||||||
newConnectionPooler := newSpec.Spec.ConnectionPooler
|
|
||||||
|
|
||||||
specSchema := ""
|
specSchema := ""
|
||||||
specUser := ""
|
specUser := ""
|
||||||
|
|
||||||
if newConnectionPooler != nil {
|
if connectionPooler != nil {
|
||||||
specSchema = newConnectionPooler.Schema
|
specSchema = connectionPooler.Schema
|
||||||
specUser = newConnectionPooler.User
|
specUser = connectionPooler.User
|
||||||
}
|
}
|
||||||
|
|
||||||
schema := util.Coalesce(
|
schema := util.Coalesce(
|
||||||
|
|
@ -779,9 +771,10 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
|
||||||
specUser,
|
specUser,
|
||||||
c.OpConfig.ConnectionPooler.User)
|
c.OpConfig.ConnectionPooler.User)
|
||||||
|
|
||||||
if err = LookupFunction(schema, user, role); err != nil {
|
if err = LookupFunction(schema, user); err != nil {
|
||||||
return NoSync, err
|
return NoSync, err
|
||||||
}
|
}
|
||||||
|
c.ConnectionPooler[role].LookupFunction = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if reason, err = c.syncConnectionPoolerWorker(oldSpec, newSpec, role); err != nil {
|
if reason, err = c.syncConnectionPoolerWorker(oldSpec, newSpec, role); err != nil {
|
||||||
|
|
@ -800,8 +793,8 @@ func (c *Cluster) syncConnectionPooler(oldSpec, newSpec *acidv1.Postgresql, Look
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !needMasterConnectionPoolerWorker(&newSpec.Spec) &&
|
if (needMasterConnectionPoolerWorker(&oldSpec.Spec) || needReplicaConnectionPoolerWorker(&oldSpec.Spec)) &&
|
||||||
!needReplicaConnectionPoolerWorker(&newSpec.Spec) {
|
!needMasterConnectionPoolerWorker(&newSpec.Spec) && !needReplicaConnectionPoolerWorker(&newSpec.Spec) {
|
||||||
if err = c.deleteConnectionPoolerSecret(); err != nil {
|
if err = c.deleteConnectionPoolerSecret(); err != nil {
|
||||||
c.logger.Warningf("could not remove connection pooler secret: %v", err)
|
c.logger.Warningf("could not remove connection pooler secret: %v", err)
|
||||||
}
|
}
|
||||||
|
|
@ -866,8 +859,6 @@ func (c *Cluster) syncConnectionPoolerWorker(oldSpec, newSpec *acidv1.Postgresql
|
||||||
newConnectionPooler = &acidv1.ConnectionPooler{}
|
newConnectionPooler = &acidv1.ConnectionPooler{}
|
||||||
}
|
}
|
||||||
|
|
||||||
c.logger.Infof("old: %+v, new %+v", oldConnectionPooler, newConnectionPooler)
|
|
||||||
|
|
||||||
var specSync bool
|
var specSync bool
|
||||||
var specReason []string
|
var specReason []string
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ import (
|
||||||
"k8s.io/client-go/kubernetes/fake"
|
"k8s.io/client-go/kubernetes/fake"
|
||||||
)
|
)
|
||||||
|
|
||||||
func mockInstallLookupFunction(schema string, user string, role PostgresRole) error {
|
func mockInstallLookupFunction(schema string, user string) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -508,7 +508,7 @@ func (c *Cluster) execCreateOrAlterExtension(extName, schemaName, statement, doi
|
||||||
|
|
||||||
// Creates a connection pool credentials lookup function in every database to
|
// Creates a connection pool credentials lookup function in every database to
|
||||||
// perform remote authentication.
|
// perform remote authentication.
|
||||||
func (c *Cluster) installLookupFunction(poolerSchema, poolerUser string, role PostgresRole) error {
|
func (c *Cluster) installLookupFunction(poolerSchema, poolerUser string) error {
|
||||||
var stmtBytes bytes.Buffer
|
var stmtBytes bytes.Buffer
|
||||||
|
|
||||||
c.logger.Info("Installing lookup function")
|
c.logger.Info("Installing lookup function")
|
||||||
|
|
@ -604,8 +604,8 @@ func (c *Cluster) installLookupFunction(poolerSchema, poolerUser string, role Po
|
||||||
c.logger.Infof("pooler lookup function installed into %s", dbname)
|
c.logger.Infof("pooler lookup function installed into %s", dbname)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(failedDatabases) == 0 {
|
if len(failedDatabases) > 0 {
|
||||||
c.ConnectionPooler[role].LookupFunction = true
|
return fmt.Errorf("could not install pooler lookup function in every specified databases")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
||||||
|
|
@ -798,6 +798,12 @@ func (c *Cluster) generateSpiloPodEnvVars(uid types.UID, spiloConfiguration stri
|
||||||
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_PREFIX", Value: ""})
|
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_PREFIX", Value: ""})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if c.OpConfig.WALAZStorageAccount != "" {
|
||||||
|
envVars = append(envVars, v1.EnvVar{Name: "AZURE_STORAGE_ACCOUNT", Value: c.OpConfig.WALAZStorageAccount})
|
||||||
|
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_SUFFIX", Value: getBucketScopeSuffix(string(uid))})
|
||||||
|
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_PREFIX", Value: ""})
|
||||||
|
}
|
||||||
|
|
||||||
if c.OpConfig.GCPCredentials != "" {
|
if c.OpConfig.GCPCredentials != "" {
|
||||||
envVars = append(envVars, v1.EnvVar{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: c.OpConfig.GCPCredentials})
|
envVars = append(envVars, v1.EnvVar{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: c.OpConfig.GCPCredentials})
|
||||||
}
|
}
|
||||||
|
|
@ -1170,9 +1176,6 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate the spilo container
|
// generate the spilo container
|
||||||
c.logger.Debugf("Generating Spilo container, environment variables")
|
|
||||||
c.logger.Debugf("%v", spiloEnvVars)
|
|
||||||
|
|
||||||
spiloContainer := generateContainer(constants.PostgresContainerName,
|
spiloContainer := generateContainer(constants.PostgresContainerName,
|
||||||
&effectiveDockerImage,
|
&effectiveDockerImage,
|
||||||
resourceRequirements,
|
resourceRequirements,
|
||||||
|
|
@ -1275,7 +1278,7 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef
|
||||||
}
|
}
|
||||||
|
|
||||||
if volumeClaimTemplate, err = generatePersistentVolumeClaimTemplate(spec.Volume.Size,
|
if volumeClaimTemplate, err = generatePersistentVolumeClaimTemplate(spec.Volume.Size,
|
||||||
spec.Volume.StorageClass); err != nil {
|
spec.Volume.StorageClass, spec.Volume.Selector); err != nil {
|
||||||
return nil, fmt.Errorf("could not generate volume claim template: %v", err)
|
return nil, fmt.Errorf("could not generate volume claim template: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1523,7 +1526,8 @@ func (c *Cluster) addAdditionalVolumes(podSpec *v1.PodSpec,
|
||||||
podSpec.Volumes = volumes
|
podSpec.Volumes = volumes
|
||||||
}
|
}
|
||||||
|
|
||||||
func generatePersistentVolumeClaimTemplate(volumeSize, volumeStorageClass string) (*v1.PersistentVolumeClaim, error) {
|
func generatePersistentVolumeClaimTemplate(volumeSize, volumeStorageClass string,
|
||||||
|
volumeSelector *metav1.LabelSelector) (*v1.PersistentVolumeClaim, error) {
|
||||||
|
|
||||||
var storageClassName *string
|
var storageClassName *string
|
||||||
|
|
||||||
|
|
@ -1556,6 +1560,7 @@ func generatePersistentVolumeClaimTemplate(volumeSize, volumeStorageClass string
|
||||||
},
|
},
|
||||||
StorageClassName: storageClassName,
|
StorageClassName: storageClassName,
|
||||||
VolumeMode: &volumeMode,
|
VolumeMode: &volumeMode,
|
||||||
|
Selector: volumeSelector,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1806,6 +1811,14 @@ func (c *Cluster) generateCloneEnvironment(description *acidv1.CloneDescription)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
result = append(result, envs...)
|
result = append(result, envs...)
|
||||||
|
} else if c.OpConfig.WALAZStorageAccount != "" {
|
||||||
|
envs := []v1.EnvVar{
|
||||||
|
{
|
||||||
|
Name: "CLONE_AZURE_STORAGE_ACCOUNT",
|
||||||
|
Value: c.OpConfig.WALAZStorageAccount,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
result = append(result, envs...)
|
||||||
} else {
|
} else {
|
||||||
c.logger.Error("Cannot figure out S3 or GS bucket. Both are empty.")
|
c.logger.Error("Cannot figure out S3 or GS bucket. Both are empty.")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1509,3 +1509,106 @@ func TestGenerateCapabilities(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVolumeSelector(t *testing.T) {
|
||||||
|
testName := "TestVolumeSelector"
|
||||||
|
makeSpec := func(volume acidv1.Volume) acidv1.PostgresSpec {
|
||||||
|
return acidv1.PostgresSpec{
|
||||||
|
TeamID: "myapp",
|
||||||
|
NumberOfInstances: 0,
|
||||||
|
Resources: acidv1.Resources{
|
||||||
|
ResourceRequests: acidv1.ResourceDescription{CPU: "1", Memory: "10"},
|
||||||
|
ResourceLimits: acidv1.ResourceDescription{CPU: "1", Memory: "10"},
|
||||||
|
},
|
||||||
|
Volume: volume,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
subTest string
|
||||||
|
volume acidv1.Volume
|
||||||
|
wantSelector *metav1.LabelSelector
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
subTest: "PVC template has no selector",
|
||||||
|
volume: acidv1.Volume{
|
||||||
|
Size: "1G",
|
||||||
|
},
|
||||||
|
wantSelector: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
subTest: "PVC template has simple label selector",
|
||||||
|
volume: acidv1.Volume{
|
||||||
|
Size: "1G",
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"environment": "unittest"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"environment": "unittest"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
subTest: "PVC template has full selector",
|
||||||
|
volume: acidv1.Volume{
|
||||||
|
Size: "1G",
|
||||||
|
Selector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"environment": "unittest"},
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "flavour",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"banana", "chocolate"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantSelector: &metav1.LabelSelector{
|
||||||
|
MatchLabels: map[string]string{"environment": "unittest"},
|
||||||
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
||||||
|
{
|
||||||
|
Key: "flavour",
|
||||||
|
Operator: metav1.LabelSelectorOpIn,
|
||||||
|
Values: []string{"banana", "chocolate"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster := New(
|
||||||
|
Config{
|
||||||
|
OpConfig: config.Config{
|
||||||
|
PodManagementPolicy: "ordered_ready",
|
||||||
|
ProtectedRoles: []string{"admin"},
|
||||||
|
Auth: config.Auth{
|
||||||
|
SuperUsername: superUserName,
|
||||||
|
ReplicationUsername: replicationUserName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, k8sutil.KubernetesClient{}, acidv1.Postgresql{}, logger, eventRecorder)
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
pgSpec := makeSpec(tt.volume)
|
||||||
|
sts, err := cluster.generateStatefulSet(&pgSpec)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s %s: no statefulset created %v", testName, tt.subTest, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
volIdx := len(sts.Spec.VolumeClaimTemplates)
|
||||||
|
for i, ct := range sts.Spec.VolumeClaimTemplates {
|
||||||
|
if ct.ObjectMeta.Name == constants.DataVolumeName {
|
||||||
|
volIdx = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if volIdx == len(sts.Spec.VolumeClaimTemplates) {
|
||||||
|
t.Errorf("%s %s: no datavolume found in sts", testName, tt.subTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
selector := sts.Spec.VolumeClaimTemplates[volIdx].Spec.Selector
|
||||||
|
if !reflect.DeepEqual(selector, tt.wantSelector) {
|
||||||
|
t.Errorf("%s %s: expected: %#v but got: %#v", testName, tt.subTest, tt.wantSelector, selector)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -746,6 +746,15 @@ func (c *Cluster) syncDatabases() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(createDatabases) > 0 {
|
||||||
|
// trigger creation of pooler objects in new database in syncConnectionPooler
|
||||||
|
if c.ConnectionPooler != nil {
|
||||||
|
for _, role := range [2]PostgresRole{Master, Replica} {
|
||||||
|
c.ConnectionPooler[role].LookupFunction = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// set default privileges for prepared database
|
// set default privileges for prepared database
|
||||||
for _, preparedDatabase := range preparedDatabases {
|
for _, preparedDatabase := range preparedDatabases {
|
||||||
if err := c.initDbConnWithName(preparedDatabase); err != nil {
|
if err := c.initDbConnWithName(preparedDatabase); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ type ClusterStatus struct {
|
||||||
|
|
||||||
type TemplateParams map[string]interface{}
|
type TemplateParams map[string]interface{}
|
||||||
|
|
||||||
type InstallFunction func(schema string, user string, role PostgresRole) error
|
type InstallFunction func(schema string, user string) error
|
||||||
|
|
||||||
type SyncReason []string
|
type SyncReason []string
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||||
result.EnableSpiloWalPathCompat = fromCRD.EnableSpiloWalPathCompat
|
result.EnableSpiloWalPathCompat = fromCRD.EnableSpiloWalPathCompat
|
||||||
result.EtcdHost = fromCRD.EtcdHost
|
result.EtcdHost = fromCRD.EtcdHost
|
||||||
result.KubernetesUseConfigMaps = fromCRD.KubernetesUseConfigMaps
|
result.KubernetesUseConfigMaps = fromCRD.KubernetesUseConfigMaps
|
||||||
result.DockerImage = util.Coalesce(fromCRD.DockerImage, "registry.opensource.zalan.do/acid/spilo-13:2.0-p7")
|
result.DockerImage = util.Coalesce(fromCRD.DockerImage, "registry.opensource.zalan.do/acid/spilo-13:2.1-p1")
|
||||||
result.Workers = util.CoalesceUInt32(fromCRD.Workers, 8)
|
result.Workers = util.CoalesceUInt32(fromCRD.Workers, 8)
|
||||||
result.MinInstances = fromCRD.MinInstances
|
result.MinInstances = fromCRD.MinInstances
|
||||||
result.MaxInstances = fromCRD.MaxInstances
|
result.MaxInstances = fromCRD.MaxInstances
|
||||||
|
|
@ -146,6 +146,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||||
result.KubeIAMRole = fromCRD.AWSGCP.KubeIAMRole
|
result.KubeIAMRole = fromCRD.AWSGCP.KubeIAMRole
|
||||||
result.WALGSBucket = fromCRD.AWSGCP.WALGSBucket
|
result.WALGSBucket = fromCRD.AWSGCP.WALGSBucket
|
||||||
result.GCPCredentials = fromCRD.AWSGCP.GCPCredentials
|
result.GCPCredentials = fromCRD.AWSGCP.GCPCredentials
|
||||||
|
result.WALAZStorageAccount = fromCRD.AWSGCP.WALAZStorageAccount
|
||||||
result.AdditionalSecretMount = fromCRD.AWSGCP.AdditionalSecretMount
|
result.AdditionalSecretMount = fromCRD.AWSGCP.AdditionalSecretMount
|
||||||
result.AdditionalSecretMountPath = util.Coalesce(fromCRD.AWSGCP.AdditionalSecretMountPath, "/meta/credentials")
|
result.AdditionalSecretMountPath = util.Coalesce(fromCRD.AWSGCP.AdditionalSecretMountPath, "/meta/credentials")
|
||||||
result.EnableEBSGp3Migration = fromCRD.AWSGCP.EnableEBSGp3Migration
|
result.EnableEBSGp3Migration = fromCRD.AWSGCP.EnableEBSGp3Migration
|
||||||
|
|
@ -153,7 +154,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
|
||||||
|
|
||||||
// logical backup config
|
// logical backup config
|
||||||
result.LogicalBackupSchedule = util.Coalesce(fromCRD.LogicalBackup.Schedule, "30 00 * * *")
|
result.LogicalBackupSchedule = util.Coalesce(fromCRD.LogicalBackup.Schedule, "30 00 * * *")
|
||||||
result.LogicalBackupDockerImage = util.Coalesce(fromCRD.LogicalBackup.DockerImage, "registry.opensource.zalan.do/acid/logical-backup:v1.6.3")
|
result.LogicalBackupDockerImage = util.Coalesce(fromCRD.LogicalBackup.DockerImage, "registry.opensource.zalan.do/acid/logical-backup:v1.7.0")
|
||||||
result.LogicalBackupProvider = util.Coalesce(fromCRD.LogicalBackup.BackupProvider, "s3")
|
result.LogicalBackupProvider = util.Coalesce(fromCRD.LogicalBackup.BackupProvider, "s3")
|
||||||
result.LogicalBackupS3Bucket = fromCRD.LogicalBackup.S3Bucket
|
result.LogicalBackupS3Bucket = fromCRD.LogicalBackup.S3Bucket
|
||||||
result.LogicalBackupS3Region = fromCRD.LogicalBackup.S3Region
|
result.LogicalBackupS3Region = fromCRD.LogicalBackup.S3Region
|
||||||
|
|
|
||||||
|
|
@ -114,7 +114,7 @@ type Scalyr struct {
|
||||||
// LogicalBackup defines configuration for logical backup
|
// LogicalBackup defines configuration for logical backup
|
||||||
type LogicalBackup struct {
|
type LogicalBackup struct {
|
||||||
LogicalBackupSchedule string `name:"logical_backup_schedule" default:"30 00 * * *"`
|
LogicalBackupSchedule string `name:"logical_backup_schedule" default:"30 00 * * *"`
|
||||||
LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup:v1.6.3"`
|
LogicalBackupDockerImage string `name:"logical_backup_docker_image" default:"registry.opensource.zalan.do/acid/logical-backup:v1.7.0"`
|
||||||
LogicalBackupProvider string `name:"logical_backup_provider" default:"s3"`
|
LogicalBackupProvider string `name:"logical_backup_provider" default:"s3"`
|
||||||
LogicalBackupS3Bucket string `name:"logical_backup_s3_bucket" default:""`
|
LogicalBackupS3Bucket string `name:"logical_backup_s3_bucket" default:""`
|
||||||
LogicalBackupS3Region string `name:"logical_backup_s3_region" default:""`
|
LogicalBackupS3Region string `name:"logical_backup_s3_region" default:""`
|
||||||
|
|
@ -152,7 +152,7 @@ type Config struct {
|
||||||
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"`
|
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-13:2.0-p7"`
|
DockerImage string `name:"docker_image" default:"registry.opensource.zalan.do/acid/spilo-13:2.1-p1"`
|
||||||
SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers
|
SidecarImages map[string]string `name:"sidecar_docker_images"` // deprecated in favour of SidecarContainers
|
||||||
SidecarContainers []v1.Container `name:"sidecars"`
|
SidecarContainers []v1.Container `name:"sidecars"`
|
||||||
PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"`
|
PodServiceAccountName string `name:"pod_service_account_name" default:"postgres-pod"`
|
||||||
|
|
@ -167,6 +167,7 @@ type Config struct {
|
||||||
KubeIAMRole string `name:"kube_iam_role"`
|
KubeIAMRole string `name:"kube_iam_role"`
|
||||||
WALGSBucket string `name:"wal_gs_bucket"`
|
WALGSBucket string `name:"wal_gs_bucket"`
|
||||||
GCPCredentials string `name:"gcp_credentials"`
|
GCPCredentials string `name:"gcp_credentials"`
|
||||||
|
WALAZStorageAccount string `name:"wal_az_storage_account"`
|
||||||
AdditionalSecretMount string `name:"additional_secret_mount"`
|
AdditionalSecretMount string `name:"additional_secret_mount"`
|
||||||
AdditionalSecretMountPath string `name:"additional_secret_mount_path" default:"/meta/credentials"`
|
AdditionalSecretMountPath string `name:"additional_secret_mount_path" default:"/meta/credentials"`
|
||||||
EnableEBSGp3Migration bool `name:"enable_ebs_gp3_migration" default:"false"`
|
EnableEBSGp3Migration bool `name:"enable_ebs_gp3_migration" default:"false"`
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package httpclient
|
package httpclient
|
||||||
|
|
||||||
//go:generate mockgen -package mocks -destination=$PWD/mocks/$GOFILE -source=$GOFILE -build_flags=-mod=vendor
|
//go:generate mockgen -package mocks -destination=../../../mocks/$GOFILE -source=$GOFILE -build_flags=-mod=vendor
|
||||||
|
|
||||||
import "net/http"
|
import "net/http"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
package volumes
|
package volumes
|
||||||
|
|
||||||
//go:generate mockgen -package mocks -destination=$PWD/mocks/$GOFILE -source=$GOFILE -build_flags=-mod=vendor
|
//go:generate mockgen -package mocks -destination=../../../mocks/$GOFILE -source=$GOFILE -build_flags=-mod=vendor
|
||||||
|
|
||||||
import v1 "k8s.io/api/core/v1"
|
import v1 "k8s.io/api/core/v1"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,3 +71,25 @@ spec:
|
||||||
"11"
|
"11"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
# Exemple of settings to make snapshot view working in the ui when using AWS
|
||||||
|
# - name: WALE_S3_ENDPOINT
|
||||||
|
# value: https+path://s3.us-east-1.amazonaws.com:443
|
||||||
|
# - name: SPILO_S3_BACKUP_PREFIX
|
||||||
|
# value: spilo/
|
||||||
|
# - name: AWS_ACCESS_KEY_ID
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: <postgres operator secret with AWS token>
|
||||||
|
# key: AWS_ACCESS_KEY_ID
|
||||||
|
# - name: AWS_SECRET_ACCESS_KEY
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: <postgres operator secret with AWS token>
|
||||||
|
# key: AWS_SECRET_ACCESS_KEY
|
||||||
|
# - name: AWS_DEFAULT_REGION
|
||||||
|
# valueFrom:
|
||||||
|
# secretKeyRef:
|
||||||
|
# name: <postgres operator secret with AWS token>
|
||||||
|
# key: AWS_DEFAULT_REGION
|
||||||
|
# - name: SPILO_S3_BACKUP_BUCKET
|
||||||
|
# value: <s3 bucket used by the operator>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
apiVersion: "networking.k8s.io/v1beta1"
|
apiVersion: "networking.k8s.io/v1"
|
||||||
kind: "Ingress"
|
kind: "Ingress"
|
||||||
metadata:
|
metadata:
|
||||||
name: "postgres-operator-ui"
|
name: "postgres-operator-ui"
|
||||||
|
|
@ -10,6 +10,10 @@ spec:
|
||||||
- host: "ui.example.org"
|
- host: "ui.example.org"
|
||||||
http:
|
http:
|
||||||
paths:
|
paths:
|
||||||
- backend:
|
- path: /
|
||||||
serviceName: "postgres-operator-ui"
|
pathType: ImplementationSpecific
|
||||||
servicePort: 80
|
backend:
|
||||||
|
service:
|
||||||
|
name: "postgres-operator-ui"
|
||||||
|
port:
|
||||||
|
number: 80
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue