Support standby replication from GS (GCS) (#1446)
* Add support for manual gs_wal_path in standby * Remove separate standby version configuration * Remove setting standby path via cluster/uid/version Picking up the version doesn't work reliably without making changes to Spilo. It's clearer to just specify the full S3/GS bucket path. Co-authored-by: Felix Kunde <felix-kunde@gmx.de>
This commit is contained in:
		
							parent
							
								
									1ed16fadca
								
							
						
					
					
						commit
						def9e1d688
					
				|  | @ -464,11 +464,11 @@ spec: | ||||||
|                 type: integer |                 type: integer | ||||||
|               standby: |               standby: | ||||||
|                 type: object |                 type: object | ||||||
|                 required: |  | ||||||
|                   - s3_wal_path |  | ||||||
|                 properties: |                 properties: | ||||||
|                   s3_wal_path: |                   s3_wal_path: | ||||||
|                     type: string |                     type: string | ||||||
|  |                   gs_wal_path: | ||||||
|  |                     type: string | ||||||
|               teamId: |               teamId: | ||||||
|                 type: string |                 type: string | ||||||
|               tls: |               tls: | ||||||
|  |  | ||||||
|  | @ -366,12 +366,16 @@ under the `clone` top-level key and do not affect the already running cluster. | ||||||
| ## Standby cluster | ## Standby cluster | ||||||
| 
 | 
 | ||||||
| On startup, an existing `standby` top-level key creates a standby Postgres | On startup, an existing `standby` top-level key creates a standby Postgres | ||||||
| cluster streaming from a remote location. So far only streaming from a S3 WAL | cluster streaming from a remote location. So far streaming from S3 and GCS WAL | ||||||
| archive is supported. | archives is supported. | ||||||
| 
 | 
 | ||||||
| * **s3_wal_path** | * **s3_wal_path** | ||||||
|   the url to S3 bucket containing the WAL archive of the remote primary. |   the url to S3 bucket containing the WAL archive of the remote primary. | ||||||
|   Required when the `standby` section is present. |   Optional, but `s3_wal_path`  or `gs_wal_path` is required. | ||||||
|  | 
 | ||||||
|  | * **gs_wal_path** | ||||||
|  |   the url to GS bucket containing the WAL archive of the remote primary. | ||||||
|  |   Optional, but `s3_wal_path`  or `gs_wal_path` is required. | ||||||
| 
 | 
 | ||||||
| ## Volume properties | ## Volume properties | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
							
								
								
									
										10
									
								
								docs/user.md
								
								
								
								
							
							
						
						
									
										10
									
								
								docs/user.md
								
								
								
								
							|  | @ -798,8 +798,8 @@ different location than its source database. Unlike cloning, the PostgreSQL | ||||||
| version between source and target cluster has to be the same. | version between source and target cluster has to be the same. | ||||||
| 
 | 
 | ||||||
| To start a cluster as standby, add the following `standby` section in the YAML | To start a cluster as standby, add the following `standby` section in the YAML | ||||||
| file and specify the S3 bucket path. An empty path will result in an error and | file. Specify the S3/GS bucket path. Omitting both settings will result in an error | ||||||
| no statefulset will be created. | and no statefulset will be created. | ||||||
| 
 | 
 | ||||||
| ```yaml | ```yaml | ||||||
| spec: | spec: | ||||||
|  | @ -807,6 +807,12 @@ spec: | ||||||
|     s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>" |     s3_wal_path: "s3://<bucketname>/spilo/<source_db_cluster>/<UID>/wal/<PGVERSION>" | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ```yaml | ||||||
|  | spec: | ||||||
|  |   standby: | ||||||
|  |     gs_wal_path: "gs://<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 | ||||||
| master. Thus, it is recommended to deploy standby clusters with only [one pod](https://github.com/zalando/postgres-operator/blob/master/manifests/standby-manifest.yaml#L10). | master. Thus, it is recommended to deploy standby clusters with only [one pod](https://github.com/zalando/postgres-operator/blob/master/manifests/standby-manifest.yaml#L10). | ||||||
| You can raise the instance count when detaching. Note, that the same pod role | You can raise the instance count when detaching. Note, that the same pod role | ||||||
|  |  | ||||||
|  | @ -649,12 +649,14 @@ var PostgresCRDResourceValidation = apiextv1.CustomResourceValidation{ | ||||||
| 						Type: "integer", | 						Type: "integer", | ||||||
| 					}, | 					}, | ||||||
| 					"standby": { | 					"standby": { | ||||||
| 						Type:     "object", | 						Type: "object", | ||||||
| 						Required: []string{"s3_wal_path"}, |  | ||||||
| 						Properties: map[string]apiextv1.JSONSchemaProps{ | 						Properties: map[string]apiextv1.JSONSchemaProps{ | ||||||
| 							"s3_wal_path": { | 							"s3_wal_path": { | ||||||
| 								Type: "string", | 								Type: "string", | ||||||
| 							}, | 							}, | ||||||
|  | 							"gs_wal_path": { | ||||||
|  | 								Type: "string", | ||||||
|  | 							}, | ||||||
| 						}, | 						}, | ||||||
| 					}, | 					}, | ||||||
| 					"teamId": { | 					"teamId": { | ||||||
|  |  | ||||||
|  | @ -166,6 +166,7 @@ type Patroni struct { | ||||||
| // StandbyDescription contains s3 wal path
 | // StandbyDescription contains s3 wal path
 | ||||||
| type StandbyDescription struct { | type StandbyDescription struct { | ||||||
| 	S3WalPath string `json:"s3_wal_path,omitempty"` | 	S3WalPath string `json:"s3_wal_path,omitempty"` | ||||||
|  | 	GSWalPath string `json:"gs_wal_path,omitempty"` | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TLSDescription specs TLS properties
 | // TLSDescription specs TLS properties
 | ||||||
|  |  | ||||||
|  | @ -1058,8 +1058,9 @@ func (c *Cluster) generateStatefulSet(spec *acidv1.PostgresSpec) (*appsv1.Statef | ||||||
| 	sort.Slice(customPodEnvVarsList, | 	sort.Slice(customPodEnvVarsList, | ||||||
| 		func(i, j int) bool { return customPodEnvVarsList[i].Name < customPodEnvVarsList[j].Name }) | 		func(i, j int) bool { return customPodEnvVarsList[i].Name < customPodEnvVarsList[j].Name }) | ||||||
| 
 | 
 | ||||||
| 	if spec.StandbyCluster != nil && spec.StandbyCluster.S3WalPath == "" { | 	if spec.StandbyCluster != nil && spec.StandbyCluster.S3WalPath == "" && | ||||||
| 		return nil, fmt.Errorf("s3_wal_path is empty for standby cluster") | 		spec.StandbyCluster.GSWalPath == "" { | ||||||
|  | 		return nil, fmt.Errorf("one of s3_wal_path or gs_wal_path must be set for standby cluster") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// backward compatible check for InitContainers
 | 	// backward compatible check for InitContainers
 | ||||||
|  | @ -1874,17 +1875,36 @@ func (c *Cluster) generateCloneEnvironment(description *acidv1.CloneDescription) | ||||||
| func (c *Cluster) generateStandbyEnvironment(description *acidv1.StandbyDescription) []v1.EnvVar { | func (c *Cluster) generateStandbyEnvironment(description *acidv1.StandbyDescription) []v1.EnvVar { | ||||||
| 	result := make([]v1.EnvVar, 0) | 	result := make([]v1.EnvVar, 0) | ||||||
| 
 | 
 | ||||||
| 	if description.S3WalPath == "" { | 	if description.S3WalPath == "" && description.GSWalPath == "" { | ||||||
| 		return nil | 		return nil | ||||||
| 	} | 	} | ||||||
| 	// standby with S3, find out the bucket to setup standby
 |  | ||||||
| 	msg := "Standby from S3 bucket using custom parsed S3WalPath from the manifest %s " |  | ||||||
| 	c.logger.Infof(msg, description.S3WalPath) |  | ||||||
| 
 | 
 | ||||||
| 	result = append(result, v1.EnvVar{ | 	if description.S3WalPath != "" { | ||||||
| 		Name:  "STANDBY_WALE_S3_PREFIX", | 		// standby with S3, find out the bucket to setup standby
 | ||||||
| 		Value: description.S3WalPath, | 		msg := "Standby from S3 bucket using custom parsed S3WalPath from the manifest %s " | ||||||
| 	}) | 		c.logger.Infof(msg, description.S3WalPath) | ||||||
|  | 
 | ||||||
|  | 		result = append(result, v1.EnvVar{ | ||||||
|  | 			Name:  "STANDBY_WALE_S3_PREFIX", | ||||||
|  | 			Value: description.S3WalPath, | ||||||
|  | 		}) | ||||||
|  | 	} else if description.GSWalPath != "" { | ||||||
|  | 		msg := "Standby from GS bucket using custom parsed GSWalPath from the manifest %s " | ||||||
|  | 		c.logger.Infof(msg, description.GSWalPath) | ||||||
|  | 
 | ||||||
|  | 		envs := []v1.EnvVar{ | ||||||
|  | 			{ | ||||||
|  | 				Name:  "STANDBY_WALE_GS_PREFIX", | ||||||
|  | 				Value: description.GSWalPath, | ||||||
|  | 			}, | ||||||
|  | 			{ | ||||||
|  | 				Name:  "STANDBY_GOOGLE_APPLICATION_CREDENTIALS", | ||||||
|  | 				Value: c.OpConfig.GCPCredentials, | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 		result = append(result, envs...) | ||||||
|  | 
 | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	result = append(result, v1.EnvVar{Name: "STANDBY_METHOD", Value: "STANDBY_WITH_WALE"}) | 	result = append(result, v1.EnvVar{Name: "STANDBY_METHOD", Value: "STANDBY_WITH_WALE"}) | ||||||
| 	result = append(result, v1.EnvVar{Name: "STANDBY_WAL_BUCKET_SCOPE_PREFIX", Value: ""}) | 	result = append(result, v1.EnvVar{Name: "STANDBY_WAL_BUCKET_SCOPE_PREFIX", Value: ""}) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue