Skip to content

Commit eecd131

Browse files
authored
refactor spilo env var generation (zalando#1848)
* refactor spilo env generation * enhance docs on env vars * add unit test for appendEnvVar
1 parent 483bf62 commit eecd131

File tree

7 files changed

+1469
-1148
lines changed

7 files changed

+1469
-1148
lines changed

docs/administrator.md

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -601,15 +601,39 @@ spec:
601601

602602
## Custom Pod Environment Variables
603603

604-
It is possible to configure a ConfigMap as well as a Secret which are used by
605-
the Postgres pods as an additional provider for environment variables. One use
606-
case is a customized Spilo image configured by extra environment variables.
607-
Another case could be to provide custom cloud provider or backup settings.
608-
609-
In general the Operator will give preference to the globally configured
610-
variables, to not have the custom ones interfere with core functionality.
611-
Variables with the 'WAL_' and 'LOG_' prefix can be overwritten though, to
612-
allow backup and log shipping to be specified differently.
604+
The operator will assign a set of environment variables to the database pods
605+
that cannot be overridden to guarantee core functionality. Only variables with
606+
'WAL_' and 'LOG_' prefixes can be customized to allow for backup and log
607+
shipping to be specified differently. There are three ways to specify extra
608+
environment variables (or override existing ones) for database pods:
609+
610+
* [Via ConfigMap](#via-configmap)
611+
* [Via Secret](#via-secret)
612+
* [Via Postgres Cluster Manifest](#via-postgres-cluster-manifest)
613+
614+
The first two options must be referenced from the operator configuration
615+
making them global settings for all Postgres cluster the operator watches.
616+
One use case is a customized Spilo image that must be configured by extra
617+
environment variables. Another case could be to provide custom cloud
618+
provider or backup settings.
619+
620+
The last options allows for specifying environment variables individual to
621+
every cluster via the `env` section in the manifest. For example, if you use
622+
individual backup locations for each of your clusters. Or you want to disable
623+
WAL archiving for a certain cluster by setting `WAL_S3_BUCKET`, `WAL_GS_BUCKET`
624+
or `AZURE_STORAGE_ACCOUNT` to an empty string.
625+
626+
The operator will give precedence to environment variables in the following
627+
order (e.g. a variable defined in 4. overrides a variable with the same name
628+
in 5.):
629+
630+
1. Assigned by the operator
631+
2. Clone section (with WAL settings from operator config when `s3_wal_path` is empty)
632+
3. Standby section
633+
4. `env` section in cluster manifest
634+
5. Pod environment secret via operator config
635+
6. Pod environment config map via operator config
636+
7. WAL and logical backup settings from operator config
613637

614638
### Via ConfigMap
615639

@@ -706,7 +730,7 @@ data:
706730
The key-value pairs of the Secret are all accessible as environment variables
707731
to the Postgres StatefulSet/pods.
708732

709-
### For individual cluster
733+
### Via Postgres Cluster Manifest
710734

711735
It is possible to define environment variables directly in the Postgres cluster
712736
manifest to configure it individually. The variables must be listed under the
@@ -951,6 +975,10 @@ When the `AWS_REGION` is set, `AWS_ENDPOINT` and `WALE_S3_ENDPOINT` are
951975
generated automatically. `WALG_S3_PREFIX` is identical to `WALE_S3_PREFIX`.
952976
`SCOPE` is the Postgres cluster name.
953977

978+
:warning: If both `AWS_REGION` and `AWS_ENDPOINT` or `WALE_S3_ENDPOINT` are
979+
defined backups with WAL-E will fail. You can fix it by switching to WAL-G
980+
with `USE_WALG_BACKUP: "true"`.
981+
954982
### Google Cloud Platform setup
955983

956984
To configure the operator on GCP these prerequisites that are needed:

docs/reference/operator_parameters.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -645,7 +645,10 @@ yet officially supported.
645645
empty.
646646

647647
* **aws_region**
648-
AWS region used to store EBS volumes. The default is `eu-central-1`.
648+
AWS region used to store EBS volumes. The default is `eu-central-1`. Note,
649+
this option is not meant for specifying the AWS region for backups and
650+
restore, since it can be separate from the EBS region. You have to define
651+
AWS_REGION as a [custom environment variable](../administrator.md#custom-pod-environment-variables).
649652

650653
* **additional_secret_mount**
651654
Additional Secret (aws or gcp credentials) to mount in the pod.

docs/user.md

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -766,15 +766,15 @@ spec:
766766
uid: "efd12e58-5786-11e8-b5a7-06148230260c"
767767
cluster: "acid-minimal-cluster"
768768
timestamp: "2017-12-19T12:40:33+01:00"
769-
s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
770769
```
771770

772771
Here `cluster` is a name of a source cluster that is going to be cloned. A new
773772
cluster will be cloned from S3, using the latest backup before the `timestamp`.
774-
Note, that a time zone is required for `timestamp` in the format of +00:00 which
775-
is UTC. You can specify the `s3_wal_path` of the source cluster or let the
776-
operator try to find it based on the configured `wal_[s3|gs]_bucket` and the
777-
specified `uid`. You can find the UID of the source cluster in its metadata:
773+
Note, a time zone is required for `timestamp` in the format of `+00:00` (UTC).
774+
775+
The operator will try to find the WAL location based on the configured
776+
`wal_[s3|gs]_bucket` or `wal_az_storage_account` and the specified `uid`.
777+
You can find the UID of the source cluster in its metadata:
778778

779779
```yaml
780780
apiVersion: acid.zalan.do/v1
@@ -784,6 +784,14 @@ metadata:
784784
uid: efd12e58-5786-11e8-b5a7-06148230260c
785785
```
786786

787+
If your source cluster uses a WAL location different from the global
788+
configuration you can specify the full path under `s3_wal_path`. For
789+
[Google Cloud Platform](administrator.md#google-cloud-platform-setup)
790+
or [Azure](administrator.md#azure-setup)
791+
it can only be set globally with [custom Pod environment variables](administrator.md#custom-pod-environment-variables)
792+
or locally in the Postgres manifest's [`env`](administrator.md#via-postgres-cluster-manifest) section.
793+
794+
787795
For non AWS S3 following settings can be set to support cloning from other S3
788796
implementations:
789797

@@ -793,6 +801,7 @@ spec:
793801
uid: "efd12e58-5786-11e8-b5a7-06148230260c"
794802
cluster: "acid-minimal-cluster"
795803
timestamp: "2017-12-19T12:40:33+01:00"
804+
s3_wal_path: "s3://custom/path/to/bucket"
796805
s3_endpoint: https://s3.acme.org
797806
s3_access_key_id: 0123456789abcdef0123456789abcdef
798807
s3_secret_access_key: 0123456789abcdef0123456789abcdef
@@ -864,22 +873,28 @@ the PostgreSQL version between source and target cluster has to be the same.
864873

865874
To start a cluster as standby, add the following `standby` section in the YAML
866875
file. You can stream changes from archived WAL files (AWS S3 or Google Cloud
867-
Storage) or from a remote primary where you specify the host address and port.
868-
If you leave out the port, Patroni will use `"5432"`. Only one option can be
869-
specfied in the manifest:
876+
Storage) or from a remote primary. Only one option can be specfied in the
877+
manifest:
870878

871879
```yaml
872880
spec:
873881
standby:
874882
s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
875883
```
876884

885+
For GCS, you have to define STANDBY_GOOGLE_APPLICATION_CREDENTIALS as a
886+
[custom pod environment variable](administrator.md#custom-pod-environment-variables).
887+
It is not set from the config to allow for overridding.
888+
877889
```yaml
878890
spec:
879891
standby:
880892
gs_wal_path: "gs://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>"
881893
```
882894

895+
For a remote primary you specify the host address and optionally the port.
896+
If you leave out the port Patroni will use `"5432"`.
897+
883898
```yaml
884899
spec:
885900
standby:

pkg/cluster/cluster.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1318,7 +1318,7 @@ func (c *Cluster) initAdditionalOwnerRoles() {
13181318
}
13191319
}
13201320

1321-
if len(memberOf) > 1 {
1321+
if len(memberOf) > 0 {
13221322
namespace := c.Namespace
13231323
additionalOwnerPgUser := spec.PgUser{
13241324
Origin: spec.RoleOriginSpilo,

pkg/cluster/cluster_test.go

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import (
2626
const (
2727
superUserName = "postgres"
2828
replicationUserName = "standby"
29+
exampleSpiloConfig = `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_connections":"100","max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`
30+
spiloConfigDiff = `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`
2931
)
3032

3133
var logger = logrus.New().WithField("test", "cluster")
@@ -957,7 +959,7 @@ func TestCompareEnv(t *testing.T) {
957959
},
958960
{
959961
Name: "SPILO_CONFIGURATION",
960-
Value: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_connections":"100","max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`,
962+
Value: exampleSpiloConfig,
961963
},
962964
},
963965
ExpectedResult: true,
@@ -978,7 +980,7 @@ func TestCompareEnv(t *testing.T) {
978980
},
979981
{
980982
Name: "SPILO_CONFIGURATION",
981-
Value: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`,
983+
Value: spiloConfigDiff,
982984
},
983985
},
984986
ExpectedResult: true,
@@ -999,7 +1001,7 @@ func TestCompareEnv(t *testing.T) {
9991001
},
10001002
{
10011003
Name: "SPILO_CONFIGURATION",
1002-
Value: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`,
1004+
Value: exampleSpiloConfig,
10031005
},
10041006
},
10051007
ExpectedResult: false,
@@ -1024,7 +1026,7 @@ func TestCompareEnv(t *testing.T) {
10241026
},
10251027
{
10261028
Name: "SPILO_CONFIGURATION",
1027-
Value: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_connections":"100","max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`,
1029+
Value: exampleSpiloConfig,
10281030
},
10291031
},
10301032
ExpectedResult: false,
@@ -1041,7 +1043,7 @@ func TestCompareEnv(t *testing.T) {
10411043
},
10421044
{
10431045
Name: "SPILO_CONFIGURATION",
1044-
Value: `{"postgresql":{"bin_dir":"/usr/lib/postgresql/12/bin","parameters":{"autovacuum_analyze_scale_factor":"0.1"},"pg_hba":["hostssl all all 0.0.0.0/0 md5","host all all 0.0.0.0/0 md5"]},"bootstrap":{"initdb":[{"auth-host":"md5"},{"auth-local":"trust"},"data-checksums",{"encoding":"UTF8"},{"locale":"en_US.UTF-8"}],"users":{"test":{"password":"","options":["CREATEDB","NOLOGIN"]}},"dcs":{"ttl":30,"loop_wait":10,"retry_timeout":10,"maximum_lag_on_failover":33554432,"postgresql":{"parameters":{"max_connections":"100","max_locks_per_transaction":"64","max_worker_processes":"4"}}}}}`,
1046+
Value: exampleSpiloConfig,
10451047
},
10461048
},
10471049
ExpectedResult: false,

0 commit comments

Comments
 (0)