Skip to content

Commit 1dd0cd9

Browse files
authored
Add Support for Azure WAL-G Backups (zalando#1537)
This commit adds support for using an Azure storage account as a backup location. It uses the existing GCS functionality as a reference for what to do, and follows the example set by GCS as closely as possible. The decision to name the cloud provider key "aws_or_gcp" is unfortunate while adding support for Azure, but I have left it alone to allow for this changeset to be backwards compatible.
1 parent 2d2ce61 commit 1dd0cd9

File tree

11 files changed

+89
-0
lines changed

11 files changed

+89
-0
lines changed

charts/postgres-operator/crds/operatorconfigurations.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,8 @@ spec:
395395
type: string
396396
wal_s3_bucket:
397397
type: string
398+
wal_az_storage_account:
399+
type: string
398400
logical_backup:
399401
type: object
400402
properties:

charts/postgres-operator/values.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ configAwsOrGcp:
268268
# GCS bucket to use for shipping WAL segments with WAL-E
269269
# wal_gs_bucket: ""
270270

271+
# Azure Storage Account to use for shipping WAL segments with WAL-G
272+
# wal_az_storage_account: ""
273+
271274
# configure K8s cron job managed by the operator
272275
configLogicalBackup:
273276
# image for pods of the logical backup job (example runs pg_dumpall)

docs/administrator.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -808,6 +808,63 @@ pod_environment_configmap: "postgres-operator-system/pod-env-overrides"
808808
...
809809
```
810810

811+
### Azure setup
812+
813+
To configure the operator on Azure these prerequisites are needed:
814+
815+
* A storage account in the same region as the Kubernetes cluster.
816+
817+
The configuration parameters that we will be using are:
818+
819+
* `pod_environment_secret`
820+
* `wal_az_storage_account`
821+
822+
1. Generate the K8s secret resource that will contain your storage account's
823+
access key. You will need a copy of this secret in every namespace you want to
824+
create postgresql clusters.
825+
826+
The latest version of WAL-G (v1.0) supports the use of a SASS token, but you'll
827+
have to make due with using the primary or secondary access token until the
828+
version of WAL-G is updated in the postgres-operator.
829+
830+
```yaml
831+
apiVersion: v1
832+
kind: Secret
833+
metadata:
834+
name: psql-backup-creds
835+
namespace: default
836+
type: Opaque
837+
stringData:
838+
AZURE_STORAGE_ACCESS_KEY: <primary or secondary access key>
839+
```
840+
841+
2. Setup pod environment configmap that instructs the operator to use WAL-G,
842+
instead of WAL-E, for backup and restore.
843+
```yml
844+
apiVersion: v1
845+
kind: ConfigMap
846+
metadata:
847+
name: pod-env-overrides
848+
namespace: postgres-operator-system
849+
data:
850+
# Any env variable used by spilo can be added
851+
USE_WALG_BACKUP: "true"
852+
USE_WALG_RESTORE: "true"
853+
CLONE_USE_WALG_RESTORE: "true"
854+
```
855+
856+
3. Setup your operator configuration values. With the `psql-backup-creds`
857+
and `pod-env-overrides` resources applied to your cluster, ensure that the operator's configuration
858+
is set up like the following:
859+
```yml
860+
...
861+
aws_or_gcp:
862+
pod_environment_secret: "pgsql-backup-creds"
863+
pod_environment_configmap: "postgres-operator-system/pod-env-overrides"
864+
wal_az_storage_account: "postgresbackupsbucket28302F2" # name of storage account to save the WAL-G logs
865+
...
866+
```
867+
811868
### Restoring physical backups
812869

813870
If cluster members have to be (re)initialized restoring physical backups

docs/reference/operator_parameters.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -557,6 +557,12 @@ yet officially supported.
557557
[service accounts](https://cloud.google.com/kubernetes-engine/docs/tutorials/authenticating-to-cloud-platform).
558558
The default is empty
559559

560+
* **wal_az_storage_account**
561+
Azure Storage Account to use for shipping WAL segments with WAL-G. The
562+
storage account must exist and be accessible by Postgres pods. Note, only the
563+
name of the storage account is required.
564+
The default is empty.
565+
560566
* **log_s3_bucket**
561567
S3 bucket to use for shipping Postgres daily logs. Works only with S3 on AWS.
562568
The bucket has to be present and accessible by Postgres pods. The default is

manifests/configmap.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ data:
129129
# team_api_role_configuration: "log_statement:all"
130130
# teams_api_url: http://fake-teams-api.default.svc.cluster.local
131131
# toleration: ""
132+
# wal_az_storage_account: ""
132133
# wal_gs_bucket: ""
133134
# wal_s3_bucket: ""
134135
watched_namespace: "*" # listen to all namespaces

manifests/operatorconfiguration.crd.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ spec:
384384
type: string
385385
log_s3_bucket:
386386
type: string
387+
wal_az_storage_account:
388+
type: string
387389
wal_gs_bucket:
388390
type: string
389391
wal_s3_bucket:

manifests/postgresql-operator-default-configuration.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@ configuration:
121121
# gcp_credentials: ""
122122
# kube_iam_role: ""
123123
# log_s3_bucket: ""
124+
# wal_az_storage_account: ""
124125
# wal_gs_bucket: ""
125126
# wal_s3_bucket: ""
126127
logical_backup:

pkg/apis/acid.zalan.do/v1/operator_configuration_type.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ type AWSGCPConfiguration struct {
132132
AWSRegion string `json:"aws_region,omitempty"`
133133
WALGSBucket string `json:"wal_gs_bucket,omitempty"`
134134
GCPCredentials string `json:"gcp_credentials,omitempty"`
135+
WALAZStorageAccount string `json:"wal_az_storage_account,omitempty"`
135136
LogS3Bucket string `json:"log_s3_bucket,omitempty"`
136137
KubeIAMRole string `json:"kube_iam_role,omitempty"`
137138
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`

pkg/cluster/k8sres.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,12 @@ func (c *Cluster) generateSpiloPodEnvVars(uid types.UID, spiloConfiguration stri
798798
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_PREFIX", Value: ""})
799799
}
800800

801+
if c.OpConfig.WALAZStorageAccount != "" {
802+
envVars = append(envVars, v1.EnvVar{Name: "AZURE_STORAGE_ACCOUNT", Value: c.OpConfig.WALAZStorageAccount})
803+
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_SUFFIX", Value: getBucketScopeSuffix(string(uid))})
804+
envVars = append(envVars, v1.EnvVar{Name: "WAL_BUCKET_SCOPE_PREFIX", Value: ""})
805+
}
806+
801807
if c.OpConfig.GCPCredentials != "" {
802808
envVars = append(envVars, v1.EnvVar{Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: c.OpConfig.GCPCredentials})
803809
}
@@ -1805,6 +1811,14 @@ func (c *Cluster) generateCloneEnvironment(description *acidv1.CloneDescription)
18051811
},
18061812
}
18071813
result = append(result, envs...)
1814+
} else if c.OpConfig.WALAZStorageAccount != "" {
1815+
envs := []v1.EnvVar{
1816+
{
1817+
Name: "CLONE_AZURE_STORAGE_ACCOUNT",
1818+
Value: c.OpConfig.WALAZStorageAccount,
1819+
},
1820+
}
1821+
result = append(result, envs...)
18081822
} else {
18091823
c.logger.Error("Cannot figure out S3 or GS bucket. Both are empty.")
18101824
}

pkg/controller/operator_config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
146146
result.KubeIAMRole = fromCRD.AWSGCP.KubeIAMRole
147147
result.WALGSBucket = fromCRD.AWSGCP.WALGSBucket
148148
result.GCPCredentials = fromCRD.AWSGCP.GCPCredentials
149+
result.WALAZStorageAccount = fromCRD.AWSGCP.WALAZStorageAccount
149150
result.AdditionalSecretMount = fromCRD.AWSGCP.AdditionalSecretMount
150151
result.AdditionalSecretMountPath = util.Coalesce(fromCRD.AWSGCP.AdditionalSecretMountPath, "/meta/credentials")
151152
result.EnableEBSGp3Migration = fromCRD.AWSGCP.EnableEBSGp3Migration

0 commit comments

Comments
 (0)