From 46f39ebe297783451fb152b0f4d4c282c5a94329 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Tue, 19 Mar 2019 11:06:57 +0600 Subject: [PATCH 01/25] Updated `continuous archiving` doc --- .../guides/postgres/snapshot/continuous_archiving.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index e8e5c8adc..46aaa7ca6 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -13,7 +13,7 @@ section_menu_id: guides # Continuous Archiving with wal-g -KubeDB PostgreSQL also supports continuous archiving using [wal-g ](https://github.com/wal-g/wal-g). Now **wal-g** supports _S3_ and _GCP_ as cloud storage. +KubeDB PostgreSQL also supports continuous archiving using [wal-g ](https://github.com/wal-g/wal-g). Now **wal-g** supports _S3_, _GCS, Azure, and Swift_ as cloud storage. ## Before You Begin @@ -65,8 +65,12 @@ Here, - `storage.s3.bucket` points to the bucket name used to store continuous archiving data. - `storage.gcs` points to GCS storage configuration. - `storage.gcs.bucket` points to the bucket name used to store continuous archiving data. + - `storage.azure` points to Azure storage configuration. + - `storage.azure.container` points to the container/bucket name used to store continuous archiving data. + - `storage.swift` points to Swift storage configuration. + - `storage.swift.container` points to the container/bucket name used to store continuous archiving data. -User can use either s3 or gcs. In this tutorial, s3 is used for wal-g archiving. `gcs` is similar to this tutorial. Follow [this link](/docs/concepts/snapshot/#google-cloud-storage-gcs) to know how to create secret for `gcs` storage. +User can use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. In this tutorial, `s3` is used for wal-g archiving. `gcs`, `azure`, and `swift` are also similar to this tutorial. Please note that `s3`, and `gcs` use `storage.bucket`, whereas `azure`, and `swift` use `storage.container` to point to the base directory of their respective cloud storages. To create secret for these storages, follow [this link](/docs/concepts/snapshot/#google-cloud-storage-gcs) for `gcs`, [this link](/docs/concepts/snapshot/#microsoft-azure-storage) for `azure`, and [this link]( [this link](/docs/concepts/snapshot/#microsoft-azure-storage)) for `swift`. **What is this Continuous Archiving** @@ -126,7 +130,7 @@ type: Opaque **Archiver Storage Backend** -**wal-g** supports both _S3_ and __GCS__ cloud providers. +**wal-g** supports _S3_, _GCS_, __Azure__, and __Swift__ as cloud providers. To configure s3 backend, following parameters are available: @@ -147,7 +151,7 @@ When database is ready, **wal-g** takes a base backup and uploads it to cloud st Archived data is stored in a folder called `{bucket}/{prefix}/kubedb/{namespace}/{postgres-name}/archive/`. -you can see continuous archiving data stored in S3 bucket. +You can see continuous archiving data stored in S3 bucket.

From 0ab80e41f2ebe00ae5f0007c844c36bcdf0f497d Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Tue, 19 Mar 2019 11:34:17 +0600 Subject: [PATCH 02/25] Updated `initialization fron WAL source` doc Signed-off-by: iamrz1 --- .../guides/postgres/initialization/wal_source.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/docs/guides/postgres/initialization/wal_source.md b/docs/guides/postgres/initialization/wal_source.md index 5da0767fa..f62f9b790 100644 --- a/docs/guides/postgres/initialization/wal_source.md +++ b/docs/guides/postgres/initialization/wal_source.md @@ -33,7 +33,7 @@ namespace/demo created ## Prepare WAL Archive -We need a WAL archive to perform initialization. If you already don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). +We need a WAL archive to perform initialization. If you don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). Let's populate the database so that we can verify that the initialized database has the same data. We will `exec` into the database pod and use `psql` command-line tool to create a table. @@ -128,16 +128,22 @@ Here, - `spec.init.postgresWAL` specifies storage information that will be used by `wal-g` - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `s3` points to s3 storage configuration. + - `s3` points to S3 storage configuration. - `s3.bucket` points to the bucket name where archived WAL data is stored. - `s3.prefix` points to the path of archived WAL data. - `gcs` points to GCS storage configuration. - `gcs.bucket` points to the bucket name where archived WAL data is stored. - - `gcs.prefix` points to the path of archived WAL data.. + - `gcs.prefix` points to the path of archived WAL data. + - `azure` points to Azure storage configuration. + - `azure.container` points to the container/bucket name where archived WAL data is stored. + - `azure.prefix` points to the path of archived WAL data. + - `swift` points to Swift storage configuration. + - `swift.container` points to the container/bucket name where archived WAL data is stored. + - `swift.prefix` points to the path of archived WAL data. -User can use either s3 or gcs WAL archiver for init. +User can use any one of `s3`,` gcs`, `azure`, or `swift` WAL archiver for init. -**wal-g** receives archived WAL data from a folder called `/kubedb/{namespace}/{postgres-name}/archive/`. +**wal-g** receives archived WAL data from a directory inside the bucket/container called `/kubedb/{namespace}/{postgres-name}/archive/`. Here, `{namespace}` & `{postgres-name}` indicates Postgres object whose WAL archived data will be replayed. From 6af76cccf8546c2a51cbc86b528ea6ca030ae69b Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 10:12:21 +0600 Subject: [PATCH 03/25] Removed extra [this link] --- docs/guides/postgres/snapshot/continuous_archiving.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index 46aaa7ca6..a9d7899a7 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -70,7 +70,7 @@ Here, - `storage.swift` points to Swift storage configuration. - `storage.swift.container` points to the container/bucket name used to store continuous archiving data. -User can use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. In this tutorial, `s3` is used for wal-g archiving. `gcs`, `azure`, and `swift` are also similar to this tutorial. Please note that `s3`, and `gcs` use `storage.bucket`, whereas `azure`, and `swift` use `storage.container` to point to the base directory of their respective cloud storages. To create secret for these storages, follow [this link](/docs/concepts/snapshot/#google-cloud-storage-gcs) for `gcs`, [this link](/docs/concepts/snapshot/#microsoft-azure-storage) for `azure`, and [this link]( [this link](/docs/concepts/snapshot/#microsoft-azure-storage)) for `swift`. +User can use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. In this tutorial, `s3` is used for wal-g archiving. `gcs`, `azure`, and `swift` are also similar to this tutorial. Please note that `s3`, and `gcs` use `storage.bucket`, whereas `azure`, and `swift` use `storage.container` to point to the base directory of their respective cloud storages. To create secret for these storages, follow [this link](/docs/concepts/snapshot/#google-cloud-storage-gcs) for `gcs`, [this link](/docs/concepts/snapshot/#microsoft-azure-storage) for `azure`, and [this link](/docs/concepts/snapshot/#microsoft-azure-storage) for `swift`. **What is this Continuous Archiving** From 573ebbb2ffc3c4a1eecb558d09889373f48f2757 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 12:02:57 +0600 Subject: [PATCH 04/25] New format for archiving wal files to S3 --- .../postgres/snapshot/archiving_to_s3.md | 132 ++++++++++++++ .../postgres/snapshot/continuous_archiving.md | 162 ++---------------- 2 files changed, 144 insertions(+), 150 deletions(-) create mode 100644 docs/guides/postgres/snapshot/archiving_to_s3.md diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md new file mode 100644 index 000000000..c6aed2f37 --- /dev/null +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -0,0 +1,132 @@ +## Archiving to S3: + +**WAL-G** is used to handle continuous archiving mechanism. For this we need storage Secret and need to provide storage backend information. + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +Below is the Postgres object created with Continuous Archiving to backup WAL files to Amazon S3. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres + namespace: demo +spec: + version: "9.6-v2" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + archiver: + storage: + storageSecretName: s3-secret + s3: + bucket: kubedb +``` + +Here, + +- `spec.archiver.storage` specifies storage information that will be used by `WAL-G` + - `storage.storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `storage.s3` points to s3 storage configuration. + - `storage.s3.bucket` points to the bucket name used to store continuous archiving data. + +**Archiver Storage Secret** + +Storage Secret should contain credentials that will be used to access storage destination. + +Storage Secret for **WAL-G** is needed with the following 2 keys: + +| Key | Description | +| ----------------------- | ----------------------------------------- | +| `AWS_ACCESS_KEY_ID` | `Required`. AWS / Minio access key ID | +| `AWS_SECRET_ACCESS_KEY` | `Required`. AWS / Minio secret access key | + +```console +$ echo -n '' > AWS_ACCESS_KEY_ID +$ echo -n '' > AWS_SECRET_ACCESS_KEY +$ kubectl create secret -n demo generic s3-secret \ + --from-file=./AWS_ACCESS_KEY_ID \ + --from-file=./AWS_SECRET_ACCESS_KEY +secret "s3-secret" created +``` + +```yaml +$ kubectl get secret -n demo s3-secret -o yaml +apiVersion: v1 +data: + AWS_ACCESS_KEY_ID: PHlvdXItYXdzLWFjY2Vzcy1rZXktaWQtaGVyZT4= + AWS_SECRET_ACCESS_KEY: PHlvdXItYXdzLXNlY3JldC1hY2Nlc3Mta2V5LWhlcmU+ +kind: Secret +metadata: + creationTimestamp: 2018-02-06T09:12:37Z + name: s3-secret + namespace: demo + resourceVersion: "59225" + selfLink: /api/v1/namespaces/demo/secrets/s3-secret + uid: dfbe6b06-0b1d-11e8-9fb9-42010a800064 +type: Opaque +``` + +**Archiver Storage Backend** + +To configure s3 backend, following parameters are available: + +| Parameter | Description | +| ------------------ | ------------------------------------------------------------ | +| `spec.s3.endpoint` | `Required`. For S3, use `s3.amazonaws.com` | +| `spec.s3.bucket` | `Required`. Name of Bucket | +| `spec.s3.prefix` | `Optional`. Path prefix into bucket where snapshot will be store | + +Now create this Postgres object with Continuous Archiving support. + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres.yaml +postgres.kubedb.com/wal-postgres created +``` + +When database is ready, **WAL-G** takes a base backup and uploads it to the cloud storage defined by storage backend. + +Archived data is stored in a folder called `{bucket}/{prefix}/kubedb/{namespace}/{postgres-name}/archive/`. + +You can see continuous archiving data stored in S3 bucket. + +

+ + continuous-archiving + +

+ +From the above image, you can see that the archived data is stored in a folder `kubedb/kubedb/demo/wal-postgres/archive`. + +## Termination Policy + +If termination policy of this `wal-postgres` is set to `WipeOut` or, If `Spec.WipeOut` of dormant database is set to `true`, then the data in cloud backend will be deleted. + +The data will be intact in other scenarios. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/wal-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/wal-postgres + +kubectl delete -n demo secret/s3-secret +kubectl delete ns demo +``` + +## Next Steps + +- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. \ No newline at end of file diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index a9d7899a7..3d46a49a0 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -11,75 +11,16 @@ section_menu_id: guides --- > New to KubeDB? Please start [here](/docs/concepts/README.md). -# Continuous Archiving with wal-g +# Continuous Archiving with WAL-G -KubeDB PostgreSQL also supports continuous archiving using [wal-g ](https://github.com/wal-g/wal-g). Now **wal-g** supports _S3_, _GCS, Azure, and Swift_ as cloud storage. - -## Before You Begin - -At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). - -Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). - -To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. - -```console -$ kubectl create ns demo -namespace/demo created -``` - -> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). - -## Create PostgreSQL with Continuous Archiving - -Below is the Postgres object created with Continuous Archiving support. - -```yaml -apiVersion: kubedb.com/v1alpha1 -kind: Postgres -metadata: - name: wal-postgres - namespace: demo -spec: - version: "9.6-v2" - replicas: 2 - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - archiver: - storage: - storageSecretName: s3-secret - s3: - bucket: kubedb -``` - -Here, - -- `spec.archiver.storage` specifies storage information that will be used by `wal-g` - - `storage.storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `storage.s3` points to s3 storage configuration. - - `storage.s3.bucket` points to the bucket name used to store continuous archiving data. - - `storage.gcs` points to GCS storage configuration. - - `storage.gcs.bucket` points to the bucket name used to store continuous archiving data. - - `storage.azure` points to Azure storage configuration. - - `storage.azure.container` points to the container/bucket name used to store continuous archiving data. - - `storage.swift` points to Swift storage configuration. - - `storage.swift.container` points to the container/bucket name used to store continuous archiving data. - -User can use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. In this tutorial, `s3` is used for wal-g archiving. `gcs`, `azure`, and `swift` are also similar to this tutorial. Please note that `s3`, and `gcs` use `storage.bucket`, whereas `azure`, and `swift` use `storage.container` to point to the base directory of their respective cloud storages. To create secret for these storages, follow [this link](/docs/concepts/snapshot/#google-cloud-storage-gcs) for `gcs`, [this link](/docs/concepts/snapshot/#microsoft-azure-storage) for `azure`, and [this link](/docs/concepts/snapshot/#microsoft-azure-storage) for `swift`. +KubeDB also supports continuous archiving of PostgreSQL using [WAL-G ](https://github.com/wal-g/wal-g). Users can use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. **What is this Continuous Archiving** -PostgreSQL maintains a write ahead log (WAL) in the `pg_xlog/` subdirectory of the cluster's data directory. The existence of the log makes it possible to use a third strategy for backing up databases and if recovery is needed, restore from the backed-up WAL files to bring the system to a current state. +PostgreSQL maintains a write ahead log (WAL) in the `pg_xlog/` subdirectory of the cluster's data directory. The existence of the log makes it possible to use a third strategy for backing up databases and if recovery is needed, restore from the backed-up WAL files to bring the system back to last known state. **Continuous Archiving Setup** -KubeDB PostgreSQL supports [wal-g](https://github.com/wal-g/wal-g) for this continuous archiving. - Following additional parameters are set in `postgresql.conf` for *primary* server ```console @@ -87,98 +28,19 @@ archive_command = 'wal-g wal-push %p' archive_timeout = 60 ``` -Here, these commands are used to push and pull WAL files respectively from cloud. - -**wal-g** is used to handle this continuous archiving mechanism. For this we need storage Secret and need to provide storage backend information. - -**Archiver Storage Secret** - -Storage Secret should contain credentials that will be used to access storage destination. - -Storage Secret for **wal-g** is needed with following 2 keys: - -| Key | Description | -| ----------------------- | ----------------------------------------- | -| `AWS_ACCESS_KEY_ID` | `Required`. AWS / Minio access key ID | -| `AWS_SECRET_ACCESS_KEY` | `Required`. AWS / Minio secret access key | - -```console -$ echo -n '' > AWS_ACCESS_KEY_ID -$ echo -n '' > AWS_SECRET_ACCESS_KEY -$ kubectl create secret -n demo generic s3-secret \ - --from-file=./AWS_ACCESS_KEY_ID \ - --from-file=./AWS_SECRET_ACCESS_KEY -secret "s3-secret" created -``` - -```yaml -$ kubectl get secret -n demo s3-secret -o yaml -apiVersion: v1 -data: - AWS_ACCESS_KEY_ID: PHlvdXItYXdzLWFjY2Vzcy1rZXktaWQtaGVyZT4= - AWS_SECRET_ACCESS_KEY: PHlvdXItYXdzLXNlY3JldC1hY2Nlc3Mta2V5LWhlcmU+ -kind: Secret -metadata: - creationTimestamp: 2018-02-06T09:12:37Z - name: s3-secret - namespace: demo - resourceVersion: "59225" - selfLink: /api/v1/namespaces/demo/secrets/s3-secret - uid: dfbe6b06-0b1d-11e8-9fb9-42010a800064 -type: Opaque -``` - -**Archiver Storage Backend** - -**wal-g** supports _S3_, _GCS_, __Azure__, and __Swift__ as cloud providers. - -To configure s3 backend, following parameters are available: - -| Parameter | Description | -| ------------------ | ---------------------------------------------------------------- | -| `spec.s3.endpoint` | `Required`. For S3, use `s3.amazonaws.com` | -| `spec.s3.bucket` | `Required`. Name of Bucket | -| `spec.s3.prefix` | `Optional`. Path prefix into bucket where snapshot will be store | - -Now create this Postgres object with Continuous Archiving support. - -```console -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres.yaml -postgres.kubedb.com/wal-postgres created -``` - -When database is ready, **wal-g** takes a base backup and uploads it to cloud storage defined by storage backend. +Here, these commands are used to push files to the cloud. -Archived data is stored in a folder called `{bucket}/{prefix}/kubedb/{namespace}/{postgres-name}/archive/`. - -You can see continuous archiving data stored in S3 bucket. - -

- - continuous-archiving - -

- -From the above image, you can see that the archived data is stored in a folder `kubedb/kubedb/demo/wal-postgres/archive`. - -## Termination Policy - -If termination policy of this `wal-postgres` is set to `WipeOut` or, If `Spec.WipeOut` of dormant database is set to `true`, then the data in cloud backend will be deleted. - -Other than that, the data will be intact in other scenarios. - -## Cleaning up +## Before You Begin -To cleanup the Kubernetes resources created by this tutorial, run: +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). -```console -kubectl patch -n demo pg/wal-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" -kubectl delete -n demo pg/wal-postgres +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). -kubectl delete -n demo secret/s3-secret -kubectl delete ns demo -``` +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). ## Next Steps -- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. +- Learn about archiving to [Amazon S3](/docs/guides/postgres/snapshot/archiving_to_s3.md). +- Learn about archiving to [Google Cloud Storage](/docs/guides/postgres/snapshot/archiving_to_gcs.md). +- Learn about archiving to [Azure Storage](/docs/guides/postgres/snapshot/archiving_to_azure.md). +- Learn about archiving to [OpenStack Object Storage (Swift)](/docs/guides/postgres/snapshot/archiving_to_swift.md). From 522982c82cc2d4a36342211bee2a8acc3cff391e Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 12:16:32 +0600 Subject: [PATCH 05/25] Added official postgres doc on continuous archiving --- docs/guides/postgres/snapshot/continuous_archiving.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index 3d46a49a0..48ca30b06 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -13,12 +13,14 @@ section_menu_id: guides # Continuous Archiving with WAL-G -KubeDB also supports continuous archiving of PostgreSQL using [WAL-G ](https://github.com/wal-g/wal-g). Users can use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. +KubeDB also supports continuous archiving of PostgreSQL using [WAL-G ](https://github.com/wal-g/wal-g). Users can now use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. **What is this Continuous Archiving** PostgreSQL maintains a write ahead log (WAL) in the `pg_xlog/` subdirectory of the cluster's data directory. The existence of the log makes it possible to use a third strategy for backing up databases and if recovery is needed, restore from the backed-up WAL files to bring the system back to last known state. +To know more about continuous archiving, please refer to the [ofiicial postgres document](https://www.postgresql.org/docs/10/continuous-archiving.html) on this topic. + **Continuous Archiving Setup** Following additional parameters are set in `postgresql.conf` for *primary* server From 7d3113ff385b7e5c5c9f191a8f5dfd8065a52a9d Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 12:47:35 +0600 Subject: [PATCH 06/25] Updated S3 doc --- docs/guides/postgres/snapshot/archiving_to_s3.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index c6aed2f37..3e325f6de 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -1,6 +1,8 @@ -## Archiving to S3: +# Continuous Archiving to S3 -**WAL-G** is used to handle continuous archiving mechanism. For this we need storage Secret and need to provide storage backend information. +**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. + +## Before You Begin To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. @@ -9,7 +11,9 @@ $ kubectl create ns demo namespace/demo created ``` -Below is the Postgres object created with Continuous Archiving to backup WAL files to Amazon S3. +## Create PostgreSQL with Continuous Archiving + +For archiving, we need storage Secret, and storage backend information. Below is a Postgres object created with Continuous Archiving support to backup WAL files to Amazon S3. ```yaml apiVersion: kubedb.com/v1alpha1 From e4622ad68d2a6fc333b520c0f4b81ada4fd168fd Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 14:12:26 +0600 Subject: [PATCH 07/25] Added GCS doc --- .../postgres/snapshot/archiving_to_gcs.md | 136 ++++++++++++++++++ .../postgres/snapshot/archiving_to_s3.md | 6 +- 2 files changed, 139 insertions(+), 3 deletions(-) create mode 100644 docs/guides/postgres/snapshot/archiving_to_gcs.md diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md new file mode 100644 index 000000000..9b4252b6b --- /dev/null +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -0,0 +1,136 @@ +# Continuous Archiving to GCS + +**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. + +## Before You Begin + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Create PostgreSQL with Continuous Archiving + +For archiving, we need storage Secret, and storage backend information. Below is a Postgres object created with Continuous Archiving support to backup WAL files to Google Cloud Storage. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres-gcs + namespace: demo +spec: + version: "11.1" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + archiver: + storage: + storageSecretName: gcs-secret + gcs: + bucket: kubedb +``` + +Here, + +- `spec.archiver.storage` specifies storage information that will be used by `WAL-G` + - `storage.storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `storage.gcs` points to GCS storage configuration. + - `storage.gcs.bucket` points to the bucket name used to store continuous archiving data. + +**Archiver Storage Secret** + +Storage Secret should contain credentials that will be used to access storage destination. + +Storage Secret for **WAL-G** is needed with the following 2 keys: + +| Key | Description | +| --------------------------------- | ------------------------------------------------- | +| `GOOGLE_PROJECT_ID` | `Required`. Google Cloud project ID | +| `GOOGLE_SERVICE_ACCOUNT_JSON_KEY` | `Required`. Google Cloud service account json key | + +```console +$ echo -n '' > GOOGLE_PROJECT_ID +$ mv downloaded-sa-json.key GOOGLE_SERVICE_ACCOUNT_JSON_KEY +$ kubectl create secret generic gcs-secret \ + --from-file=./GOOGLE_PROJECT_ID \ + --from-file=./GOOGLE_SERVICE_ACCOUNT_JSON_KEY +secret "gcs-secret" created +``` + +```yaml +$ kubectl get secret gcs-secret -o yaml +apiVersion: v1 +data: + GOOGLE_PROJECT_ID: PHlvdXItcHJvamVjdC1pZD4= + GOOGLE_SERVICE_ACCOUNT_JSON_KEY: ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3V...9tIgp9Cg== +kind: Secret +metadata: + creationTimestamp: 2017-06-28T13:06:51Z + name: gcs-secret + namespace: default + resourceVersion: "5461" + selfLink: /api/v1/namespaces/default/secrets/gcs-secret + uid: a6983b00-5c02-11e7-bb52-08002711f4aa +type: Opaque +``` + +**Archiver Storage Backend** + +To configure GCS backend, following parameters are available: + +| Parameter | Description | +| ----------------- | ------------------------------------------------------------ | +| `spec.gcs.bucket` | `Required`. Name of Bucket | +| `spec.gcs.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | + +Now create this Postgres object with Continuous Archiving support. + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml +postgres.kubedb.com/wal-postgres created +``` + +When database is ready, **WAL-G** takes a base backup and uploads it to the cloud storage defined by storage backend. + +Archived data is stored in a folder called `{bucket}/{prefix}/kubedb/{namespace}/{postgres-name}/archive/`. + +You can see continuous archiving data stored in GCS bucket. + +

+ + continuous-archiving + +

+ + +From the above image, you can see that the archived data is stored in a folder `kubedb/kubedb/demo/wal-postgres/archive`. + +## Termination Policy + +If termination policy of this `wal-postgres` is set to `WipeOut` or, If `Spec.WipeOut` of dormant database is set to `true`, then the data in cloud backend will be deleted. + +The data will be intact in other scenarios. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/wal-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/wal-postgres + +kubectl delete -n demo secret/gcs-secret +kubectl delete ns demo +``` + +## Next Steps + +- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. \ No newline at end of file diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index 3e325f6de..91abc0627 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -22,7 +22,7 @@ metadata: name: wal-postgres namespace: demo spec: - version: "9.6-v2" + version: "11.1" replicas: 2 storage: storageClassName: "standard" @@ -90,12 +90,12 @@ To configure s3 backend, following parameters are available: | ------------------ | ------------------------------------------------------------ | | `spec.s3.endpoint` | `Required`. For S3, use `s3.amazonaws.com` | | `spec.s3.bucket` | `Required`. Name of Bucket | -| `spec.s3.prefix` | `Optional`. Path prefix into bucket where snapshot will be store | +| `spec.s3.prefix` | `Optional`. Path prefix into bucket where snapshot will be stores | Now create this Postgres object with Continuous Archiving support. ```console -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres.yaml +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-s3.yaml postgres.kubedb.com/wal-postgres created ``` From 6f1d09ce91df1b524070c9037a35f725f88a4de8 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 14:31:51 +0600 Subject: [PATCH 08/25] slight updates --- docs/guides/postgres/snapshot/archiving_to_gcs.md | 7 ++++--- docs/guides/postgres/snapshot/archiving_to_s3.md | 3 ++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md index 9b4252b6b..b74a6f579 100644 --- a/docs/guides/postgres/snapshot/archiving_to_gcs.md +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -19,7 +19,7 @@ For archiving, we need storage Secret, and storage backend information. Below is apiVersion: kubedb.com/v1alpha1 kind: Postgres metadata: - name: wal-postgres-gcs + name: wal-postgres namespace: demo spec: version: "11.1" @@ -42,7 +42,7 @@ Here, - `spec.archiver.storage` specifies storage information that will be used by `WAL-G` - `storage.storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `storage.gcs` points to GCS storage configuration. + - `storage.gcs` points to GCS configuration. - `storage.gcs.bucket` points to the bucket name used to store continuous archiving data. **Archiver Storage Secret** @@ -133,4 +133,5 @@ kubectl delete ns demo ## Next Steps -- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. \ No newline at end of file +- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. + diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index 91abc0627..da0e54aca 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -133,4 +133,5 @@ kubectl delete ns demo ## Next Steps -- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. \ No newline at end of file +- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. + From 168693075924874aacf526d2ce05d03aaa69fbc6 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 14:49:05 +0600 Subject: [PATCH 09/25] Added Azure doc --- .../postgres/snapshot/archiving_to_azure.md | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 docs/guides/postgres/snapshot/archiving_to_azure.md diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md new file mode 100644 index 000000000..f38018fc4 --- /dev/null +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -0,0 +1,138 @@ +# Continuous Archiving to Azure + +**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. + +## Before You Begin + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Create PostgreSQL with Continuous Archiving + +For archiving, we need storage Secret, and storage backend information. Below is a Postgres object created with Continuous Archiving support to backup WAL files to Azure Storage. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres + namespace: demo +spec: + version: "11.1" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + archiver: + storage: + storageSecretName: azure-secret + gcs: + bucket: kubedb +``` + +Here, + +- `spec.archiver.storage` specifies storage information that will be used by `WAL-G` + - `storage.storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `storage.azure` points to Azure storage configuration. + - `storage.azure.container` points to the bucket name used to store continuous archiving data. + +**Archiver Storage Secret** + +Storage Secret should contain credentials that will be used to access storage destination. + +Storage Secret for **WAL-G** is needed with the following 2 keys: + +| Key | Description | +| -------------------- | -------------------------------------- | +| `AZURE_ACCOUNT_NAME` | `Required`. Azure Storage account name | +| `AZURE_ACCOUNT_KEY` | `Required`. Azure Storage account key | + +```console +$ echo -n '' > AZURE_ACCOUNT_NAME +$ echo -n '' > AZURE_ACCOUNT_KEY +$ kubectl create secret generic azure-secret \ + --from-file=./AZURE_ACCOUNT_NAME \ + --from-file=./AZURE_ACCOUNT_KEY +secret "azure-secret" created +``` + +```yaml +$ kubectl get secret azure-secret -o yaml +apiVersion: v1 +data: + AZURE_ACCOUNT_KEY: PHlvdXItYXp1cmUtc3RvcmFnZS1hY2NvdW50LWtleT4= + AZURE_ACCOUNT_NAME: PHlvdXItYXp1cmUtc3RvcmFnZS1hY2NvdW50LW5hbWU+ +kind: Secret +metadata: + creationTimestamp: 2017-06-28T13:27:16Z + name: azure-secret + namespace: default + resourceVersion: "6809" + selfLink: /api/v1/namespaces/default/secrets/azure-secret + uid: 80f658d1-5c05-11e7-bb52-08002711f4aa +type: Opaque +``` + +**Archiver Storage Backend** + +To configure GCS backend, following parameters are available: + +| Parameter | Description | +| ---------------------- | ------------------------------------------------------------ | +| `spec.azure.container` | `Required`. Name of Storage container | +| `spec.azure.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | + +Now create this Postgres object with Continuous Archiving support. + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-azure.yaml +postgres.kubedb.com/wal-postgres created +``` + +When database is ready, **WAL-G** takes a base backup and uploads it to the cloud storage defined by storage backend. + +Archived data is stored in a folder called `{container}/{prefix}/kubedb/{namespace}/{postgres-name}/archive/`. + +You can see continuous archiving data stored in azure container. + +

+ + continuous-archiving + +

+ + + +From the above image, you can see that the archived data is stored in a folder `kubedb/kubedb/demo/wal-postgres/archive`. + +## Termination Policy + +If termination policy of this `wal-postgres` is set to `WipeOut` or, If `Spec.WipeOut` of dormant database is set to `true`, then the data in cloud backend will be deleted. + +The data will be intact in other scenarios. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/wal-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/wal-postgres + +kubectl delete -n demo secret/azure-secret +kubectl delete ns demo +``` + +## Next Steps + +- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. + From efb1fd18c3f62c3221f3da67b831849d342f36fe Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 15:01:21 +0600 Subject: [PATCH 10/25] minor fix --- docs/concepts/snapshot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/concepts/snapshot.md b/docs/concepts/snapshot.md index f3ad32202..6720018dd 100644 --- a/docs/concepts/snapshot.md +++ b/docs/concepts/snapshot.md @@ -434,7 +434,7 @@ secret "swift-secret" created ``` ```yaml -$ kubectl get secret azure-secret -o yaml +$ kubectl get secret swift-secret -o yaml apiVersion: v1 data: OS_AUTH_URL: PHlvdXItYXV0aC11cmw+ From 59bbebd4dba9be9dcb832a5e86c177b7b540e8b7 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 15:01:36 +0600 Subject: [PATCH 11/25] Added swift doc --- .../postgres/snapshot/archiving_to_swift.md | 158 ++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 docs/guides/postgres/snapshot/archiving_to_swift.md diff --git a/docs/guides/postgres/snapshot/archiving_to_swift.md b/docs/guides/postgres/snapshot/archiving_to_swift.md new file mode 100644 index 000000000..28e7d9485 --- /dev/null +++ b/docs/guides/postgres/snapshot/archiving_to_swift.md @@ -0,0 +1,158 @@ +# Continuous Archiving to Swift + +**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. + +## Before You Begin + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Create PostgreSQL with Continuous Archiving + +For archiving, we need storage Secret, and storage backend information. Below is a Postgres object created with Continuous Archiving support to backup WAL files to Swift Storage. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres + namespace: demo +spec: + version: "11.1" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + archiver: + storage: + storageSecretName: swift-secret + gcs: + bucket: kubedb +``` + +Here, + +- `spec.archiver.storage` specifies storage information that will be used by `WAL-G` + - `storage.storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `storage.swift` points to Swift storage configuration. + - `storage.swift.container` points to the bucket name used to store continuous archiving data. + +**Archiver Storage Secret** + +Storage Secret should contain credentials that will be used to access storage destination. + +Storage Secret for **WAL-G** is needed with the full set of v1, v2 or v3 authentication keys from the following list: + +| Key | Description | +| ------------------------ | ---------------------------------- | +| `ST_AUTH` | For keystone v1 authentication | +| `ST_USER` | For keystone v1 authentication | +| `ST_KEY` | For keystone v1 authentication | +| `OS_AUTH_URL` | For keystone v2 authentication | +| `OS_REGION_NAME` | For keystone v2 authentication | +| `OS_USERNAME` | For keystone v2 authentication | +| `OS_PASSWORD` | For keystone v2 authentication | +| `OS_TENANT_ID` | For keystone v2 authentication | +| `OS_TENANT_NAME` | For keystone v2 authentication | +| `OS_AUTH_URL` | For keystone v3 authentication | +| `OS_REGION_NAME` | For keystone v3 authentication | +| `OS_USERNAME` | For keystone v3 authentication | +| `OS_PASSWORD` | For keystone v3 authentication | +| `OS_USER_DOMAIN_NAME` | For keystone v3 authentication | +| `OS_PROJECT_NAME` | For keystone v3 authentication | +| `OS_PROJECT_DOMAIN_NAME` | For keystone v3 authentication | +| `OS_STORAGE_URL` | For authentication based on tokens | +| `OS_AUTH_TOKEN` | For authentication based on tokens | + +```console +$ echo -n '' > AZURE_ACCOUNT_NAME +$ echo -n '' > AZURE_ACCOUNT_KEY +$ kubectl create secret generic swift-secret \ + --from-file=./AZURE_ACCOUNT_NAME \ + --from-file=./AZURE_ACCOUNT_KEY +secret "swift-secret" created +``` + +```yaml +$ kubectl get secret swift-secret -o yaml +apiVersion: v1 +data: + OS_AUTH_URL: PHlvdXItYXV0aC11cmw+ + OS_PASSWORD: PHlvdXItcGFzc3dvcmQ+ + OS_REGION_NAME: PHlvdXItcmVnaW9uPg== + OS_TENANT_ID: PHlvdXItdGVuYW50LWlkPg== + OS_TENANT_NAME: PHlvdXItdGVuYW50LW5hbWU+ + OS_USERNAME: PHlvdXItdXNlcm5hbWU+ +kind: Secret +metadata: + creationTimestamp: 2017-07-03T19:17:39Z + name: swift-secret + namespace: default + resourceVersion: "36381" + selfLink: /api/v1/namespaces/default/secrets/swift-secret + uid: 47b4bcab-6024-11e7-879a-080027726d6b +type: Opaqu +``` + +**Archiver Storage Backend** + +To configure GCS backend, following parameters are available: + +| Parameter | Description | +| ---------------------- | ------------------------------------------------------------ | +| `spec.azure.container` | `Required`. Name of Storage container | +| `spec.azure.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | + +Now create this Postgres object with Continuous Archiving support. + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-swift.yaml +postgres.kubedb.com/wal-postgres created +``` + +When database is ready, **WAL-G** takes a base backup and uploads it to the cloud storage defined by storage backend. + +Archived data is stored in a folder called `{container}/{prefix}/kubedb/{namespace}/{postgres-name}/archive/`. + +You can see continuous archiving data stored in swift container. + +

+ + continuous-archiving + +

+ + + +From the above image, you can see that the archived data is stored in a folder `kubedb/kubedb/demo/wal-postgres/archive`. + +## Termination Policy + +If termination policy of this `wal-postgres` is set to `WipeOut` or, If `Spec.WipeOut` of dormant database is set to `true`, then the data in cloud backend will be deleted. + +The data will be intact in other scenarios. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/wal-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/wal-postgres + +kubectl delete -n demo secret/swift-secret +kubectl delete ns demo +``` + +## Next Steps + +- Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. + From f1d034bada4bf8523865b6be051604c32359ee9b Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 17:37:47 +0600 Subject: [PATCH 12/25] Added image and yaml sources --- .../postgres/snapshot/wal-postgres-azure.yaml | 20 ++++++++++++++++++ .../postgres/snapshot/wal-postgres-gcs.yaml | 20 ++++++++++++++++++ .../postgres/snapshot/wal-postgres-swift.yaml | 20 ++++++++++++++++++ .../postgres/snapshot/archiving_to_s3.md | 2 +- docs/images/postgres/wal-postgres-azure.png | Bin 0 -> 19017 bytes docs/images/postgres/wal-postgres-gcs.png | Bin 0 -> 19046 bytes docs/images/postgres/wal-postgres-swift.png | Bin 0 -> 109919 bytes 7 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 docs/examples/postgres/snapshot/wal-postgres-azure.yaml create mode 100644 docs/examples/postgres/snapshot/wal-postgres-gcs.yaml create mode 100644 docs/examples/postgres/snapshot/wal-postgres-swift.yaml create mode 100644 docs/images/postgres/wal-postgres-azure.png create mode 100644 docs/images/postgres/wal-postgres-gcs.png create mode 100644 docs/images/postgres/wal-postgres-swift.png diff --git a/docs/examples/postgres/snapshot/wal-postgres-azure.yaml b/docs/examples/postgres/snapshot/wal-postgres-azure.yaml new file mode 100644 index 000000000..4ea4b3620 --- /dev/null +++ b/docs/examples/postgres/snapshot/wal-postgres-azure.yaml @@ -0,0 +1,20 @@ +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + archiver: + storage: + storageSecretName: azure-secret + azure: + container: kubedb \ No newline at end of file diff --git a/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml b/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml new file mode 100644 index 000000000..2280fa444 --- /dev/null +++ b/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml @@ -0,0 +1,20 @@ +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + archiver: + storage: + storageSecretName: gcs-secret + gcs: + bucket: kubedb \ No newline at end of file diff --git a/docs/examples/postgres/snapshot/wal-postgres-swift.yaml b/docs/examples/postgres/snapshot/wal-postgres-swift.yaml new file mode 100644 index 000000000..d2ed445e8 --- /dev/null +++ b/docs/examples/postgres/snapshot/wal-postgres-swift.yaml @@ -0,0 +1,20 @@ +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: wal-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Mi + archiver: + storage: + storageSecretName: swift-secret + swift: + container: kubedb diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index da0e54aca..784734d0d 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -95,7 +95,7 @@ To configure s3 backend, following parameters are available: Now create this Postgres object with Continuous Archiving support. ```console -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-s3.yaml +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres.yaml postgres.kubedb.com/wal-postgres created ``` diff --git a/docs/images/postgres/wal-postgres-azure.png b/docs/images/postgres/wal-postgres-azure.png new file mode 100644 index 0000000000000000000000000000000000000000..17042ed267d9da3639e71fcdc90d2c33a4dcbf0b GIT binary patch literal 19017 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 ye+m7UkfDYGGy0eR`>6i^_`Ls03;*Q@x597QHw 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 literal 0 HcmV?d00001 diff --git a/docs/images/postgres/wal-postgres-swift.png b/docs/images/postgres/wal-postgres-swift.png new file mode 100644 index 0000000000000000000000000000000000000000..917f7d4b4b74d1f6458062aa89d5d030489e53ec GIT binary patch literal 109919 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%0Dx@d(zv(PgPI z{Ecj1Yf8Ltfx)yuA&X>Aa{=DdO(u^aFc7NFXHJ%4dTuT%?Ycx6r<+?F{?0FKfM^+Ly16BMj`6aTB08d@3$IOM*lwis0-2>Ve~Qt>18_yHIJG|$sjcQ*dG zSYA}(k>~YguLNk{>?!hxHM{YBB@cS)s*zh}mqtCerM{EF_1qr}c0aZhHEfq>e}a1P z;PVnI+<6Z-f0sZQ1u6K&%A+#^S%qRz>G3SX@w*RZW&thN?5y5Jl_zs`sSRse>$BT; z&0w*c&oIfH?1(}J8`69i-LT>VWx9H`{wn|MTE?p>RO%cJENrejjG*7t!FjqJN@eBX z5(Bt%+2hG6jo%NI0YCV~j$Tt~ad|(wSIkCv(zMBqvH<|9txvmnB!YyWE=%#8WtH6K zrEEZ@-oR3|r#eD=JY6QPs{bwuR{8V$M4=EwRZ|HF^NtPEbru;tYSlQS0qXw!JmRD< zqVw#ZEWlByf$?o#H3GpwxvH-8SL! zu;|R>(Yn9o*HGYzxHo(9vE#`o8c5pcK}*Bjtfkb+8QOfLU=#sAsTgGNNuF8eq^MKT zVB%LjIixY+bCe6iHnLw~o+)6cwD0uaM`!y68h-qB8jt}n68Uwyq?iMp;9^>}!=Vbw znKLv5pc_gKTJqe`zrZJ=efLg15YZ&``7W5QM?{JSjc6uR5@qlCWeyQ7og!hpVna5h z5ApW|7LsUH%$avU-suw7clVyt1#Q`I zY|S3hDbhX<1*GBDMkCxsy>w+Yl^9ZZr8Qq^G%$}rCfMwzB;o~8J>ZUj7LuB7CLjp7 zp~`J5^as3GeHLcG3RweHTkE~H;ncdaJR%va=$wFAe-|sLOn_hZH2#8exBf|@r6cs( zj;$dcV{+a;erU51i!}B;$qq&&~q(%HwI(SM;XF+*|=xWbXYk9&-dGmK~_#SI)M3%kR z-qgxc-x%);x3)T<>ZTn8R{}qhj8c?$r8ZqgwEqkp5*@8@vsEY&2GA?AlPXx2Is+_v zz8wV{{Pz9~5N8j@c^sUC^@U8d=i63{#>}?*^1-1gXBePHEAYBJ5>c99fx(1Va?`Zd zZa^WUZ)2k`v8>u2Af%>V3e{rln?%e#on4<}W#4oEt01q~^J^mMBsDs=>vuQGvEO%C zVlo{V5j!QwV8{}_&h^^mh*IbBC>#*7X20(vOjqg$rNj4VPwe=EsuJ3e)G}&X!U2FJ z2CMsLd#ZJgacE&^A$zJTGz~_SU(KzDxExjtLyFf>5MV{Je?NQvv6GZfp9pw1;_X*& z_`YgtJeL!}>pzZK+OLV(e&plwx^7|FuC$>8y=e`qeYVk+Zg}MDOa|Zv)(c)Qt~neH zZOsBc({*WadPR(Xp3WC^O<)0*3$CrOL?N8X^%_TGW?UfHG0xh{sn38XZxW@pR+h~t zhuzTB)+~Z)|cNWg*=(iS=JxMGPt2K zy<4z>F35!Srh}P>lXEBDm-wihv*AWC;xx~`4`lT~F5bfqog@x$*q6h-4c-Djcbt5JDp8CG7{<7>Dv#^54 zP527LvwmQ~n%;QcL4EzIxn6UBx2KKo zqMo_itmsAVdj-7}s)$#?1_4$qn$dP;PFX7wneC{%qC65E zH}W5HV`Y8QOZ~ulAqE~8*zCdf==0KC%n%DZJIFWzGyxBN)`X`jeS*=-X$_!&@F3}u z5+6`y`I8YqkM#OG&NuCu;Y*>TSyg!`;2pHu4QXD$dAT*OWb~>y7suBh2}f*aYKI@Y zk~||TIFIIyDRXiePggQma^XO*66DiaiS{*yXKn<@T;Po39%FtkERRALK6AJx4jKq# zaIlm=%1d2KH)dVsvO20_sWBR;T&)kkJHXnwr`@8eImkoSSu6@9Q6vqAB30X-{ir?|EZOSoJK2~fb(M_QfL zL6iSlGN4@P0{Yh0iL~fyp!) zKB2fdUaZq*O1BvmI7L_d2_G#|A6dGN)H^`=^t8Qelmb*r7el2>U?>QQZLD zYq7iWKi>2?*}FOPt_aTs{62dN8H`*~g72;ZZQlFlh=G7`HMFmfrjcL3SbQ8b$NTZ0 zTGfU$VBfw3$mBF>VeOA$Du-f9WC7uDkJ>QU%!PX@sxMn zRQLQ^r0jaSU*V~$tM0x#ZVigIN;2$!WL<1af`agRJkn#uPn-Y>v#Mk#4DZBIgSOOZ zf~69a!LQEc(nv%aE9F$M-qw)OKZ_}G@*~m5l4pJQy~oWM`W>*(gI8>QUt}CH4=^xx z-DTQ-0vrp(;jpKfGb2m(wCf%Y_`Qh|6Ssiuu4GiS^70vV6A>kt<~8NRf;agrn-Ba( z89g7W95tH3FF%2ILWh(=HfUH^7ueI)gHp*NF}5)J=s; z7)DP1t%QF^tTuFBUKtjM*{sgF44vGb?<*_ohWPn4=xF(#-ZIT<>8#g{Se?#q)yXQ1 zb%`aM4tA_~z=XiT-JEn7^vR70hV&KCtYybCZ&ovS!2URKbi;h)=3)zp4`gyYk95&q zUU=?%tpUc3O}s@*Wgg8flntT{Y|M4fTs|P@IS}h!@+Yn^6qy=}E<$eT&c{QC$jb@E zPr+0a#Fqd8E-EfpMMi^=jxFtC_jmqUh6@y2sy6PDmnY#7FKhtTK<6#x2+mPgE2Y0t6Z!dtbd$_m~cMpF!XyL`0n3} zC=7VRz3Y5~S&fzt2#^ubT>!KMIi-_3&5W)Pu1I@6b~KSAbnM^b(;5pt)Fc3}cgZPL zid%Z(b&rZ5Ah^0HKy%JyKg5ajgx-F%#{W2hzg=Ddj1Mj{3BAFb0&Z1Jpx{40@>*tG z9L2X(oz=C1)@(-R^3F$-?Gw-rN%>s`2Lq(xR?WPzw5bQLysX8Myx~2%XSIA9@oWyW zwi5A-cteV@r8gSJ$`5O2j8lJ~(F2+=JL~-5-&hEgs$e5&AX)Xo8Oxfo*Xdi^j>Z&~ z+KHOFD1=_t)kUrYCbW0Ywb-6oGGWJt5&7%4t)PJ>KD^PvDp*`3d@j`!{#larQZ5QM znVaxg2fE6-+RH|-@%4r#bN}3qz~q^389(evX|L$+D7Mi9O@sF!U>@V`w}DMZ(6oB% zh#S;@I}>-AgnYDC8rnnxgluw(2k45ZYxudWauWW3-{o5AO{)78?DHSyn{Q^0F!kVpcd5Rsf6Y@$VEG z3@FjDPxnNLEC^x>HaG!AVkIz2CGb(mHpoIiT;kN~9wL^f-0V>(D@*D@S_W&g{LDgpqvfb$N|vvIus;HHnIui&u}OnW-t z@)SB0S8ZwX;m4~2!=Gs%A&}>U;VE%g-lRNCG>Rx_B#UXJ&*+4O37HBS{+VDs3hRp> z7c>}Xvshb!53CyzC1(7VC_vif*rn&xBoz5?-nR~bB?BZWe*nx>ZTarCS#7&z(`k7A z03h1W3mxG4?6Mpr5X%7a5tI{$>aeCqn?=~MD5Ud*Lb%&q%_I2LYp^K*%4B8Z?mo$G zC)ndbz*V0DsuXVf0%#OEEEV|l_Zw?TMgVpf&M=0^QU^rFLvIDkcL!TFu!0>8`oE!_ z6*SQO!1fTV7Js;m0bm`lobFPEtNLm8>q~|1v;M`cRcA?RmEYf4#Wrc?to%#0k2BKY zyIE%!kW;mX{0lTcCl05_07Ul!VqL}rqAF;xQu#z)weqAQNblIfwYdG@Ae+gO>?tHB zA?Uw6$?6^wuQoeIHiot+ocDOwW@!q|R)Km;!0-NfdSzwG0kwl*ZnN6ryboEaduk2} z^1SEWchftl&NN;Ck;i1QNVKkScnCjamF4Lkt_e1 zh;S4}siro9FeFlZe{@h=I_klp_3H5kEQCL)e-vzR**ulx)Y2zgCk_rkkuCL>@&C@_ z4~>jWt{}1T@ThxbjpN#^%(UzNHE>Gctj}*~&&G^aV0r)|SO3Y38l3N}6G>ddSDqw4 zcN>$?zY7|+ecS+&clAVZp^H59v(rTBH8#4t{#_FX zRF0>IrAStG&LAMK@raQ1E)rscSn1yZrRIXc>3IMND#G5#cI9PZHoBg37bp@e8Ram8 zn$1n28W3Ec#@#=v+t-_g$={(jK?iwcLs-n|QF!|O3x z9(&{ECQ9d2d|cSTmRIK*gx7$4-MA^h=(&yHbE$`;ZP_B6h2Czg*rC1O4yBZ_xG@D^v*GKOTgQ) zphrCrhMep&>FwuK?A08VO%Q@|rx&US;!r8w%2fLF=)*0|%e(V5JBn$h=eM}s{O4wh z&t-n9eoB}*OU^5|l)%5hlLIKe4eRkIKSDe3mkHb*H@yMHTheO#;97XtezixO3c}$i zBF9iwHPsp|eJ)d5d$x>HGyJi2 zfFs1o$?ft!%VjS1qm|+9^x=mfd5@F9zP4KHx@s@ZH%*za*d``*Gf9^Fd++kjYNvW< zwQQ!Xh#8RU9K7fC2}|q_|0aD&M3qD4sEc17{7n+rx)}E*@s+N(BXWe%N85_&K$8!v zhPu%j?R`nfX(13lJK1~{V4Ky!c}(>i0~iDrku)IeA2#s-H`3i8kbrznHHaEWh8IhF zBSsZG(>T9^Q!f(p9J`ydRldahP zt21zlmzG#f5lKNO_fvm96ZYyDW#SHEg`?PTM{Ggg)GsZ{Ph46t&hiW6m)?eksI& z9{eL;Sz&N6IQ!J~1pdY9<*7K-e@z~-F?9Bppz=yD;(TTzIN_w9i zGPj=Zade|9nQvFnG*4b0?#t;B)>|346vkLgw8tFCU4ur|Yxj9R$OY7u$taSwZzjgp zW%V)93Bk&RkaPo3%=ANriT+M3oYzd8MZ6oB)AXOW3c#e#4!Ao&Vdn)M`ry zi_E--?flMKL=y}T4yfE0@E}`HTxsp8yHUELR~I-B#ErufAq8gr*siu(M(>M$&AQ4( z1+eCBfIK~no)QFAE-`mezxW;`mH3M=(OJj|U}}kZ#(;H*sx80M>($ldb8I&X8NT*60`CS`u^{^1 zIf-b(ujey&Px!3pgP;iz8tv)V`5*5BSx&A++HVJxEX(Ee^2&uLT+&Btm#Auw-E-b1 z?dxeeN7q0wLW-cjo)U$t&4p(%RZRS=R7oTe_?P^-d(XT<$G~zj3!ugesLZ6U#w43rLrs+X5F3Bwotu z$%z>v6*tIkMUMkppY4(f+8A&y#0nvWze1%sp{d_iy%JhWM7p}-cCj;Ew69SHdcn2GUoxn`Ha4$Y_Zzgc z-hIDY`1v|E&OfmzG<{3^muSu?+O-Z2-$OGSXn_rB_;c}Nql*9{$k1xc;*bCJfU#hH zN{{>br<=R(;jtp7wBF*SYuARy zv_Wf{!=u={^mSox3y}5~38+mJmCL*Q=o`f1qOW9y5>>Dvwbmv-u+Tv(G9WK!Vgj4= z<#)A^+NR7nXmp-JX6Q9Y(8`3X?J+M#2-xW$h6@e4Veety-E8Gqm6hX(EXvhsZ*XaY zHf^gz-?4#@bm7@7E;v8~GHXbcwn8^cmtb*CHk0i5v|o8P)rD-jfNxAc4%RWR%$V{) zCa1X&cs|+eFKFo?UF!QW9UrpYb0t6lKmf?L@o-r7%~`0=tjiAPGb@5LXSOU=?0Xdp zxb%*R(I<5M)@^$*GJFXlWCSY3wefaz#c+E9Ed?nA#Fsjx^GTjw%h$n=jFAFp83Fmh ze2JreCsnRb;peQJ7#kzk!cY)SE*{`c5_UXnh@9-z#JcfKALkl&&#uk7$nx>@06~Up z`50)fE;2w42F6qjPllh$HraYJkWy~EhsXfdTXjf)gw{J2M`A+x-rS6J;J(NO=?f$4 z50ksBG(bgNsPcI_wB5L4Ls$;F)d3N`vej2$Z$ zAqMB(#%fDExJZ!8n9kv;mh5l;jEH7DE}5Z!jo&lqUnw4xh}>1Qav(T zMPPU;r?%BL2ri|AP;+EN2~qY;t{T0BqCVzUh+wjq00@MPiPU{xa?>+3H;L~3>ip*q zzEM>J{vRYhB)LI*o>!!BaBwGtMc$6MP6C9WQ>v1^MD4qlScV9>8;DO9;b zZ1&~`t6Yd0zOm^g6Gy|)hN+n)&~IstuP#n+_GxvV>o&JgH4ZS523Qz>7$#_P_KX?? zhNjlc=V3LU*t>K;43nfAq)+_#dYWs`MNby!)2eMwsWJMy^ic2xXVTMXp6RA>R_OPn zDCUlinvIg7YKuz1K!9A=AzO)HPdKJ!%w2(1_ye|B6f1``L4c66GLLzWV+*$uqfytCjV&=Pao zv){OX@e!etY2>zgdeHMTSa5X1rv*5QN{B)8(1q1X4jG&@5~qp3-giuodFRLC*9&;9 zRbpv;p!QhQ=&0Vi7X99(@_nz;78gnLUdrleVtG^a@(N9&)uVu*ygSR89w2AS=Ch-W zS1U|NPjK0&jEDJ_OK|O$=}jgqXIu;YdL+2gd@nDn*psls>wOZMG-YeO;Ib3 z9OhXDZ&263P?s=tWFgRD*GFqKi$NZJD6BUxB?OL;Wr4gEgD~QRPH5poUO@#Jxo7vqlW~AIW4iXX@2`jp&}$x6N#i z0a%3s1%f~kpL;GiRQtgA!1U1`tDl>WKyz}o5^V_4Nd1Rs=wd6?$D_qD%p@W=DpvYFt<+m}gJx1M!;a7?Iv!bonu;SQKl^Sh}> zAU}0-e%1TOf$AA41izti`RGJ9F>(3eWia*TR?*K4vLm?=_4U~xNdLpR7^S&932v92 zRfIF=F<5N{md*_Cj;pp=1uL)5*@Jvqi#N2~7JYwm9gqsr2(dwcIr(G{KoiNGGrNyQ zF~52qo~O!la1ydl&ZxAj+4ORRl7MdN^>yW5Yl3Gw#WNjX6xR>HDwa_QB%| zCs#{qQ3w|RRQ-59!lC^#{^xVVQ1BiJWSVOWOaP91W*r05E4sk@=fJ0|^Q~k6kuXYz zN{nX_(_v9|jn_&b7BT{Kp7MpC00#zwm`_S%+`zzSe-59j%k6_6sisYT&Pc+JJJ6df zY;C*h+xm@6KT<@cGT?%bC(8iKlwZL_)AVgB zT~{v1J3i}zkgqi(8Z(o|D&w-{&+5Pi?7uU<6t)x6${NtNtolQ#OW%lc%|shv4a8=nVec_JYg#Tc}r;)I+64W#_H!B?N! zEy#EJAJ6TbJ|)NoU48Ox9a_7y(NZ&LY~imVKT2IMfj(t`;z^$0x5mCGmLMVh^;TczbVOAlSI6Z{nbi?`eEv_0pSN(CMl#2~% z2>NgC)qy`q-d7viX>EDwZ!7B+Bb5BKpy9m)hEuuWUYX*eUQ4uOQD@#6(N%C>zQl;M zxyV=o9|LH+fw_UC0_3(6jq9onFKWqspllv{HT^Sr=HYKCJU_2}6^t%cvz&ZmT2xUk z;i*C9tNVZ-Bu+s|b;D%l*>S=YIh%B&8;HWtNSMAJ=FWC>0&&*WVczFG13OKM`QQ=g?SdIvALD!ves`#f@ zg(5wJZ-e3_ZcWyUx?a%p=b~`qq9m^rbBDJ znyZKi2;2_!~^y zN;stSS_qD2vY{d6V^#Xx2w7W~QD7mRF6PYb%+nG0*Kc3ng8#9?a>I6ZVL=SC`s3C7 zE*!{Hv3V=Q_-fU`qFvRyTXs34ARK=Zd+=Hl$t?4auH%9chdQwSv4gXSro@zNcDC%* z+_E0M8F_LSqBrZcg9Gki$bh%;H>9all9EFB&VdPFHBKVbd+%0O)3W*;_sd(Gz}=V5 z=jFn8edbl)u_*ZIUo7#%r?x8b2i{(bgIJ$N#Y(t3v71D(8U=p|%cLdOc1eE$FW-Ew z=JjY}+UKCyWp53Z;YFtp^bh+mw_Y3Nv6@->%rkup*fn!}6ipQ?x~+~sV6zUPO5c@M zU)22{+TH@H%C2i0-G~a(AV`Caf^4o(w&F(yt z{k;GCe9!xxGtNK$Grr?+I2=3gz3#QEE7gKjxEq1ro)BWf6`J6!m-p5-ams<6hjI39DBDveU`<-V|Wwin+0f?0G^C8PgC3$g3cc+S-F zs^90)$AAn_dQwn)FWGit3MbS9AhzCHPz{YC95b8gh3naoe?>iGWlmH8_T@_zoBjMA zCrGh)@7b%%D@HL~g6cLCrA9WM$&-{jO;&!FF=kS@6aSnFB%O7^B$~_`^MfbRAOhxQ zC$Koo{Pun{*308D+*flL{!+Evi8iWg|Jv$m!}o|*mhU>uMVj0PtD)3186D9&7sL~Z z)`wGtsqsdY_xwcBCQc{AJ}?k>Fx_d774+g!wi@-_QOUmZLx=g%XTA~LxVIDIQ{Mg9 z%+&{+KcC+AIO$=yigbmER=7ahY_sC5KN-$0_d{_J7D=KOPtXD9=eE9**6zU)p|s^^ znvXoKy;TeSwL~ZpQD+Mdh?*oJ4}^sU!&uAj+N@7F5-TgWit@PL)?Z<7;^t$VCyktX zA%+La>Jg`#6hksyn$qAoR@Gd(pA7lmz)>GckGft7en!fbXGdsWsiQ zkv)~5ok&hzvbd=@h*}~f+Ip+7mtd)qX&g{Bead^n>V3?kIAls$0CC&A+tzhSod{WT zG?}Bk?7t+2uJ&>LCSn^aDDO0jS=YeoiiL#*|IVSbBkMMr_)P-a!Jyz&Zihd41=;}& z*NSszHw+L69cGu)1%J9>8ka&R`MarxHABejPp%M_{_YMkyIwca|OpB>`P@=WrC_8(oogr=F0(48g4GI3IU?}n_& z$mn6zv-wu`Dx_^8BmZNI+luD66X&}o`vzmDOQU7@{}182X<4w$Wh6Dn8;efd{Q-Q4|BxshIK~&WYtBQ= zjXl+Rri81Ys@Y`9K@ov`@JaH1b*^7V#9*92;5Fx!`iDgNd92@anJ!~(w*w2~zHHz7VL2&1rZJF` ziOHMA7%Q4{D#$6eDk>^Zp2bNv@*m8b1WRYLjA^IpgENKPtTK3~M5bj9>weCcn2f9l zu9M<}x?zWg$a8YBxT+m2sr94dj>gQ=lJ1PGzQp1@6FGHe1JoNMC5^TZmIHVgqZL1o zH4(>3Tiai#m0oFovoN6t`UA39O}%ZZkkkz01YgbCInpQ=d;jUPh3nc(8HVpATX8!X z=QquaPpVY&o0)RH>%%*O1C*48*q|c6@2$Zc!T!p4`&qU}0%VH`E$*FkW4$NlW+hBo zgZ&f8ovuB1!4qZ}+}3t}(kyCgGb+JVvoC4Nt?)f$b2*w_+431l%np%z2g?~3CvSN@ zZzWcSMlszvn%fw)U|9HRvE13CsaD^pnrNJjW3_hDSEAid6(v}l2C>e!%(aiFBD!FB zm*S{j=0fI>pDt_dcS}%vTEf_#jl(+UIBRf`;71+Rx)Yk1AEd0odTz5RC5m;#(G)rO zkt&L;l14kTO&?FTZ1f&wKg!ZL)3A$t<^l8Bh$iVY&Wc@bvHFhf9~Y06%QyyQ3I0K) z&S(MCDw8ZjS9O;u3XQ6^JTlEHyFUH+tiDzrUAH-&$!qkk^xyy^S(x z#1PqQ;Tns3&tD7cI!;730TtW9#57aST3cB<8?!=!EnF^#-8^?OsH|LZ1J|6%pwiLM z{tEb+2uHiI2Z=7dMoc88%}U%Q+A3p8o5toI@^~4Fx9`TF#AU=($)PPgJ=#Hh=vumB zwJ|+^$(>JQcsr(D^Cm%zH2dx3Zr#uYq|2{v)(16W2o_;0n zM|2A+J&VH$3tbLc!rjSY#WC1_{OIAoCdh0yy83YiTGI|kHd_JbMp(9XfBfO4N8Z*l zdB2FrKatDK=9Zcf`qb`wtfXDs@JNgp{1l!Lb|;-_W^aME*iN+T0O%5n`}PCv z%X6ju@6~qUk)HPujit zDVbPj&Wrv5Q)7_S{EoHiEx!*%t9sU?HyNMQu(Vg^bU*uzeiPW@+sPji%9oSmwO{&6 zZM}Pt^D`i&l3Mf)I^m$<#63}Ug-Yqr{#`1^6{6FypX#!hx9~qU%sC#OxQ#o=76wv} z(~81F=z@R9BVT=Ed@JC5DMdWQbihFF4)ZNP0(kCU{}g=m{u&BMX;VzlTTv*98%Xsy`R@5$f$@ zQ!h+bsbRtCGk2%^$Hjc`E{%`ZoLeCM@`Bzf@=W2sUl@lL`hWbs|A8z0-+zR$Q?=}u zyqVs*6HlyvTq{9u8YXNw>j%#lA4InP-=6Ds#Ql#K|Nk+{dddeUm;ZUE=JcYXlfvri z^d(Yzl}D<5^vKeb_C4@FN&Yz#yz-ApfN941>geeEj~^oGFQ}&%r@HBzzbsMw^OL?s z65qH{Y>v(>{NHAa`8Rp9Os>sK|9y^7{2$Me|NY4S56sj-W6D<+E6aAvqWp7Me*`w} zJiLeg&}@X!RayPoyN8f`moLl$ew-{VZ^rS6p%|f(Jy~=}rSVZS`KhSBWajG0=^x4m z^bc(!J&TQ?F8}?z#isCVr*y+SBuy!Foabz^>u~4~D_iN;fza?zA7A$e$15YfHLiQ# zA(xEAI(nA+wmizQS~ifNE@FMebC?weJwT7A*dl8?9N)o7qL=NvwIr-Bg}&31qz5?~ zCuCXUOv0lyJs7keo3&?x*QjOKX?(u++Itk+vy0({`XnT*2~gXtB;J9RE6<+hWFPFh zE1VBg`Kp@5uz>bkAz7vy)y@d z2*EQu#!F`vgv5);nG@?aXKEfahUD)9>)1n{)v@uREu1P^dJ z9U6_}1=AAxW2;!BN&_-J{$ENtZA9iFSKk%)eTa(1fD0bxei&F%ht{@kA>|hxrE>EY zD;NWuKqKofe3NB3t>P;dB-JThh@p+ry3{?k2D-E_fcMg@XG4v8mNFgHG+m!~6$)AF z$re#bHz2jIK&c#(7T(mgUca7Cd(lwZHpJ?vOB;bKFh2SnSo(O*x2AW2i>{iCJEHHU zni4vCPZ?*tCd8M6`MhNbpsBk0@hf%4QQ`a#YC?VN`K%^`TktJ0mtavS< ztV6@GZ4xiqMD5+UAj?cvwwPL|#SFmmLVk*C+ohpqRN+_p5;lzflf$m4@o7n-s-G)wH!Tg=p;g{s)gcbD}kEuf4q zK6W~f2qLi z_N@w-RU4V9)3CVfHYoSM7@Q!8BcoChlDM_C%MiDdxe~2Yjc2B|b|j=(EVq8QbRvzhCwL3$Q}8We%}?i3Fq6lbD^Tp+*35~7ub z#ZcSTjGZHNK?YF4Uax4MiAz^)#P^JdnXQrQJyD)VJ8n<$-`CV^(yUGfJPTOi3>cH_ zXqX=l+}w)m%JW7AhA{6RIF&8)H3oG7X&Rwf{{bSy5_v>(qlk zgr-ZCYJwR;lIulgq^+HOL-arN&zI=90Er$t_L9u@pIi7`JUCWQGr+`kPtPI<>xel#jjg1a-k?OQ?^ggJ_1+SfiCO`Qgq^)-R;OEb$2lr$O{g5tfdG=>aC1pIdJ+(BM z+#8LHdgz$n28!C zp&_T*Ft(>)q8k&1JD%KQiW&)A!aakL;?KFEfrX z*)snzmg+yD`LlT~W z9q1-E6wEj|ot!?jk?3-aJ>j^xHuCD3t%H;G8FRUD@8`H6_IYXY@tHu5&*vKspS`;i zOTFbmRU8`szW!oD^*ut!23plkrP!#X=p?OUZtl(C!!32Z8aJ_0n4 zr)bOA+NgL*0+&Cld+c}GL*Ze!*l^`1jJHnZ#qFn}w@gY>4+eT|OGV!aT^v(lLm#S5 z5yB6HZJX;0)idpl7G#1CE+KSnOoF^B%ae;ylNY~{rHoZX>P#flb z>R+v|4=APDg+xiJ-C=GznnoTOYJ$~$7a_Rj5B*(h<7jhg8Z+OK-5}47rui&b4xzjv zjl;DYiohpX$}4A95)m{N(5YGO!ESnnDQZ8=erzaJ`mcE(8Hp*VO>;OiPC7MbiXS58 zd*OM2p&uIG)Z1)AA&{8IQ$Y*Y@tKiz^I+>~f+B>PKvF(FR#?Pe0qWVeAPgk0@DV0gnLlvZak$0`xonIq8L977(Bn5aknvn6r~K zsMnRO;1=@waYqK}QVc`bb+8cpIcD_O-?!)C>+(JLLk zT64w;!D)_vn1V1}>3~r}_;5!t_9Jy(L0f{8felx~CZ34qU3-_t6!zx)3(xyZXx^3+ zL9F#x<-;bFZxUd#q+Frw-Vjgtl8U^to;qgv&TZ0HURwx9OnlG7mEzR^1+KEyScvm^ zRSbt4OK4)~6KgNlL=Qvy@{Z8zuv*ExY!ANeQ}g;>U&s+nRn#*zp(y} zg`GEi6*~J3=guNfLB%~$!SjrT(7ZIY zf2atWEwR4Dnf(fVB!#EDzy5qfxZ9JH>~U!^*Dj{jGk%w&t6=$jQ}>arr1Y`D;5R}y zfz0Y-BXk&`Am8S$>G?Hiv&fEJAW+WckhfBE4Ps8sNDEHXW zg=M+pamT0dCB|@Hsa-pDO@F9>+9QTutc{R{r{kZmvXsIm%C*k#2dL>V@*V4=U(EM|gY^UVx1Wd2ueW_UuN;Z)n)bb&%Xt3= z2thD$&AJ%IJ_6!*xW*SN_dt=1O&F#Di1FstnRrteDOk27vB}lAAD+6#x4FuR473u*lq?;5MD$xj^6CpK;yN}7ong& z8j!-4Ng7v*+n;jlrN+EmBR-ie2DD3zkmn;4HJcw5bK3*Vlq^nTEb;H8blcu8T@Nsj ztJX%WX9augZ^aIKukyFHGUP5yJ#0v<@?-5mhlv_s#hOQeR0Z+0DV5+W!sae*xP4f( zp5+vfd{&ftglivtkGq}nP5KSIu*8$@x^vN}yMU($M;z_avbm>wfd0;UJrIV%Ko_DG z4;6L6ll;i zkrgqsP{TF+ zhnzHfOqX(wSn^&rUFvQ6ucUWF)_GL~zC$KY=}c8q#~YFB)<^S6l76ehTc=m5xa=xh z!rKY0Ji7&vPfzZ2e z1k?kh<{?dAq}$sc`V&iW+fLe7}5tLg)&g!ZW(`)iLsPF4tXj(^2BbT(5DS)mA8)q_V& z11Efw9D83dui^E(?;|-Y_)yYuXz9Mi9RU&;R)-l|=eW={^v~-7g=P!4f@wx|HmF|* zc|SpSbx13)4Ei?>!Lf&$0QcQ)#x)~qMx=%y-+1*&>Icf~d(_wb)gjQ?c&B{6|60kY z8UWjQUMF7sXTy%D{WD{U7aDRjMubTlO^P^C6k{XC_HYqmNW^h~|K~^CO7xu0G(4dW z(b-RK66g-s*n&ie3IJBa%C4BXf=8A}${?tVU0;>xw+<%*Svovtw~@-|FB@Bc`i`UD zim0py@UR`m3r^o7}Q@>$!{Rig$f-ueJqA$Rg}y!e_FcDkwR z96?+tUr%?NxwuXN3?HsoA!x#*eM_438C!*vZf_84FVc0or4+>$TNE`c?lGwr+TmM|N!CX|&*#*1T9MLk zSiqk2=+10HEw+f7`UcxI+9~vL`55X z0q;_-&I&Q}qY2sId*ta;19yQiWiN*eauzC}tsY9L9`=GeumfyvZ3|y)t|NT%>hG{R zt;#_@FOt|-cO)O8`1j&LF$+e@QZYU3F{H059z+VIQFzaGVy=qoH_Ge;UZ1IZn%3v?SM zowp+q;$MIL5ZmDKZlv<}^`+MKnkRHzBJ(TMI1o|Kk+}mTK6sXZ_T1ce6i-kLkP5lc zDsRDoYKwuasrhU3(=pkYR#+sP3*(MvZh**+s$`sRJ;`3-CdonY%!---xB^Y(5!&A8 zb}+eTV3x=+N1%6eIg><7=IYM7R^(X{Lb8(!@7phiFVs0Lp!xHW{*ewpY1@r1Xllf9 zObCq28=axGr@LROpvh~1SpCgAd^#JYiVu`lJ%`pV_7fhRZZ9|oQ;b$mQ;lyn%B~ET z%tWL~w=g^s`BEJ=F$u`fNJS)rraE(=@J-nh?pD=vnZO?@DzHJlucFV)q5(`^9=Z2jili8z2lp!n-iqX7j@AExw6i>W+%Zo4Qv2m&7#XvvvfCCiT zPmVjz5*aFTOK@=N7dxs+7dLQI<^5-Rx0UgS5>oEj9ok5u!_4jXcU2tfr)aO7+#R82 z`@#*~c6tQ6@fDi!8hxq+TqF0ITBQWpe(h}4|Hv|>oob6BthN~rLAn$i9aeq{hYg?A z`cN1lJeeyeP0dGq3zvBvX5Is{@7#_Xy&_0ceVf1xgFyYd-?fO{HgNL&`&C%JK3SzGP-vAzg4#%cn2wMSViBC2V)aBHfyaSIL;4Xw07PV&bx@ zGtcxAby*p}whoC~<6>L+a8r{h)%NqCre*1QRSgZj<>BO2A)v;8|G_#uF{d;^32q86 zE=N6zG49Tr6}d6NPOM^c_epa9;3O0sJ$artEiHG`Ev6Oldu5tgzI!u2a@Xft;BPhh zNRN5>5)WT-=UAiBN6C`M7JZfueOd~l;RN)B>N%uwUnV*C+u@$7;oG zOC)K~X0BZ4t0?5-Dx>hy?cfbA86(4ml%joW<|AOgwia|wSR8eECcMm8ukJ2|E>o<% zifP+89K42DcfR2-k1F<1#Xm|66P@(xG9p*+1kHEHW{jyOy-M!~ZjEB;H3S3qs;HQ< zAOr^1iv2Nz5+}OrthgJRP0OB5z;2%Anls#XbE&7Z5eR%}5SW~%Y`$M|&>K~kE?pM+ z`CZbWq3UdWY_|Ie~U|p1a`rvnsmOYi11#PoH4@#mK6`MwHl&A#b@ z45*#^p+SItJB!r}j`c#A-_v?ANr&d1Qo9wrx-utyN*};%UuP%0899=9eEA54vj7CM zY6E-RZ8tfcVAGg5^TRKgnlDQH+pZN4)2N9iBXamp9{kMu*`1YNRNL29kBhzV;u4~y zoOgD&(E{9KB9Kr?w6!-zt`u+9TFBlhNxtbmo$<oNw z6w@sc03yXEbF;y(?2{9X0ojIpUp}hdLcy;Kcx%HGGR#5(N#iPVKFpmBT2H{&aLnaE zSnTClmVfYkg@q&Lc3@>f zmiDc&R09IU7xx8SXRmBH1_aRA&Ca&^n?-qIVcnsS5#v8MBHz?|nsPF&_84V&P$c5`Chp>U}bx2>v-vAs>G($e`NgQCt zTl3rH^{)>|mp8@)2_wEx_LFSsBlFI?!{(vJQNPYj(5bc|AQsnu?R`I>pQ& z;7umXTH<S` zme8B-7i+vZzy&uYhO$$VK4#|U#IKqdO;(Y*AzdG|;ptm)_!Nhh`1M=u@!cvmS#oZi zr1RVxoQ3iL)Xx5H;Q^Lyx;lqR&pl?jSHXa-^pa5a#Cy=yk?-D}pH02DGjj5suUTrS zKw!J1_Y<#EuiG$ptZzr{1Rf|gD(c7sPy)$_g`7IT(oPJz05-g4Q(dB(L+3CX_UthT znZTrUWa*~LVL~LRu|*eWY%Dvtam3ESMrF74Zq++lMNv=J6~Cmsv}U~HN&;U2Is(qV zAx@RQk}7%Suf5%J*kK$f{eqRnEWl6Lr1-zYI#x<$h6o8RP}J zWLHtxOV1OGn|FC~)hcgoa04HI`S@f?U7!AHz(I|FCO0dDXsB}+t(ukad*6k=*IlvK z+;2{-_t~VW5Fg@zQw`8Q_WjEHq9?(xQa0C{oFL?P2@Q{mFL3M5SGoHc4QX0|2-5`} zt7BK&fuO5<8@PNL8WTZkE*rgs7-2d!P$8mn!{QCYX_za&Nk$i1Aj4x8H?`pS)RIxdZdgVy7W4~}%2UitI-;*m~6)Js%%f!zE? zm1;}j1V}qblpu+#xe(ZSTRY>Lm(HYTTdgfds%!NKP>imM^M?p4bvyfl=6r0E!cKny z;lFBz{CP`*_kbzuxQFR)$0V;R-dUsYWZ{mU+{(Jnk)H6UMLg{nGMJo;05XQ+iK@>< z*qa$PF&5}7%GPNne{P+Nu~nTck~lZioSGS+GL9HlJHHk;9R;U7w*Iy`C}(^CO+DVL z;!CP7eXQbuls}Am4w5D#apcqewRaE;H_sVlQPNY0op!tZ_W-d^F~RN_I+eB938`2b zIXZMePR8)NVe-2wb5L3wbMo?ZlSU2{0>1(=(jUZL{lS`*?~5WO-a^k8J+`Pv~sZU8+IW5Im==6Z89BH6tX@G8#S^jcu zX6}p1;bH*J0H>lcU{iokq#tzifr!$RPw3k>ll)j&5QS5%uI{?o?yge2*@-T!KZO21 zJ%tV|iu5EO<=F@z*uvb{rRXLL5IOBIM6o@q6{5tElG54V<5c9{lvub>+QB?C47B6) zd}v7#w#UW`n@2A)&7_zBs$^{H;QuUT|NFo026MOX=IV;?xIhuCKeXe>q zfak$c84u`7k>x3XvqJyBsTamfSV3(F(?EM(-qAapcPNu@)fzK6;neF6GzmO_hP2;$ zo=97pyqM(}+@&gosMzF2ZAKQLWfaR$;rWHx>v$D+|5Yrj9nZw^oC%eXdo1<)4i+4u z2zH$L2iM>ExrLCdQEJPf)Z!cw09Q&~EB*i)m#-h$IM#((tu#4M0+ZO%D{nzR1Cm65 zjej#fn2)59nY=Di|7ztTL5~ACy7+02b&bqGY(L#E-fx1z1D1e2w82|H;@*&J_tUII z@Ax3MuzoKm$cE}XuD2#e54}5619K+(o?hc;tH1aZQW}M>Y*vrfRd7w8vfa|=o0sNW-rlL}m!hZv$6P>6;!Ir}G1JAV7^+hBW5lYKjXxaa$}cIv#6 z(1nvwPwR;--5rcBrg(p7?&izbG2rXy=C`f!{1j3O=z!GJY$J$di|#??cmN{l0;J-+ z$TaC_@*YI&s2Z!I98YiPbp&8}b*m3k>`q?XKk*tOQ>m1&Gzj^Pd5-XM;$hv6jSzD*?lqA3qaw!&k;WHZF-TrE9PvU3x$b|NZai--~wtp8o0d)n9UYY5=l z1E$ES;gPmOy#eKls#QB6t&-(4>}HiIv~~7*MvqQ}nN+5{Cof)Chb0c2NPHVKwcP_n z6%;fJd5>L816{Peh`O=&k53X_dd|b4C-~!xgkbgxpIvs-Kv+Auc=FpG~wBW~%K12821#ZGs9I*Zc==-N_Qa_K6bDF#z(a+R z({@%rv%V;gClK&K;62{$7kZ&u`~qgPm{kHXRNAoNvXnWm`v9Z(os$C8yFGD1OA)k# z`WHP8izA$ua|8}}+*~#+H}%_zOx>jy&toa=tsl{3#Z~aDYpCVv73ot}?DXn`koD5K z;oMY5n98DzQ1_?wa)zd-_zfTih zAUSe|_;iO&lV@lDgnpP3hBWyKuuO+>EiMb>^B$qW>D~&Eww235U5*MgdhcO4%5HgT zl|}iXv=LBu!=yA0>{|@50Jp{Pa7-613M7vGb_q>Td)Q&~?!w+q&*5LOg$aPv?4BH5 zrJ?@1QoUg^6&~9IUrYoK-{UV*5(K{}Wz3*|K2Qp>ofEiaD?I{8AS9aJb0VkytiLy* ziJQo^tsB2gLEdvcsp^dX&8cUeu@sKr$(Af^J=#k>RN)erK|t8gk>NVnFFC!u`kNe2 z)eEG4E}%b`$vVHp#OWkIQP28Uu0`oQ>`FO)^q7ygzzxOQLB;GPn7G)-PAo;6^v*iL zcWY=O#gc5&qC+;RNuPKC-nTr+@~hY84Z4 z6u_+(A+EpP&#GE%CA86~uFlSAJ>qZ~h>Vyq(}^i94B4+B-mvjHy{>(-iD5ZO8U%nh z>c1eoQS<6n9;}vi8LNsw#qKXa*1G*E#RFuO7Yd1n0BVfQ)jG8b_qRK#gQlA+Wz^6c zu6b1qm&&6rfmfhBU>Qyjh=Zv}cS95vh**TKLOB z=iJitdvW7n_9H#*2Ly}7BOI=lgO^WDj&6VNH$UAd7s^eI#Wv%r5>wdNU{t$b_~)4) z(nEH_4v;g?I@|t!$vnMgk&459e#Gb{#rrCYR+-THl*mgVmiGwA4Io*lPb&m&5nvKf zEe1{qJf^hN&`3YKglhZ08Yx0ai-E9CH3Y2oW+hFr_Ih^wlk!tff$7z`FU4*dsQ?C{ zgfP#IIFTzaQ|0e)SCgd#jBAOUsOw`TsR{-FHFtwJMZuQOlnnR1WSbqs zJ@nh*ZyD!+n$Gg2k$BZeB59XTGAGCrY@WDKMB`eHSlq7u};WJTcOQs|qMv6k;ZZ zw-nf={Ifn>!45cIB5-GcU?y21<<{pwS#7`Soal+$*F2z0=WRxY=!0%vLDW4yO{HAy zPu8lJY^X)l98sY)^;JJy8hM4eJ+%LE+Tkp1CQ??DLy0a++%Ds?K}uoui09_r`@s~! zX0rikaCE^gY3$~~UR?*$tlO01zPlfkn=^k*XhfVsh*5k-IH3UHSSKxHF^~d$XxZ?3 zHfK)2;v70^Kqjl832F*kaN1N>8yS-7O79}Hr$gME7D0(#pVjjwaO>T}tCf8rJ(UE- zI|m|gj3Hi9#an16X6bm0O%39f_Rsu82468|AY|UW^^jzoQu#MmG)<`^CKjq488TB; zUJVy+*<+6OTa6^vOP+-s6(FN1TIGH7I3rk#g^iIt`T!dfC2%=|nQ;RN2w@oYwTSQp zd=qgD@NtM{4HlU5B=MN9ZDI)ElC|Y~RPx*2T38QC%P>*7NxZBS9H%j;@uSqp@1f}H z4?9;Bkl5X)VrX6ypr9FQ!*{?&?Xx4VR*u-B(s6M%dVUyvX9efSyz227dcaaI5Djn~ z0jRsg#C14B>IWr*K!RnrzU}03ILhwET(D8GdzT`qW`MGV=X$gcX>_}9ae8^UfPgC1 zs#Q=NQdz*J$Gs|M_Uhh*mtEe(qGYz? z2vym_$#RGx)c&=mm0_}#i`v&NUxF8A4%ry|7OvMmLsVCckDdJ@P6ATI)GY^a63|u! z_p+^3tWx`;+n)YB*KCHc@2r28@sZ7b8;);iXQCR@WQ%=6?Z1;-HuUSe-7Di3uE$jq zG;p_}2sB7vwg_gZo>icmLUz_Qs+J>?j<2dv3isKw*9>7h$&&}*EY=T_#+j>ctn{(> z&q=t9zX=HUbf1ZvuNqdahHmGZlx8s(ZctLjS7K681LRopKaaK0KI~Z zED)u)=&CU(LaxFj=Xkv23^$*T*Ar6Y(4@*Y?@|hOK0M|fHR$g?A1*t0)*DHk_ECEOq1)59nL#87#w#v>G+%}u+YM8|J5gy90ov}gqLtG;IO zJNvu$#!6BXz9i|9jaj;uY$&;Q$rbDzG$nbTg}B91!S1YaK!b*UHHBhc<;Tw-A_
SnF&psB4eTL|4 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

i`Ti?(Qnf zTLoOSw9g^60h{@<9?*R=(DVL#6T|f>?_bx@NQ?RRDGdBC##9J$#p{F@W6kTZw_?s2 zAlVz^HGVb<`Ly8HgcD9bl(ps+1#%|L3s^$Y>%W?Cmpj3DUqTl0DtRxi>J4iCR$R-a zcL2!do7}7QWFrV;*R={rK7X)LZEKR|&ko19Pez{yuLHYQaf1*Tkpx4p@o#|(1)i+};c!rT8VFW?%N^Ix{W;P6M_Pm%ds@0B$0#DN<$=w`ReTmv-!?`!`1DT44Qau zvlZOrPR*MB2G611Mpok&XcU8d?{UoOZ;03nWW72uv6%;?X(*JAaJ1N&?R@|%jS0AP z;X^6IBcTSDZjr#zRVX{g91pL9OBdaeIz(TPhcRWE9g0Ld?Fe9qF%Ym{1d?efP9^{2 zM?Om7U7HKcW>f4hNeXNm2PCLIn<7f~R&zGi~o2Gxk^k%0A7Af2x~=-`dc{8Nn>+Pa2SDMtlxC!I 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%0D9; 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 Date: Thu, 21 Mar 2019 17:40:16 +0600 Subject: [PATCH 13/25] space fix --- docs/examples/postgres/snapshot/wal-postgres-azure.yaml | 2 +- docs/examples/postgres/snapshot/wal-postgres-gcs.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/examples/postgres/snapshot/wal-postgres-azure.yaml b/docs/examples/postgres/snapshot/wal-postgres-azure.yaml index 4ea4b3620..8aa29772c 100644 --- a/docs/examples/postgres/snapshot/wal-postgres-azure.yaml +++ b/docs/examples/postgres/snapshot/wal-postgres-azure.yaml @@ -17,4 +17,4 @@ spec: storage: storageSecretName: azure-secret azure: - container: kubedb \ No newline at end of file + container: kubedb diff --git a/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml b/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml index 2280fa444..ce91d30ee 100644 --- a/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml +++ b/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml @@ -17,4 +17,4 @@ spec: storage: storageSecretName: gcs-secret gcs: - bucket: kubedb \ No newline at end of file + bucket: kubedb From 1fd62bd4bee6d53d1f5fcd6c30cc488df4103cdb Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Thu, 21 Mar 2019 18:31:54 +0600 Subject: [PATCH 14/25] Restructured Initialize from WAL source for newer storages Signed-off-by: iamrz1 --- .../postgres/initialization/wal_source.md | 111 +++++++++++++++++- 1 file changed, 105 insertions(+), 6 deletions(-) diff --git a/docs/guides/postgres/initialization/wal_source.md b/docs/guides/postgres/initialization/wal_source.md index f62f9b790..a8eb153ac 100644 --- a/docs/guides/postgres/initialization/wal_source.md +++ b/docs/guides/postgres/initialization/wal_source.md @@ -94,9 +94,9 @@ Now, we are ready to proceed for rest of the tutorial. ## Create Postgres with WAL source -We can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. +We can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. User can use any of S3, GCS, Azure, or Swift WAL archiver for init. -Here, the YAML of Postgres object that we are going to create in this tutorial, +Here, the YAML of Postgres object that we are going to create in this tutorial, uses S3 as the cloud backup provider. ```yaml apiVersion: kubedb.com/v1alpha1 @@ -105,7 +105,7 @@ metadata: name: replay-postgres namespace: demo spec: - version: "9.6-v2" + version: "11.1-v1" replicas: 2 databaseSecret: secretName: wal-postgres-auth @@ -126,22 +126,121 @@ spec: Here, -- `spec.init.postgresWAL` specifies storage information that will be used by `wal-g` +- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - `s3` points to S3 storage configuration. - `s3.bucket` points to the bucket name where archived WAL data is stored. - `s3.prefix` points to the path of archived WAL data. - - `gcs` points to GCS storage configuration. + +Here is a YAML of Postgres object that uses GCS as the cloud backup provider. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: azure-secret + azure: + bucket: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `gcs` points to storage configuration of GCS. - `gcs.bucket` points to the bucket name where archived WAL data is stored. - `gcs.prefix` points to the path of archived WAL data. + +Here is another YAML of Postgres object that uses Azure as the cloud backup provider. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: azure-secret + azure: + container: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by`WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - `azure` points to Azure storage configuration. - `azure.container` points to the container/bucket name where archived WAL data is stored. - `azure.prefix` points to the path of archived WAL data. + +And this yet another YAML of Postgres object that uses Swift as it's cloud backup provider. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: swift-secret + swift: + container: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - `swift` points to Swift storage configuration. - `swift.container` points to the container/bucket name where archived WAL data is stored. - `swift.prefix` points to the path of archived WAL data. -User can use any one of `s3`,` gcs`, `azure`, or `swift` WAL archiver for init. + **wal-g** receives archived WAL data from a directory inside the bucket/container called `/kubedb/{namespace}/{postgres-name}/archive/`. From 4b29d20f184c2c49d9b3cc989d87810a1ff4de28 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 10:47:49 +0600 Subject: [PATCH 15/25] Added supported DB versions for different cloud providers Signed-off-by: iamrz1 --- .../postgres/snapshot/continuous_archiving.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index 48ca30b06..cafadff64 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -40,6 +40,21 @@ Now, install KubeDB cli on your workstation and KubeDB operator in your cluster > Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). +**List of supported Cloud Providers for PostgresVersion CRDs** + +| Name | Version | S3 | GCS | Azure | Swift | +| :------: | :-----: | :--: | :--: | :---: | :---: | +| 9.6-v2 | 9.6 | ✓ | ✓ | ✗ | ✗ | +| 9.6.7-v2 | 9.6.7 | ✓ | ✓ | ✗ | ✗ | +| 10.2-v2 | 10.2 | ✓ | ✓ | ✗ | ✗ | +| 10.6 | 10.6 | ✓ | ✓ | ✗ | ✗ | +| 11.1 | 11.1 | ✓ | ✓ | ✗ | ✗ | +| 9.6-v3 | 9.6 | ✓ | ✓ | ✓ | ✓ | +| 9.6.7-v3 | 9.6.7 | ✓ | ✓ | ✓ | ✓ | +| 10.2-v3 | 10.2 | ✓ | ✓ | ✓ | ✓ | +| 10.6-v1 | 10.6 | ✓ | ✓ | ✓ | ✓ | +| 11.1-v1 | 11.1 | ✓ | ✓ | ✓ | ✓ | + ## Next Steps - Learn about archiving to [Amazon S3](/docs/guides/postgres/snapshot/archiving_to_s3.md). From 990530011d400787902e9173a25eae71ae765b18 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:08:00 +0600 Subject: [PATCH 16/25] Fixed init with gcs --- docs/guides/postgres/initialization/wal_source.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guides/postgres/initialization/wal_source.md b/docs/guides/postgres/initialization/wal_source.md index a8eb153ac..9dfcc51b5 100644 --- a/docs/guides/postgres/initialization/wal_source.md +++ b/docs/guides/postgres/initialization/wal_source.md @@ -154,8 +154,8 @@ spec: storage: 1Gi init: postgresWAL: - storageSecretName: azure-secret - azure: + storageSecretName: gcs-secret + gcs: bucket: kubedb prefix: 'kubedb/demo/wal-postgres/archive' ``` From 167a4e21d7a821d0bc5cd904446e81d4b916862f Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:14:20 +0600 Subject: [PATCH 17/25] Fixed archiving to DB --- .../postgres/snapshot/archiving_to_azure.md | 19 +++++++++++++++++-- .../postgres/snapshot/archiving_to_gcs.md | 18 +++++++++++++++++- .../postgres/snapshot/archiving_to_s3.md | 19 +++++++++++++++++-- .../postgres/snapshot/archiving_to_swift.md | 18 +++++++++++++++++- 4 files changed, 68 insertions(+), 6 deletions(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md index f38018fc4..95b7bd3b0 100644 --- a/docs/guides/postgres/snapshot/archiving_to_azure.md +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -1,3 +1,18 @@ +--- +title: Continuous Archiving to Azure +menu: + docs_0.11.0: + identifier: pg-continuous-archiving-snapshot + name: WAL Archiving + parent: pg-snapshot-postgres + weight: 20 +menu_name: docs_0.11.0 +section_menu_id: guides + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). + # Continuous Archiving to Azure **WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. @@ -22,7 +37,7 @@ metadata: name: wal-postgres namespace: demo spec: - version: "11.1" + version: "11.1-v1" replicas: 2 storage: storageClassName: "standard" @@ -34,7 +49,7 @@ spec: archiver: storage: storageSecretName: azure-secret - gcs: + azure: bucket: kubedb ``` diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md index b74a6f579..f6d776df8 100644 --- a/docs/guides/postgres/snapshot/archiving_to_gcs.md +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -1,3 +1,19 @@ +--- +title: Continuous Archiving to GCS +menu: + docs_0.11.0: + identifier: pg-continuous-archiving-snapshot + name: WAL Archiving + parent: pg-snapshot-postgres + weight: 20 +menu_name: docs_0.11.0 +section_menu_id: guides + + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). + # Continuous Archiving to GCS **WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. @@ -22,7 +38,7 @@ metadata: name: wal-postgres namespace: demo spec: - version: "11.1" + version: "11.1-v1" replicas: 2 storage: storageClassName: "standard" diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index 784734d0d..d71c0b6fd 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -1,3 +1,18 @@ +--- +title: Continuous Archiving to S3 +menu: + docs_0.11.0: + identifier: pg-continuous-archiving-snapshot + name: WAL Archiving + parent: pg-snapshot-postgres + weight: 20 +menu_name: docs_0.11.0 +section_menu_id: guides + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). + # Continuous Archiving to S3 **WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. @@ -22,7 +37,7 @@ metadata: name: wal-postgres namespace: demo spec: - version: "11.1" + version: "11.1-v1" replicas: 2 storage: storageClassName: "standard" @@ -95,7 +110,7 @@ To configure s3 backend, following parameters are available: Now create this Postgres object with Continuous Archiving support. ```console -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres.yaml +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-s3.yaml postgres.kubedb.com/wal-postgres created ``` diff --git a/docs/guides/postgres/snapshot/archiving_to_swift.md b/docs/guides/postgres/snapshot/archiving_to_swift.md index 28e7d9485..6a159bcf7 100644 --- a/docs/guides/postgres/snapshot/archiving_to_swift.md +++ b/docs/guides/postgres/snapshot/archiving_to_swift.md @@ -1,3 +1,19 @@ +--- +title: Continuous Archiving to Swift +menu: + docs_0.11.0: + identifier: pg-continuous-archiving-snapshot + name: WAL Archiving + parent: pg-snapshot-postgres + weight: 20 +menu_name: docs_0.11.0 +section_menu_id: guides + + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). + # Continuous Archiving to Swift **WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. @@ -22,7 +38,7 @@ metadata: name: wal-postgres namespace: demo spec: - version: "11.1" + version: "11.1-v1" replicas: 2 storage: storageClassName: "standard" From d06420c0903e95acd756019fd3fc14475c786eb2 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:18:37 +0600 Subject: [PATCH 18/25] changed example files --- docs/examples/postgres/snapshot/wal-postgres-azure.yaml | 2 +- docs/examples/postgres/snapshot/wal-postgres-gcs.yaml | 2 +- .../snapshot/{wal-postgres.yaml => wal-postgres-s3.yaml} | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename docs/examples/postgres/snapshot/{wal-postgres.yaml => wal-postgres-s3.yaml} (94%) diff --git a/docs/examples/postgres/snapshot/wal-postgres-azure.yaml b/docs/examples/postgres/snapshot/wal-postgres-azure.yaml index 8aa29772c..962052203 100644 --- a/docs/examples/postgres/snapshot/wal-postgres-azure.yaml +++ b/docs/examples/postgres/snapshot/wal-postgres-azure.yaml @@ -12,7 +12,7 @@ spec: - ReadWriteOnce resources: requests: - storage: 50Mi + storage: 1Gi archiver: storage: storageSecretName: azure-secret diff --git a/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml b/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml index ce91d30ee..0924099cc 100644 --- a/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml +++ b/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml @@ -12,7 +12,7 @@ spec: - ReadWriteOnce resources: requests: - storage: 50Mi + storage: 1Gi archiver: storage: storageSecretName: gcs-secret diff --git a/docs/examples/postgres/snapshot/wal-postgres.yaml b/docs/examples/postgres/snapshot/wal-postgres-s3.yaml similarity index 94% rename from docs/examples/postgres/snapshot/wal-postgres.yaml rename to docs/examples/postgres/snapshot/wal-postgres-s3.yaml index 5c758a70c..f2a58f836 100644 --- a/docs/examples/postgres/snapshot/wal-postgres.yaml +++ b/docs/examples/postgres/snapshot/wal-postgres-s3.yaml @@ -4,7 +4,7 @@ metadata: name: wal-postgres namespace: demo spec: - version: "9.6-v2" + version: "11.1-v1" replicas: 2 storage: storageClassName: "standard" From f071b46124307b8a18aa794750a74d40d5ad724e Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:21:38 +0600 Subject: [PATCH 19/25] fixed azure Signed-off-by: iamrz1 --- docs/guides/postgres/snapshot/archiving_to_azure.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md index 95b7bd3b0..0a675b18c 100644 --- a/docs/guides/postgres/snapshot/archiving_to_azure.md +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -50,7 +50,7 @@ spec: storage: storageSecretName: azure-secret azure: - bucket: kubedb + container: kubedb ``` Here, From 7abaab70aa8c8d4443ab1c904e77896eb27c9894 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:25:29 +0600 Subject: [PATCH 20/25] Removed "Before you begin" from first page of archiving Signed-off-by: iamrz1 --- docs/guides/postgres/snapshot/archiving_to_azure.md | 6 ++++++ docs/guides/postgres/snapshot/archiving_to_gcs.md | 6 ++++++ docs/guides/postgres/snapshot/archiving_to_s3.md | 6 ++++++ docs/guides/postgres/snapshot/archiving_to_swift.md | 6 ++++++ docs/guides/postgres/snapshot/continuous_archiving.md | 6 ------ 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md index 0a675b18c..74a821c45 100644 --- a/docs/guides/postgres/snapshot/archiving_to_azure.md +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -19,6 +19,12 @@ section_menu_id: guides ## Before You Begin +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. ```console diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md index f6d776df8..6dd04d219 100644 --- a/docs/guides/postgres/snapshot/archiving_to_gcs.md +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -20,6 +20,12 @@ section_menu_id: guides ## Before You Begin +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. ```console diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index d71c0b6fd..6bbca4f49 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -19,6 +19,12 @@ section_menu_id: guides ## Before You Begin +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. ```console diff --git a/docs/guides/postgres/snapshot/archiving_to_swift.md b/docs/guides/postgres/snapshot/archiving_to_swift.md index 6a159bcf7..7c4fa5d48 100644 --- a/docs/guides/postgres/snapshot/archiving_to_swift.md +++ b/docs/guides/postgres/snapshot/archiving_to_swift.md @@ -20,6 +20,12 @@ section_menu_id: guides ## Before You Begin +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. ```console diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index cafadff64..5259704e3 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -32,13 +32,7 @@ archive_timeout = 60 Here, these commands are used to push files to the cloud. -## Before You Begin -At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). - -Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). - -> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). **List of supported Cloud Providers for PostgresVersion CRDs** From 793d309afb39fbd805259b28d14cdcfec9769810 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:32:01 +0600 Subject: [PATCH 21/25] Fixed front-matter --- docs/guides/postgres/snapshot/archiving_to_azure.md | 4 ++-- docs/guides/postgres/snapshot/archiving_to_gcs.md | 4 ++-- docs/guides/postgres/snapshot/archiving_to_s3.md | 4 ++-- docs/guides/postgres/snapshot/archiving_to_swift.md | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md index 74a821c45..d6a012217 100644 --- a/docs/guides/postgres/snapshot/archiving_to_azure.md +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -3,9 +3,9 @@ title: Continuous Archiving to Azure menu: docs_0.11.0: identifier: pg-continuous-archiving-snapshot - name: WAL Archiving + name: Archiving to Azure parent: pg-snapshot-postgres - weight: 20 + weight: 35 menu_name: docs_0.11.0 section_menu_id: guides diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md index 6dd04d219..d7c66cce2 100644 --- a/docs/guides/postgres/snapshot/archiving_to_gcs.md +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -3,9 +3,9 @@ title: Continuous Archiving to GCS menu: docs_0.11.0: identifier: pg-continuous-archiving-snapshot - name: WAL Archiving + name: Archiving to GCS parent: pg-snapshot-postgres - weight: 20 + weight: 30 menu_name: docs_0.11.0 section_menu_id: guides diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index 6bbca4f49..454c7c539 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -3,9 +3,9 @@ title: Continuous Archiving to S3 menu: docs_0.11.0: identifier: pg-continuous-archiving-snapshot - name: WAL Archiving + name: Archiving to S3 parent: pg-snapshot-postgres - weight: 20 + weight: 25 menu_name: docs_0.11.0 section_menu_id: guides diff --git a/docs/guides/postgres/snapshot/archiving_to_swift.md b/docs/guides/postgres/snapshot/archiving_to_swift.md index 7c4fa5d48..6d2753d45 100644 --- a/docs/guides/postgres/snapshot/archiving_to_swift.md +++ b/docs/guides/postgres/snapshot/archiving_to_swift.md @@ -3,9 +3,9 @@ title: Continuous Archiving to Swift menu: docs_0.11.0: identifier: pg-continuous-archiving-snapshot - name: WAL Archiving + name: Archiving to Swift parent: pg-snapshot-postgres - weight: 20 + weight: 40 menu_name: docs_0.11.0 section_menu_id: guides From a44f312faa204770d496a77ef4c35f1f96c24a24 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 15:35:57 +0600 Subject: [PATCH 22/25] Removed extra spaces --- docs/guides/postgres/snapshot/archiving_to_azure.md | 1 - docs/guides/postgres/snapshot/archiving_to_gcs.md | 2 -- docs/guides/postgres/snapshot/archiving_to_s3.md | 1 - docs/guides/postgres/snapshot/archiving_to_swift.md | 2 -- 4 files changed, 6 deletions(-) diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md index d6a012217..69ea7592f 100644 --- a/docs/guides/postgres/snapshot/archiving_to_azure.md +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -8,7 +8,6 @@ menu: weight: 35 menu_name: docs_0.11.0 section_menu_id: guides - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md index d7c66cce2..f3781afe3 100644 --- a/docs/guides/postgres/snapshot/archiving_to_gcs.md +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -8,8 +8,6 @@ menu: weight: 30 menu_name: docs_0.11.0 section_menu_id: guides - - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index 454c7c539..436859663 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -8,7 +8,6 @@ menu: weight: 25 menu_name: docs_0.11.0 section_menu_id: guides - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). diff --git a/docs/guides/postgres/snapshot/archiving_to_swift.md b/docs/guides/postgres/snapshot/archiving_to_swift.md index 6d2753d45..c05d61732 100644 --- a/docs/guides/postgres/snapshot/archiving_to_swift.md +++ b/docs/guides/postgres/snapshot/archiving_to_swift.md @@ -8,8 +8,6 @@ menu: weight: 40 menu_name: docs_0.11.0 section_menu_id: guides - - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). From b1d43fcfae383d8dcdaf18a70aa777172070793b Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 17:45:47 +0600 Subject: [PATCH 23/25] Spitted Initialization doc Signed-off-by: iamrz1 --- .../initialization/replay-postgres-azure.yaml | 23 ++ .../initialization/replay-postgres-gcs.yaml | 23 ++ ...-postgres.yaml => replay-postgres-s3.yaml} | 2 +- .../initialization/replay-postgres-swift.yaml | 23 ++ .../initialization/replay_from_azure.md | 216 ++++++++++++ .../initialization/replay_from_gcs.md | 216 ++++++++++++ .../postgres/initialization/replay_from_s3.md | 216 ++++++++++++ .../initialization/replay_from_swift.md | 216 ++++++++++++ .../postgres/initialization/wal_source.md | 317 ++---------------- .../postgres/snapshot/continuous_archiving.md | 4 +- 10 files changed, 960 insertions(+), 296 deletions(-) create mode 100644 docs/examples/postgres/initialization/replay-postgres-azure.yaml create mode 100644 docs/examples/postgres/initialization/replay-postgres-gcs.yaml rename docs/examples/postgres/initialization/{replay-postgres.yaml => replay-postgres-s3.yaml} (95%) create mode 100644 docs/examples/postgres/initialization/replay-postgres-swift.yaml create mode 100644 docs/guides/postgres/initialization/replay_from_azure.md create mode 100644 docs/guides/postgres/initialization/replay_from_gcs.md create mode 100644 docs/guides/postgres/initialization/replay_from_s3.md create mode 100644 docs/guides/postgres/initialization/replay_from_swift.md diff --git a/docs/examples/postgres/initialization/replay-postgres-azure.yaml b/docs/examples/postgres/initialization/replay-postgres-azure.yaml new file mode 100644 index 000000000..95ca84661 --- /dev/null +++ b/docs/examples/postgres/initialization/replay-postgres-azure.yaml @@ -0,0 +1,23 @@ +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: azure-secret + azure: + container: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' diff --git a/docs/examples/postgres/initialization/replay-postgres-gcs.yaml b/docs/examples/postgres/initialization/replay-postgres-gcs.yaml new file mode 100644 index 000000000..832b60832 --- /dev/null +++ b/docs/examples/postgres/initialization/replay-postgres-gcs.yaml @@ -0,0 +1,23 @@ +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: gcs-secret + gcs: + bucket: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' diff --git a/docs/examples/postgres/initialization/replay-postgres.yaml b/docs/examples/postgres/initialization/replay-postgres-s3.yaml similarity index 95% rename from docs/examples/postgres/initialization/replay-postgres.yaml rename to docs/examples/postgres/initialization/replay-postgres-s3.yaml index 97365576b..6ce49a0c1 100644 --- a/docs/examples/postgres/initialization/replay-postgres.yaml +++ b/docs/examples/postgres/initialization/replay-postgres-s3.yaml @@ -4,7 +4,7 @@ metadata: name: replay-postgres namespace: demo spec: - version: "9.6-v2" + version: "11.1-v1" replicas: 2 databaseSecret: secretName: wal-postgres-auth diff --git a/docs/examples/postgres/initialization/replay-postgres-swift.yaml b/docs/examples/postgres/initialization/replay-postgres-swift.yaml new file mode 100644 index 000000000..2da0d0212 --- /dev/null +++ b/docs/examples/postgres/initialization/replay-postgres-swift.yaml @@ -0,0 +1,23 @@ +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: swift-secret + swift: + container: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' diff --git a/docs/guides/postgres/initialization/replay_from_azure.md b/docs/guides/postgres/initialization/replay_from_azure.md new file mode 100644 index 000000000..b536176d7 --- /dev/null +++ b/docs/guides/postgres/initialization/replay_from_azure.md @@ -0,0 +1,216 @@ +--- +title: Initialize Postgres from Azure +menu: + docs_0.11.0: + identifier: pg-wal-source-initialization + name: Postgres from Azure + parent: pg-initialization-postgres + weight: 35 +menu_name: docs_0.11.0 +section_menu_id: guides + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). +> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. + +# PostgreSQL Initialization from Azure + +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. +If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare WAL Archive + +We need a WAL archive to perform initialization. If you don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). + +Let's populate the database so that we can verify that the initialized database has the same data. We will `exec` into the database pod and use `psql` command-line tool to create a table. + +At first, find out the primary replica using the following command, + +```console +$ kubectl get pods -n demo --selector="kubedb.com/name=wal-postgres","kubedb.com/role=primary" +NAME READY STATUS RESTARTS AGE +wal-postgres-0 1/1 Running 0 8m +``` + +Now, let's `exec` into the pod and create a table, + +```console +$ kubectl exec -it -n demo wal-postgres-0 sh +# login as "postgres" superuser. +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# create a table +postgres=# CREATE TABLE COMPANY( NAME TEXT NOT NULL, EMPLOYEE INT NOT NULL); +CREATE TABLE + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres + +# quit from the database +postgres=# \q + +# exit from the pod +/ # exit +``` + +Now, we are ready to proceed for rest of the tutorial. + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create Postgres with WAL source + +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. + +The YAML file in this tutorial creates a Postgres object using WAL files from Azure Storage. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: azure-secret + azure: + container: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by`WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `azure` points to Azure storage configuration. + - `azure.container` points to the container/bucket name where archived WAL data is stored. + - `azure.prefix` points to the path of archived WAL data. + +**wal-g** receives archived WAL data from a directory inside the container called `/kubedb/{namespace}/{postgres-name}/archive/`. + +Here, `{namespace}` & `{postgres-name}` indicates Postgres object whose WAL archived data will be replayed. + +> Note: Postgres `replay-postgres` must have same superuser credentials as archived Postgres. In our case, it is `wal-postgres`. + +Now, let's create the Postgres object that's YAML has shown above, + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/initialization/replay-postgres-azure.yaml +postgres.kubedb.com/replay-postgres created +``` + +This will create a new database and will initialize the database from the archived WAL files. + +## Verify Initialization + +Let's verify that the new database has been initialized successfully from the WAL archive. It must contain the table we have created for `wal-postgres` database. + +We will `exec` into new database pod and use `psql` command-line tool to list tables of `postgres` database. + +```console +$ kubectl exec -it -n demo replay-postgres-0 sh +# login as "postgres" superuser +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres +(1 row) + +# quit from the database +postgres=# \q + +# exit from pod +/ # exit +``` + +So, we can see that our new database `replay-postgres` has been initialized successfully and contains the data we had inserted into `wal-postgres`. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/replay-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/replay-postgres + +kubectl delete ns demo +``` + +Also cleanup the resources created for `wal-postgres` following the guide [here](/docs/guides/postgres/snapshot/continuous_archiving.md#cleaning-up). + +## Next Steps + +- Learn about initializing [PostgreSQL with Script](/docs/guides/postgres/initialization/script_source.md). +- Monitor your PostgreSQL database with KubeDB using [built-in Prometheus](/docs/guides/postgres/monitoring/using-builtin-prometheus.md). +- Monitor your PostgreSQL database with KubeDB using [CoreOS Prometheus Operator](/docs/guides/postgres/monitoring/using-coreos-prometheus-operator.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/postgres/initialization/replay_from_gcs.md b/docs/guides/postgres/initialization/replay_from_gcs.md new file mode 100644 index 000000000..63ecaa179 --- /dev/null +++ b/docs/guides/postgres/initialization/replay_from_gcs.md @@ -0,0 +1,216 @@ +--- +title: Initialize Postgres from GCS +menu: + docs_0.11.0: + identifier: pg-wal-source-initialization + name: Postgres from GCS + parent: pg-initialization-postgres + weight: 30 +menu_name: docs_0.11.0 +section_menu_id: guides + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). +> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. + +# PostgreSQL Initialization from GCS + +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. +If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare WAL Archive + +We need a WAL archive to perform initialization. If you don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). + +Let's populate the database so that we can verify that the initialized database has the same data. We will `exec` into the database pod and use `psql` command-line tool to create a table. + +At first, find out the primary replica using the following command, + +```console +$ kubectl get pods -n demo --selector="kubedb.com/name=wal-postgres","kubedb.com/role=primary" +NAME READY STATUS RESTARTS AGE +wal-postgres-0 1/1 Running 0 8m +``` + +Now, let's `exec` into the pod and create a table, + +```console +$ kubectl exec -it -n demo wal-postgres-0 sh +# login as "postgres" superuser. +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# create a table +postgres=# CREATE TABLE COMPANY( NAME TEXT NOT NULL, EMPLOYEE INT NOT NULL); +CREATE TABLE + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres + +# quit from the database +postgres=# \q + +# exit from the pod +/ # exit +``` + +Now, we are ready to proceed for rest of the tutorial. + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create Postgres with WAL source + +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. + +The YAML file in this tutorial creates a Postgres object using WAL files from Google Cloud Storage. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: gcs-secret + gcs: + bucket: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `gcs` points to storage configuration of GCS. + - `gcs.bucket` points to the bucket name where archived WAL data is stored. + - `gcs.prefix` points to the path of archived WAL data. + +**wal-g** receives archived WAL data from a directory inside the bucket called `/kubedb/{namespace}/{postgres-name}/archive/`. + +Here, `{namespace}` & `{postgres-name}` indicates Postgres object whose WAL archived data will be replayed. + +> Note: Postgres `replay-postgres` must have same superuser credentials as archived Postgres. In our case, it is `wal-postgres`. + +Now, let's create the Postgres object that's YAML has shown above, + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/initialization/replay-postgres-gcs.yaml +postgres.kubedb.com/replay-postgres created +``` + +This will create a new database and will initialize the database from the archived WAL files. + +## Verify Initialization + +Let's verify that the new database has been initialized successfully from the WAL archive. It must contain the table we have created for `wal-postgres` database. + +We will `exec` into new database pod and use `psql` command-line tool to list tables of `postgres` database. + +```console +$ kubectl exec -it -n demo replay-postgres-0 sh +# login as "postgres" superuser +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres +(1 row) + +# quit from the database +postgres=# \q + +# exit from pod +/ # exit +``` + +So, we can see that our new database `replay-postgres` has been initialized successfully and contains the data we had inserted into `wal-postgres`. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/replay-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/replay-postgres + +kubectl delete ns demo +``` + +Also cleanup the resources created for `wal-postgres` following the guide [here](/docs/guides/postgres/snapshot/continuous_archiving.md#cleaning-up). + +## Next Steps + +- Learn about initializing [PostgreSQL with Script](/docs/guides/postgres/initialization/script_source.md). +- Monitor your PostgreSQL database with KubeDB using [built-in Prometheus](/docs/guides/postgres/monitoring/using-builtin-prometheus.md). +- Monitor your PostgreSQL database with KubeDB using [CoreOS Prometheus Operator](/docs/guides/postgres/monitoring/using-coreos-prometheus-operator.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/postgres/initialization/replay_from_s3.md b/docs/guides/postgres/initialization/replay_from_s3.md new file mode 100644 index 000000000..9feab357d --- /dev/null +++ b/docs/guides/postgres/initialization/replay_from_s3.md @@ -0,0 +1,216 @@ +--- +title: Initialize Postgres from S3 +menu: + docs_0.11.0: + identifier: pg-wal-source-initialization + name: Postgres from S3 + parent: pg-initialization-postgres + weight: 25 +menu_name: docs_0.11.0 +section_menu_id: guides + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). +> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. + +# PostgreSQL Initialization from S3 + +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. +If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare WAL Archive + +We need a WAL archive to perform initialization. If you don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). + +Let's populate the database so that we can verify that the initialized database has the same data. We will `exec` into the database pod and use `psql` command-line tool to create a table. + +At first, find out the primary replica using the following command, + +```console +$ kubectl get pods -n demo --selector="kubedb.com/name=wal-postgres","kubedb.com/role=primary" +NAME READY STATUS RESTARTS AGE +wal-postgres-0 1/1 Running 0 8m +``` + +Now, let's `exec` into the pod and create a table, + +```console +$ kubectl exec -it -n demo wal-postgres-0 sh +# login as "postgres" superuser. +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# create a table +postgres=# CREATE TABLE COMPANY( NAME TEXT NOT NULL, EMPLOYEE INT NOT NULL); +CREATE TABLE + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres + +# quit from the database +postgres=# \q + +# exit from the pod +/ # exit +``` + +Now, we are ready to proceed for rest of the tutorial. + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create Postgres with WAL source + +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. + +The YAML file in this tutorial creates a Postgres object using WAL files from Amazon S3. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: s3-secret + s3: + bucket: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `s3` points to S3 storage configuration. + - `s3.bucket` points to the bucket name where archived WAL data is stored. + - `s3.prefix` points to the path of archived WAL data. + +**wal-g** receives archived WAL data from a directory inside the bucket called `/kubedb/{namespace}/{postgres-name}/archive/`. + +Here, `{namespace}` & `{postgres-name}` indicates Postgres object whose WAL archived data will be replayed. + +> Note: Postgres `replay-postgres` must have same superuser credentials as archived Postgres. In our case, it is `wal-postgres`. + +Now, let's create the Postgres object that's YAML has shown above, + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/initialization/replay-postgres-s3.yaml +postgres.kubedb.com/replay-postgres created +``` + +This will create a new database and will initialize the database from the archived WAL files. + +## Verify Initialization + +Let's verify that the new database has been initialized successfully from the WAL archive. It must contain the table we have created for `wal-postgres` database. + +We will `exec` into new database pod and use `psql` command-line tool to list tables of `postgres` database. + +```console +$ kubectl exec -it -n demo replay-postgres-0 sh +# login as "postgres" superuser +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres +(1 row) + +# quit from the database +postgres=# \q + +# exit from pod +/ # exit +``` + +So, we can see that our new database `replay-postgres` has been initialized successfully and contains the data we had inserted into `wal-postgres`. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/replay-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/replay-postgres + +kubectl delete ns demo +``` + +Also cleanup the resources created for `wal-postgres` following the guide [here](/docs/guides/postgres/snapshot/continuous_archiving.md#cleaning-up). + +## Next Steps + +- Learn about initializing [PostgreSQL with Script](/docs/guides/postgres/initialization/script_source.md). +- Monitor your PostgreSQL database with KubeDB using [built-in Prometheus](/docs/guides/postgres/monitoring/using-builtin-prometheus.md). +- Monitor your PostgreSQL database with KubeDB using [CoreOS Prometheus Operator](/docs/guides/postgres/monitoring/using-coreos-prometheus-operator.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/postgres/initialization/replay_from_swift.md b/docs/guides/postgres/initialization/replay_from_swift.md new file mode 100644 index 000000000..1f770f814 --- /dev/null +++ b/docs/guides/postgres/initialization/replay_from_swift.md @@ -0,0 +1,216 @@ +--- +title: Initialize Postgres from Swift +menu: + docs_0.11.0: + identifier: pg-wal-source-initialization + name: Postgres from Swift + parent: pg-initialization-postgres + weight: 40 +menu_name: docs_0.11.0 +section_menu_id: guides + +--- + +> New to KubeDB? Please start [here](/docs/concepts/README.md). +> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. + +# PostgreSQL Initialization from Swift + +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. + +## Before You Begin + +At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. +If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). + +Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). + +To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. + +```console +$ kubectl create ns demo +namespace/demo created +``` + +## Prepare WAL Archive + +We need a WAL archive to perform initialization. If you don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). + +Let's populate the database so that we can verify that the initialized database has the same data. We will `exec` into the database pod and use `psql` command-line tool to create a table. + +At first, find out the primary replica using the following command, + +```console +$ kubectl get pods -n demo --selector="kubedb.com/name=wal-postgres","kubedb.com/role=primary" +NAME READY STATUS RESTARTS AGE +wal-postgres-0 1/1 Running 0 8m +``` + +Now, let's `exec` into the pod and create a table, + +```console +$ kubectl exec -it -n demo wal-postgres-0 sh +# login as "postgres" superuser. +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# create a table +postgres=# CREATE TABLE COMPANY( NAME TEXT NOT NULL, EMPLOYEE INT NOT NULL); +CREATE TABLE + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres + +# quit from the database +postgres=# \q + +# exit from the pod +/ # exit +``` + +Now, we are ready to proceed for rest of the tutorial. + +> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). + +## Create Postgres with WAL source + +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. + +The YAML file in this tutorial creates a Postgres object using WAL files from Swift Storage. + +```yaml +apiVersion: kubedb.com/v1alpha1 +kind: Postgres +metadata: + name: replay-postgres + namespace: demo +spec: + version: "11.1-v1" + replicas: 2 + databaseSecret: + secretName: wal-postgres-auth + storage: + storageClassName: "standard" + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 1Gi + init: + postgresWAL: + storageSecretName: swift-secret + swift: + container: kubedb + prefix: 'kubedb/demo/wal-postgres/archive' +``` + +Here, + +- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` + - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. + - `swift` points to Swift storage configuration. + - `swift.container` points to the container/bucket name where archived WAL data is stored. + - `swift.prefix` points to the path of archived WAL data. + +**wal-g** receives archived WAL data from a directory inside the container called `/kubedb/{namespace}/{postgres-name}/archive/`. + +Here, `{namespace}` & `{postgres-name}` indicates Postgres object whose WAL archived data will be replayed. + +> Note: Postgres `replay-postgres` must have same superuser credentials as archived Postgres. In our case, it is `wal-postgres`. + +Now, let's create the Postgres object that's YAML has shown above, + +```console +$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/initialization/replay-postgres-swift.yaml +postgres.kubedb.com/replay-postgres created +``` + +This will create a new database and will initialize the database from the archived WAL files. + +## Verify Initialization + +Let's verify that the new database has been initialized successfully from the WAL archive. It must contain the table we have created for `wal-postgres` database. + +We will `exec` into new database pod and use `psql` command-line tool to list tables of `postgres` database. + +```console +$ kubectl exec -it -n demo replay-postgres-0 sh +# login as "postgres" superuser +/ # psql -U postgres +psql (11.1) +Type "help" for help. + +# list available databases +postgres=# \l + List of databases + Name | Owner | Encoding | Collate | Ctype | Access privileges +-----------+----------+----------+------------+------------+----------------------- + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres + template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + + | | | | | postgres=CTc/postgres +(3 rows) + +# connect to "postgres" database +postgres=# \c postgres +You are now connected to database "postgres" as user "postgres". + +# list tables +postgres=# \d + List of relations + Schema | Name | Type | Owner +--------+---------+-------+---------- + public | company | table | postgres +(1 row) + +# quit from the database +postgres=# \q + +# exit from pod +/ # exit +``` + +So, we can see that our new database `replay-postgres` has been initialized successfully and contains the data we had inserted into `wal-postgres`. + +## Cleaning up + +To cleanup the Kubernetes resources created by this tutorial, run: + +```console +kubectl patch -n demo pg/replay-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" +kubectl delete -n demo pg/replay-postgres + +kubectl delete ns demo +``` + +Also cleanup the resources created for `wal-postgres` following the guide [here](/docs/guides/postgres/snapshot/continuous_archiving.md#cleaning-up). + +## Next Steps + +- Learn about initializing [PostgreSQL with Script](/docs/guides/postgres/initialization/script_source.md). +- Monitor your PostgreSQL database with KubeDB using [built-in Prometheus](/docs/guides/postgres/monitoring/using-builtin-prometheus.md). +- Monitor your PostgreSQL database with KubeDB using [CoreOS Prometheus Operator](/docs/guides/postgres/monitoring/using-coreos-prometheus-operator.md). +- Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/postgres/initialization/wal_source.md b/docs/guides/postgres/initialization/wal_source.md index 9dfcc51b5..2006906dd 100644 --- a/docs/guides/postgres/initialization/wal_source.md +++ b/docs/guides/postgres/initialization/wal_source.md @@ -15,310 +15,39 @@ section_menu_id: guides # PostgreSQL Initialization from WAL files -KubeDB supports PostgreSQL database initialization. When you create a new Postgres object, you can provide existing WAL files to restore from by "replaying" the log entries. +KubeDB supports PostgreSQL database initialization. When you create a new Postgres object, you can provide existing WAL files to restore from by "replaying" the log entries. Users can now restore from any one of `s3`, `gcs`, `azure`, or `swift` as cloud backup provider. -## Before You Begin +**What is this Continuous Archiving** -At first, you need to have a Kubernetes cluster, and the kubectl command-line tool must be configured to communicate with your cluster. -If you do not already have a cluster, you can create one by using [minikube](https://github.com/kubernetes/minikube). +PostgreSQL maintains a write ahead log (WAL) in the `pg_xlog/` subdirectory of the cluster's data directory. The existence of the log makes it possible to restore from the backed-up WAL files to bring the system back to a last known state. -Now, install KubeDB cli on your workstation and KubeDB operator in your cluster following the steps [here](/docs/setup/install.md). +To know more about continuous archiving, please refer to the [ofiicial postgres document](https://www.postgresql.org/docs/10/continuous-archiving.html) on this topic. -To keep things isolated, this tutorial uses a separate namespace called `demo` throughout this tutorial. +**List of supported Cloud Providers for PostgresVersion CRDs** -```console -$ kubectl create ns demo -namespace/demo created -``` +| Name | Version | S3 | GCS | Azure | Swift | +| :------: | :-----: | :--: | :--: | :---: | :---: | +| 9.6-v2 | 9.6 | ✓ | ✓ | ✗ | ✗ | +| 9.6.7-v2 | 9.6.7 | ✓ | ✓ | ✗ | ✗ | +| 10.2-v2 | 10.2 | ✓ | ✓ | ✗ | ✗ | +| 10.6 | 10.6 | ✓ | ✓ | ✗ | ✗ | +| 11.1 | 11.1 | ✓ | ✓ | ✗ | ✗ | +| 9.6-v3 | 9.6 | ✓ | ✓ | ✓ | ✓ | +| 9.6.7-v3 | 9.6.7 | ✓ | ✓ | ✓ | ✓ | +| 10.2-v3 | 10.2 | ✓ | ✓ | ✓ | ✓ | +| 10.6-v1 | 10.6 | ✓ | ✓ | ✓ | ✓ | +| 11.1-v1 | 11.1 | ✓ | ✓ | ✓ | ✓ | -## Prepare WAL Archive - -We need a WAL archive to perform initialization. If you don't have a WAL archive ready, create one by following the tutorial [here](/docs/guides/postgres/snapshot/continuous_archiving.md). - -Let's populate the database so that we can verify that the initialized database has the same data. We will `exec` into the database pod and use `psql` command-line tool to create a table. - -At first, find out the primary replica using the following command, - -```console -$ kubectl get pods -n demo --selector="kubedb.com/name=wal-postgres","kubedb.com/role=primary" -NAME READY STATUS RESTARTS AGE -wal-postgres-0 1/1 Running 0 8m -``` - -Now, let's `exec` into the pod and create a table, - -```console -$ kubectl exec -it -n demo wal-postgres-0 sh -# login as "postgres" superuser. -/ # psql -U postgres -psql (9.6.7) -Type "help" for help. - -# list available databases -postgres=# \l - List of databases - Name | Owner | Encoding | Collate | Ctype | Access privileges ------------+----------+----------+------------+------------+----------------------- - postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | - template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + - | | | | | postgres=CTc/postgres - template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + - | | | | | postgres=CTc/postgres -(3 rows) - -# connect to "postgres" database -postgres=# \c postgres -You are now connected to database "postgres" as user "postgres". - -# create a table -postgres=# CREATE TABLE COMPANY( NAME TEXT NOT NULL, EMPLOYEE INT NOT NULL); -CREATE TABLE - -# list tables -postgres=# \d - List of relations - Schema | Name | Type | Owner ---------+---------+-------+---------- - public | company | table | postgres - -# quit from the database -postgres=# \q - -# exit from the pod -/ # exit -``` - -Now, we are ready to proceed for rest of the tutorial. - -> Note: YAML files used in this tutorial are stored in [docs/examples/postgres](https://github.com/kubedb/cli/tree/master/docs/examples/postgres) folder in GitHub repository [kubedb/cli](https://github.com/kubedb/cli). - -## Create Postgres with WAL source - -We can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. User can use any of S3, GCS, Azure, or Swift WAL archiver for init. - -Here, the YAML of Postgres object that we are going to create in this tutorial, uses S3 as the cloud backup provider. - -```yaml -apiVersion: kubedb.com/v1alpha1 -kind: Postgres -metadata: - name: replay-postgres - namespace: demo -spec: - version: "11.1-v1" - replicas: 2 - databaseSecret: - secretName: wal-postgres-auth - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - init: - postgresWAL: - storageSecretName: s3-secret - s3: - bucket: kubedb - prefix: 'kubedb/demo/wal-postgres/archive' -``` - -Here, - -- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` - - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `s3` points to S3 storage configuration. - - `s3.bucket` points to the bucket name where archived WAL data is stored. - - `s3.prefix` points to the path of archived WAL data. - -Here is a YAML of Postgres object that uses GCS as the cloud backup provider. - -```yaml -apiVersion: kubedb.com/v1alpha1 -kind: Postgres -metadata: - name: replay-postgres - namespace: demo -spec: - version: "11.1-v1" - replicas: 2 - databaseSecret: - secretName: wal-postgres-auth - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - init: - postgresWAL: - storageSecretName: gcs-secret - gcs: - bucket: kubedb - prefix: 'kubedb/demo/wal-postgres/archive' -``` - -Here, - -- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` - - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `gcs` points to storage configuration of GCS. - - `gcs.bucket` points to the bucket name where archived WAL data is stored. - - `gcs.prefix` points to the path of archived WAL data. - -Here is another YAML of Postgres object that uses Azure as the cloud backup provider. - -```yaml -apiVersion: kubedb.com/v1alpha1 -kind: Postgres -metadata: - name: replay-postgres - namespace: demo -spec: - version: "11.1-v1" - replicas: 2 - databaseSecret: - secretName: wal-postgres-auth - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - init: - postgresWAL: - storageSecretName: azure-secret - azure: - container: kubedb - prefix: 'kubedb/demo/wal-postgres/archive' -``` - -Here, - -- `spec.init.postgresWAL` specifies storage information that will be used by`WAL-G` - - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `azure` points to Azure storage configuration. - - `azure.container` points to the container/bucket name where archived WAL data is stored. - - `azure.prefix` points to the path of archived WAL data. - -And this yet another YAML of Postgres object that uses Swift as it's cloud backup provider. - -```yaml -apiVersion: kubedb.com/v1alpha1 -kind: Postgres -metadata: - name: replay-postgres - namespace: demo -spec: - version: "11.1-v1" - replicas: 2 - databaseSecret: - secretName: wal-postgres-auth - storage: - storageClassName: "standard" - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 1Gi - init: - postgresWAL: - storageSecretName: swift-secret - swift: - container: kubedb - prefix: 'kubedb/demo/wal-postgres/archive' -``` - -Here, - -- `spec.init.postgresWAL` specifies storage information that will be used by `WAL-G` - - `storageSecretName` points to the Secret containing the credentials for cloud storage destination. - - `swift` points to Swift storage configuration. - - `swift.container` points to the container/bucket name where archived WAL data is stored. - - `swift.prefix` points to the path of archived WAL data. - - - -**wal-g** receives archived WAL data from a directory inside the bucket/container called `/kubedb/{namespace}/{postgres-name}/archive/`. - -Here, `{namespace}` & `{postgres-name}` indicates Postgres object whose WAL archived data will be replayed. - -> Note: Postgres `replay-postgres` must have same superuser credentials as archived Postgres. In our case, it is `wal-postgres`. - -Now, let's create the Postgres object that's YAML has shown above, - -```console -$ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/initialization/replay-postgres.yaml -postgres.kubedb.com/replay-postgres created -``` - -This will create a new database and will initialize the database from the archived WAL files. - -## Verify Initialization - -Let's verify that the new database has been initialized successfully from the WAL archive. It must contain the table we have created for `wal-postgres` database. - -We will `exec` into new database pod and use `psql` command-line tool to list tables of `postgres` database. - -```console -$ kubectl exec -it -n demo replay-postgres-0 sh -# login as "postgres" superuser -/ # psql -U postgres -psql (9.6.7) -Type "help" for help. - -# list available databases -postgres=# \l - List of databases - Name | Owner | Encoding | Collate | Ctype | Access privileges ------------+----------+----------+------------+------------+----------------------- - postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | - template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + - | | | | | postgres=CTc/postgres - template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + - | | | | | postgres=CTc/postgres -(3 rows) - -# connect to "postgres" database -postgres=# \c postgres -You are now connected to database "postgres" as user "postgres". - -# list tables -postgres=# \d - List of relations - Schema | Name | Type | Owner ---------+---------+-------+---------- - public | company | table | postgres -(1 row) - -# quit from the database -postgres=# \q - -# exit from pod -/ # exit -``` - -So, we can see that our new database `replay-postgres` has been initialized successfully and contains the data we had inserted into `wal-postgres`. - -## Cleaning up - -To cleanup the Kubernetes resources created by this tutorial, run: - -```console -kubectl patch -n demo pg/replay-postgres -p '{"spec":{"terminationPolicy":"WipeOut"}}' --type="merge" -kubectl delete -n demo pg/replay-postgres - -kubectl delete ns demo -``` - -Also cleanup the resources created for `wal-postgres` following the guide [here](/docs/guides/postgres/snapshot/continuous_archiving.md#cleaning-up). +Users can use supported cloud providers to replay existing WAL files to restore a backed-up database. KubeDB currently supports *restoring from* [Amazon S3](/docs/guides/postgres/initialization/replay_from_s3.md), [Google Cloud Storage](/docs/guides/postgres/initialization/replay_from_gcs.md), [Azure Storage](/docs/guides/postgres/initialization/replay_from_azure.md), and [OpenStack Object Storage (Swift)](/docs/guides/postgres/initialization/replay_from_swift.md). ## Next Steps +- Learn about restoring from [Amazon S3](/docs/guides/postgres/initialization/replay_from_s3.md). +- Learn about restoring from [Google Cloud Storage](/docs/guides/postgres/initialization/replay_from_gcs.md). +- Learn about restoring from [Azure Storage](/docs/guides/postgres/initialization/replay_from_azure.md). +- Learn about restoring from [OpenStack Object Storage (Swift)](/docs/guides/postgres/initialization/replay_from_swift.md). - Learn about initializing [PostgreSQL with Script](/docs/guides/postgres/initialization/script_source.md). - Monitor your PostgreSQL database with KubeDB using [built-in Prometheus](/docs/guides/postgres/monitoring/using-builtin-prometheus.md). - Monitor your PostgreSQL database with KubeDB using [CoreOS Prometheus Operator](/docs/guides/postgres/monitoring/using-coreos-prometheus-operator.md). - Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). + diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index 5259704e3..e402a0996 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -34,7 +34,7 @@ Here, these commands are used to push files to the cloud. -**List of supported Cloud Providers for PostgresVersion CRDs** +**List of supported Cloud Destination for PostgresVersion CRDs** | Name | Version | S3 | GCS | Azure | Swift | | :------: | :-----: | :--: | :--: | :---: | :---: | @@ -49,6 +49,8 @@ Here, these commands are used to push files to the cloud. | 10.6-v1 | 10.6 | ✓ | ✓ | ✓ | ✓ | | 11.1-v1 | 11.1 | ✓ | ✓ | ✓ | ✓ | +Users can use supported cloud destinations to backup WAL files to restore whaen needed. KubeDB currently supports *archiving to* [Amazon S3](/docs/guides/postgres/snapshot/archiving_to_s3.md), [Google Cloud Storage](/docs/guides/postgres/snapshot/archiving_to_gcs.md), [Azure Storage](/docs/guides/postgres/snapshot/archiving_to_azure.md), and [OpenStack Object Storage (Swift)](/docs/guides/postgres/snapshot/archiving_to_swift.md). + ## Next Steps - Learn about archiving to [Amazon S3](/docs/guides/postgres/snapshot/archiving_to_s3.md). From 9fc1b4262a989ebd5bf476d4c46b3d3436a66908 Mon Sep 17 00:00:00 2001 From: iamrz1 Date: Fri, 22 Mar 2019 17:49:21 +0600 Subject: [PATCH 24/25] minor fix --- docs/guides/postgres/initialization/replay_from_azure.md | 3 +-- docs/guides/postgres/initialization/replay_from_gcs.md | 3 +-- docs/guides/postgres/initialization/replay_from_s3.md | 3 +-- docs/guides/postgres/initialization/replay_from_swift.md | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/docs/guides/postgres/initialization/replay_from_azure.md b/docs/guides/postgres/initialization/replay_from_azure.md index b536176d7..7f89abaa7 100644 --- a/docs/guides/postgres/initialization/replay_from_azure.md +++ b/docs/guides/postgres/initialization/replay_from_azure.md @@ -2,13 +2,12 @@ title: Initialize Postgres from Azure menu: docs_0.11.0: - identifier: pg-wal-source-initialization + identifier: pg-wal-source-initialization-azure name: Postgres from Azure parent: pg-initialization-postgres weight: 35 menu_name: docs_0.11.0 section_menu_id: guides - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). diff --git a/docs/guides/postgres/initialization/replay_from_gcs.md b/docs/guides/postgres/initialization/replay_from_gcs.md index 63ecaa179..cad5f636a 100644 --- a/docs/guides/postgres/initialization/replay_from_gcs.md +++ b/docs/guides/postgres/initialization/replay_from_gcs.md @@ -2,13 +2,12 @@ title: Initialize Postgres from GCS menu: docs_0.11.0: - identifier: pg-wal-source-initialization + identifier: pg-wal-source-initialization-gcs name: Postgres from GCS parent: pg-initialization-postgres weight: 30 menu_name: docs_0.11.0 section_menu_id: guides - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). diff --git a/docs/guides/postgres/initialization/replay_from_s3.md b/docs/guides/postgres/initialization/replay_from_s3.md index 9feab357d..7c766078c 100644 --- a/docs/guides/postgres/initialization/replay_from_s3.md +++ b/docs/guides/postgres/initialization/replay_from_s3.md @@ -2,13 +2,12 @@ title: Initialize Postgres from S3 menu: docs_0.11.0: - identifier: pg-wal-source-initialization + identifier: pg-wal-source-initialization-s3 name: Postgres from S3 parent: pg-initialization-postgres weight: 25 menu_name: docs_0.11.0 section_menu_id: guides - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). diff --git a/docs/guides/postgres/initialization/replay_from_swift.md b/docs/guides/postgres/initialization/replay_from_swift.md index 1f770f814..0ae12b4f0 100644 --- a/docs/guides/postgres/initialization/replay_from_swift.md +++ b/docs/guides/postgres/initialization/replay_from_swift.md @@ -2,13 +2,12 @@ title: Initialize Postgres from Swift menu: docs_0.11.0: - identifier: pg-wal-source-initialization + identifier: pg-wal-source-initialization-swift name: Postgres from Swift parent: pg-initialization-postgres weight: 40 menu_name: docs_0.11.0 section_menu_id: guides - --- > New to KubeDB? Please start [here](/docs/concepts/README.md). From db00bb88751732af68cf27cc366afd2c9e354f68 Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Sat, 23 Mar 2019 07:50:33 -0700 Subject: [PATCH 25/25] various fixes --- .../{pitr.md => point-in-time-recovery.md} | 10 +++--- .../initialization/replay_from_azure.md | 6 ++-- .../initialization/replay_from_gcs.md | 6 ++-- .../postgres/initialization/replay_from_s3.md | 6 ++-- .../initialization/replay_from_swift.md | 6 ++-- .../postgres/initialization/wal_source.md | 9 ++--- .../postgres/snapshot/archiving_to_azure.md | 17 ++++----- .../postgres/snapshot/archiving_to_gcs.md | 12 +++---- .../postgres/snapshot/archiving_to_s3.md | 14 ++++---- .../postgres/snapshot/archiving_to_swift.md | 36 +++++++++++-------- .../postgres/snapshot/continuous_archiving.md | 11 ++---- 11 files changed, 65 insertions(+), 68 deletions(-) rename docs/guides/postgres/initialization/{pitr.md => point-in-time-recovery.md} (97%) diff --git a/docs/guides/postgres/initialization/pitr.md b/docs/guides/postgres/initialization/point-in-time-recovery.md similarity index 97% rename from docs/guides/postgres/initialization/pitr.md rename to docs/guides/postgres/initialization/point-in-time-recovery.md index 1008e3dec..ebac6841b 100644 --- a/docs/guides/postgres/initialization/pitr.md +++ b/docs/guides/postgres/initialization/point-in-time-recovery.md @@ -125,9 +125,9 @@ Type "help" for help. # list available databases postgres=# \l List of databases - Name | Owner | Encoding | Collate | Ctype | Access privileges + Name | Owner | Encoding | Collate | Ctype | Access privileges -----------+----------+----------+------------+------------+----------------------- - postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | + postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres + @@ -157,7 +157,7 @@ INSERT 0 1 # let's view the inserted data. check "created_at" column. # we are going to use this timestamp for point-in-time recovery. postgres=# select * from pitrDemo; - id | message | created_at + id | message | created_at ----+---------------+------------------------------- 1 | row 1 created | 2019-01-07 08:28:58.752729+00 2 | row 2 created | 2019-01-07 08:39:36.77533+00 @@ -241,7 +241,7 @@ psql (10.2) Type "help" for help. postgres=# select * from pitrDemo; - id | message | created_at + id | message | created_at ----+---------------+------------------------------- 1 | row 1 created | 2019-01-07 08:28:58.752729+00 (1 row) @@ -308,7 +308,7 @@ psql (10.2) Type "help" for help. postgres=# select * from pitrDemo; - id | message | created_at + id | message | created_at ----+---------------+------------------------------- 1 | row 1 created | 2019-01-07 08:28:58.752729+00 2 | row 2 created | 2019-01-07 08:39:36.77533+00 diff --git a/docs/guides/postgres/initialization/replay_from_azure.md b/docs/guides/postgres/initialization/replay_from_azure.md index 7f89abaa7..751f9bb17 100644 --- a/docs/guides/postgres/initialization/replay_from_azure.md +++ b/docs/guides/postgres/initialization/replay_from_azure.md @@ -11,11 +11,11 @@ section_menu_id: guides --- > New to KubeDB? Please start [here](/docs/concepts/README.md). -> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. +> Don't know how to take continuous backup? Check this [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. # PostgreSQL Initialization from Azure -**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in KubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. ## Before You Begin @@ -94,7 +94,7 @@ Now, we are ready to proceed for rest of the tutorial. ## Create Postgres with WAL source -User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. The YAML file in this tutorial creates a Postgres object using WAL files from Azure Storage. diff --git a/docs/guides/postgres/initialization/replay_from_gcs.md b/docs/guides/postgres/initialization/replay_from_gcs.md index cad5f636a..d0fbbc4ef 100644 --- a/docs/guides/postgres/initialization/replay_from_gcs.md +++ b/docs/guides/postgres/initialization/replay_from_gcs.md @@ -11,11 +11,11 @@ section_menu_id: guides --- > New to KubeDB? Please start [here](/docs/concepts/README.md). -> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. +> Don't know how to take continuous backup? Check this [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. # PostgreSQL Initialization from GCS -**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in KubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. ## Before You Begin @@ -94,7 +94,7 @@ Now, we are ready to proceed for rest of the tutorial. ## Create Postgres with WAL source -User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. The YAML file in this tutorial creates a Postgres object using WAL files from Google Cloud Storage. diff --git a/docs/guides/postgres/initialization/replay_from_s3.md b/docs/guides/postgres/initialization/replay_from_s3.md index 7c766078c..b2e11b036 100644 --- a/docs/guides/postgres/initialization/replay_from_s3.md +++ b/docs/guides/postgres/initialization/replay_from_s3.md @@ -11,11 +11,11 @@ section_menu_id: guides --- > New to KubeDB? Please start [here](/docs/concepts/README.md). -> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. +> Don't know how to take continuous backup? Check this [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. # PostgreSQL Initialization from S3 -**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in KubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. ## Before You Begin @@ -94,7 +94,7 @@ Now, we are ready to proceed for rest of the tutorial. ## Create Postgres with WAL source -User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. The YAML file in this tutorial creates a Postgres object using WAL files from Amazon S3. diff --git a/docs/guides/postgres/initialization/replay_from_swift.md b/docs/guides/postgres/initialization/replay_from_swift.md index 0ae12b4f0..a64633335 100644 --- a/docs/guides/postgres/initialization/replay_from_swift.md +++ b/docs/guides/postgres/initialization/replay_from_swift.md @@ -11,11 +11,11 @@ section_menu_id: guides --- > New to KubeDB? Please start [here](/docs/concepts/README.md). -> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. +> Don't know how to take continuous backup? Check this [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. # PostgreSQL Initialization from Swift -**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in kubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. +**WAL-G** is used to handle replay, and restoration mechanism. Please refer to [Initialization from WAL files in KubeDB](/docs/guides/postgres/initialization/wal_source.md) to know more about it. ## Before You Begin @@ -94,7 +94,7 @@ Now, we are ready to proceed for rest of the tutorial. ## Create Postgres with WAL source -User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. +User can initialize a new database from this archived WAL files. We have to specify the archive backend in the `spec.init.postgresWAL` field of Postgres object. The YAML file in this tutorial creates a Postgres object using WAL files from Swift Storage. diff --git a/docs/guides/postgres/initialization/wal_source.md b/docs/guides/postgres/initialization/wal_source.md index 2006906dd..385ffb02b 100644 --- a/docs/guides/postgres/initialization/wal_source.md +++ b/docs/guides/postgres/initialization/wal_source.md @@ -11,13 +11,13 @@ section_menu_id: guides --- > New to KubeDB? Please start [here](/docs/concepts/README.md). -> Don't know how to take continuous backup? Check [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. +> Don't know how to take continuous backup? Check this [tutorial](/docs/guides/postgres/snapshot/continuous_archiving.md) on Continuous Archiving. # PostgreSQL Initialization from WAL files -KubeDB supports PostgreSQL database initialization. When you create a new Postgres object, you can provide existing WAL files to restore from by "replaying" the log entries. Users can now restore from any one of `s3`, `gcs`, `azure`, or `swift` as cloud backup provider. +KubeDB supports PostgreSQL database initialization. When you create a new Postgres object, you can provide existing WAL files to restore from by "replaying" the log entries. Users can now restore from any one of `s3`, `gcs`, `azure`, or `swift` as cloud backup provider. -**What is this Continuous Archiving** +**What is Continuous Archiving** PostgreSQL maintains a write ahead log (WAL) in the `pg_xlog/` subdirectory of the cluster's data directory. The existence of the log makes it possible to restore from the backed-up WAL files to bring the system back to a last known state. @@ -38,8 +38,6 @@ To know more about continuous archiving, please refer to the [ofiicial postgres | 10.6-v1 | 10.6 | ✓ | ✓ | ✓ | ✓ | | 11.1-v1 | 11.1 | ✓ | ✓ | ✓ | ✓ | -Users can use supported cloud providers to replay existing WAL files to restore a backed-up database. KubeDB currently supports *restoring from* [Amazon S3](/docs/guides/postgres/initialization/replay_from_s3.md), [Google Cloud Storage](/docs/guides/postgres/initialization/replay_from_gcs.md), [Azure Storage](/docs/guides/postgres/initialization/replay_from_azure.md), and [OpenStack Object Storage (Swift)](/docs/guides/postgres/initialization/replay_from_swift.md). - ## Next Steps - Learn about restoring from [Amazon S3](/docs/guides/postgres/initialization/replay_from_s3.md). @@ -50,4 +48,3 @@ Users can use supported cloud providers to replay existing WAL files to restore - Monitor your PostgreSQL database with KubeDB using [built-in Prometheus](/docs/guides/postgres/monitoring/using-builtin-prometheus.md). - Monitor your PostgreSQL database with KubeDB using [CoreOS Prometheus Operator](/docs/guides/postgres/monitoring/using-coreos-prometheus-operator.md). - Want to hack on KubeDB? Check our [contribution guidelines](/docs/CONTRIBUTING.md). - diff --git a/docs/guides/postgres/snapshot/archiving_to_azure.md b/docs/guides/postgres/snapshot/archiving_to_azure.md index 69ea7592f..6b06de4d7 100644 --- a/docs/guides/postgres/snapshot/archiving_to_azure.md +++ b/docs/guides/postgres/snapshot/archiving_to_azure.md @@ -14,7 +14,7 @@ section_menu_id: guides # Continuous Archiving to Azure -**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. +**WAL-G** is used to continuously archive PostgreSQL WAL files. Please refer to [continuous archiving in KubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to learn more about it. ## Before You Begin @@ -104,14 +104,14 @@ type: Opaque **Archiver Storage Backend** -To configure GCS backend, following parameters are available: +To configure Azure backend, following parameters are available: -| Parameter | Description | -| ---------------------- | ------------------------------------------------------------ | -| `spec.azure.container` | `Required`. Name of Storage container | -| `spec.azure.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | +| Parameter | Description | +| --------------------------------------- | ------------------------------------------------------------ | +| `spec.archiver.storage.azure.container` | `Required`. Name of Storage container | +| `spec.archiver.storage.azure.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | -Now create this Postgres object with Continuous Archiving support. +Now create this Postgres object with continuous archiving support. ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-azure.yaml @@ -130,8 +130,6 @@ You can see continuous archiving data stored in azure container.

- - From the above image, you can see that the archived data is stored in a folder `kubedb/kubedb/demo/wal-postgres/archive`. ## Termination Policy @@ -155,4 +153,3 @@ kubectl delete ns demo ## Next Steps - Learn about initializing [PostgreSQL from WAL](/docs/guides/postgres/initialization/script_source.md) files stored in cloud. - diff --git a/docs/guides/postgres/snapshot/archiving_to_gcs.md b/docs/guides/postgres/snapshot/archiving_to_gcs.md index f3781afe3..e493ae70f 100644 --- a/docs/guides/postgres/snapshot/archiving_to_gcs.md +++ b/docs/guides/postgres/snapshot/archiving_to_gcs.md @@ -14,7 +14,7 @@ section_menu_id: guides # Continuous Archiving to GCS -**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. +**WAL-G** is used to continuously archive PostgreSQL WAL files. Please refer to [continuous archiving in KubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to learn more about it. ## Before You Begin @@ -106,12 +106,12 @@ type: Opaque To configure GCS backend, following parameters are available: -| Parameter | Description | -| ----------------- | ------------------------------------------------------------ | -| `spec.gcs.bucket` | `Required`. Name of Bucket | -| `spec.gcs.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | +| Parameter | Description | +| ---------------------------------- | ------------------------------------------------------------ | +| `spec.archiver.storage.gcs.bucket` | `Required`. Name of Bucket | +| `spec.archiver.storage.gcs.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | -Now create this Postgres object with Continuous Archiving support. +Now create this Postgres object with continuous archiving support. ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-gcs.yaml diff --git a/docs/guides/postgres/snapshot/archiving_to_s3.md b/docs/guides/postgres/snapshot/archiving_to_s3.md index 436859663..e62506829 100644 --- a/docs/guides/postgres/snapshot/archiving_to_s3.md +++ b/docs/guides/postgres/snapshot/archiving_to_s3.md @@ -14,7 +14,7 @@ section_menu_id: guides # Continuous Archiving to S3 -**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. +**WAL-G** is used to continuously archive PostgreSQL WAL files. Please refer to [continuous archiving in KubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to learn more about it. ## Before You Begin @@ -106,13 +106,13 @@ type: Opaque To configure s3 backend, following parameters are available: -| Parameter | Description | -| ------------------ | ------------------------------------------------------------ | -| `spec.s3.endpoint` | `Required`. For S3, use `s3.amazonaws.com` | -| `spec.s3.bucket` | `Required`. Name of Bucket | -| `spec.s3.prefix` | `Optional`. Path prefix into bucket where snapshot will be stores | +| Parameter | Description | +| ----------------------------------- | ------------------------------------------------------------ | +| `spec.archiver.storage.s3.endpoint` | `Required`. For S3, use `s3.amazonaws.com` | +| `spec.archiver.storage.s3.bucket` | `Required`. Name of Bucket | +| `spec.archiver.storage.s3.prefix` | `Optional`. Path prefix into bucket where snapshot will be stores | -Now create this Postgres object with Continuous Archiving support. +Now create this Postgres object with continuous archiving support. ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-s3.yaml diff --git a/docs/guides/postgres/snapshot/archiving_to_swift.md b/docs/guides/postgres/snapshot/archiving_to_swift.md index c05d61732..c0a6bca7d 100644 --- a/docs/guides/postgres/snapshot/archiving_to_swift.md +++ b/docs/guides/postgres/snapshot/archiving_to_swift.md @@ -14,7 +14,7 @@ section_menu_id: guides # Continuous Archiving to Swift -**WAL-G** is used to handle continuous archiving mechanism. Please refer to [continuous archiving in kubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to know more about it. +**WAL-G** is used to continuously archive PostgreSQL WAL files. Please refer to [continuous archiving in KubeDB](/docs/guides/postgres/snapshot/continuous_archiving.md) to learn more about it. ## Before You Begin @@ -50,12 +50,12 @@ spec: - ReadWriteOnce resources: requests: - storage: 1Gi + storage: 50Mi archiver: storage: storageSecretName: swift-secret - gcs: - bucket: kubedb + swift: + container: kubedb ``` Here, @@ -93,11 +93,19 @@ Storage Secret for **WAL-G** is needed with the full set of v1, v2 or v3 authent | `OS_AUTH_TOKEN` | For authentication based on tokens | ```console -$ echo -n '' > AZURE_ACCOUNT_NAME -$ echo -n '' > AZURE_ACCOUNT_KEY +$ echo -n '' > OS_AUTH_URL +$ echo -n '' > OS_TENANT_ID +$ echo -n '' > OS_TENANT_NAME +$ echo -n '' > OS_USERNAME +$ echo -n '' > OS_PASSWORD +$ echo -n '' > OS_REGION_NAME $ kubectl create secret generic swift-secret \ - --from-file=./AZURE_ACCOUNT_NAME \ - --from-file=./AZURE_ACCOUNT_KEY + --from-file=./OS_AUTH_URL \ + --from-file=./OS_TENANT_ID \ + --from-file=./OS_TENANT_NAME \ + --from-file=./OS_USERNAME \ + --from-file=./OS_PASSWORD \ + --from-file=./OS_REGION_NAME secret "swift-secret" created ``` @@ -124,14 +132,14 @@ type: Opaqu **Archiver Storage Backend** -To configure GCS backend, following parameters are available: +To configure Swift backend, following parameters are available: -| Parameter | Description | -| ---------------------- | ------------------------------------------------------------ | -| `spec.azure.container` | `Required`. Name of Storage container | -| `spec.azure.prefix` | `Optional`. Path prefix into bucket where snapshot will be stored | +| Parameter | Description | +| --------------------------------------- | ------------------------------------------------------------ | +| `spec.archiver.storage.swift.container` | `Required`. Name of Storage container | +| `spec.archiver.storage.swift.prefix` | `Optional`. Path prefix into container where snapshot will be stored | -Now create this Postgres object with Continuous Archiving support. +Now create this Postgres object with continuous archiving support. ```console $ kubectl create -f https://raw.githubusercontent.com/kubedb/cli/0.11.0/docs/examples/postgres/snapshot/wal-postgres-swift.yaml diff --git a/docs/guides/postgres/snapshot/continuous_archiving.md b/docs/guides/postgres/snapshot/continuous_archiving.md index e402a0996..3cc35ab23 100644 --- a/docs/guides/postgres/snapshot/continuous_archiving.md +++ b/docs/guides/postgres/snapshot/continuous_archiving.md @@ -9,13 +9,14 @@ menu: menu_name: docs_0.11.0 section_menu_id: guides --- + > New to KubeDB? Please start [here](/docs/concepts/README.md). # Continuous Archiving with WAL-G -KubeDB also supports continuous archiving of PostgreSQL using [WAL-G ](https://github.com/wal-g/wal-g). Users can now use any one of `s3`, `gcs`, `azure`, or `swift` as cloud storage destination. +KubeDB supports continuous archiving of PostgreSQL WAL files using [WAL-G ](https://github.com/wal-g/wal-g). You can use `s3`, `gcs`, `azure`, or `swift` to store the WAL files. -**What is this Continuous Archiving** +**What is Continuous Archiving** PostgreSQL maintains a write ahead log (WAL) in the `pg_xlog/` subdirectory of the cluster's data directory. The existence of the log makes it possible to use a third strategy for backing up databases and if recovery is needed, restore from the backed-up WAL files to bring the system back to last known state. @@ -30,10 +31,6 @@ archive_command = 'wal-g wal-push %p' archive_timeout = 60 ``` -Here, these commands are used to push files to the cloud. - - - **List of supported Cloud Destination for PostgresVersion CRDs** | Name | Version | S3 | GCS | Azure | Swift | @@ -49,8 +46,6 @@ Here, these commands are used to push files to the cloud. | 10.6-v1 | 10.6 | ✓ | ✓ | ✓ | ✓ | | 11.1-v1 | 11.1 | ✓ | ✓ | ✓ | ✓ | -Users can use supported cloud destinations to backup WAL files to restore whaen needed. KubeDB currently supports *archiving to* [Amazon S3](/docs/guides/postgres/snapshot/archiving_to_s3.md), [Google Cloud Storage](/docs/guides/postgres/snapshot/archiving_to_gcs.md), [Azure Storage](/docs/guides/postgres/snapshot/archiving_to_azure.md), and [OpenStack Object Storage (Swift)](/docs/guides/postgres/snapshot/archiving_to_swift.md). - ## Next Steps - Learn about archiving to [Amazon S3](/docs/guides/postgres/snapshot/archiving_to_s3.md).