From f1b83ad009ce6d4d9035444b651aaf126e393683 Mon Sep 17 00:00:00 2001 From: Mike Ditton Date: Mon, 10 Nov 2025 10:34:06 +0100 Subject: [PATCH 1/6] Add files from upstream chart This copies the upstream helmchart for provisioning a cnpg cluster as-is without any modifications. --- charts/vshnpostgresql/Chart.yaml | 34 + charts/vshnpostgresql/README.md | 311 ++++++++ charts/vshnpostgresql/README.md.gotmpl | 158 ++++ charts/vshnpostgresql/docs/Getting Started.md | 106 +++ charts/vshnpostgresql/docs/Recovery.md | 27 + .../docs/runbooks/CNPGClusterHACritical.md | 49 ++ .../docs/runbooks/CNPGClusterHAWarning.md | 51 ++ .../CNPGClusterHighConnectionsCritical.md | 24 + .../CNPGClusterHighConnectionsWarning.md | 24 + .../runbooks/CNPGClusterHighReplicationLag.md | 31 + .../CNPGClusterInstancesOnSameNode.md | 28 + .../CNPGClusterLowDiskSpaceCritical.md | 31 + .../CNPGClusterLowDiskSpaceWarning.md | 31 + .../docs/runbooks/CNPGClusterOffline.md | 43 ++ .../runbooks/CNPGClusterZoneSpreadWarning.md | 37 + charts/vshnpostgresql/examples/basic.yaml | 8 + .../examples/custom-queries.yaml | 24 + .../examples/image-catalog-ref.yaml | 12 + .../examples/image-catalog.yaml | 14 + charts/vshnpostgresql/examples/pgbouncer.yaml | 34 + charts/vshnpostgresql/examples/postgis.yaml | 9 + .../examples/recovery-backup.yaml | 23 + .../examples/recovery-object_store.yaml | 31 + .../examples/recovery-pg_basebackup.yaml | 15 + .../examples/standalone-s3.yaml | 20 + .../vshnpostgresql/examples/timescaledb.yaml | 9 + .../prometheus_rules/cluster-ha-critical.yaml | 26 + .../prometheus_rules/cluster-ha-warning.yaml | 24 + .../cluster-high_connection-critical.yaml | 17 + .../cluster-high_connection-warning.yaml | 17 + .../cluster-high_replication_lag.yaml | 19 + .../cluster-instances_on_same_node.yaml | 19 + .../cluster-low_disk_space-critical.yaml | 24 + .../cluster-low_disk_space-warning.yaml | 24 + .../prometheus_rules/cluster-offline.yaml | 19 + .../cluster-zone_spread-warning.yaml | 18 + charts/vshnpostgresql/templates/NOTES.txt | 102 +++ charts/vshnpostgresql/templates/_backup.tpl | 23 + .../templates/_barman_object_store.tpl | 75 ++ .../vshnpostgresql/templates/_bootstrap.tpl | 112 +++ charts/vshnpostgresql/templates/_colorize.tpl | 12 + .../templates/_external_source_cluster.tpl | 33 + charts/vshnpostgresql/templates/_helpers.tpl | 146 ++++ .../templates/backup-azure-creds.yaml | 12 + .../templates/backup-google-creds.yaml | 9 + .../templates/backup-s3-creds.yaml | 10 + .../vshnpostgresql/templates/ca-bundle.yaml | 10 + charts/vshnpostgresql/templates/cluster.yaml | 145 ++++ .../image-catalog-timescaledb-ha.yaml | 19 + .../templates/image-catalog.yaml | 13 + charts/vshnpostgresql/templates/pooler.yaml | 49 ++ .../templates/prometheus-rule.yaml | 30 + .../templates/recovery-azure-creds.yaml | 12 + .../templates/recovery-google-creds.yaml | 9 + .../recovery-pg_basebackup-password.yaml | 9 + .../templates/recovery-s3-creds.yaml | 10 + .../templates/scheduled-backups.yaml | 19 + .../vshnpostgresql/templates/tests/ping.yaml | 44 ++ .../templates/user-metrics.yaml | 24 + .../01-monitoring_cluster-assert.yaml | 135 ++++ .../monitoring/01-monitoring_cluster.yaml | 80 ++ .../test/monitoring/chainsaw-test.yaml | 29 + .../test/pooler/01-pooler_cluster-assert.yaml | 37 + .../test/pooler/01-pooler_cluster.yaml | 17 + .../test/pooler/chainsaw-test.yaml | 30 + ..._default_configuration_cluster-assert.yaml | 133 ++++ .../01-non_default_configuration_cluster.yaml | 132 ++++ ...ry_object_store_database_owner-assert.yaml | 10 + ...-recovery_object_store_database_owner.yaml | 15 + ...recovery_backup_database_owner-assert.yaml | 11 + .../03-recovery_backup_database_owner.yaml | 16 + .../chainsaw-test.yaml | 56 ++ .../00-source-cluster-assert.yaml | 6 + .../postgresql-import/00-source-cluster.yaml | 9 + .../00-source-superuser-password.yaml | 8 + .../01-data_write-assert.yaml | 6 + .../test/postgresql-import/01-data_write.yaml | 33 + .../02-import-cluster-assert.yaml | 6 + .../postgresql-import/02-import-cluster.yaml | 32 + .../03-data_test-assert.yaml | 6 + .../test/postgresql-import/03-data_test.yaml | 29 + .../04-import-cluster-schema_only-assert.yaml | 6 + .../04-import-cluster-schema_only.yaml | 33 + .../05-data_test-assert.yaml | 6 + .../test/postgresql-import/05-data_test.yaml | 29 + .../test/postgresql-import/chainsaw-test.yaml | 97 +++ .../00-minio_cleanup-assert.yaml | 6 + .../00-minio_cleanup.yaml | 16 + .../01-standalone_cluster-assert.yaml | 6 + .../01-standalone_cluster.yaml | 27 + .../02-data_write-assert.yaml | 6 + .../02-data_write.yaml | 23 + .../03-backup.yaml | 8 + .../03-backup_completed-assert.yaml | 10 + .../03-backup_running-assert.yaml | 10 + .../03-checkpoint.yaml | 27 + .../04-post_backup_data_write-assert.yaml | 6 + .../04-post_backup_data_write.yaml | 57 ++ .../05-recovery_backup_cluster-assert.yaml | 6 + .../05-recovery_backup_cluster.yaml | 32 + .../06-data_test-assert.yaml | 6 + .../06-data_test.yaml | 23 + ...-recovery_object_store_cluster-assert.yaml | 6 + .../07-recovery_object_store_cluster.yaml | 48 ++ .../08-data_test-assert.yaml | 6 + .../08-data_test.yaml | 23 + ...9-recovery_backup_pitr_cluster-assert.yaml | 6 + .../09-recovery_backup_pitr_cluster.yaml | 48 ++ .../10-data_test-assert.yaml | 6 + .../10-data_test.yaml | 27 + .../chainsaw-test.yaml | 148 ++++ .../00-source-cluster-assert.yaml | 6 + .../00-source-cluster.yaml | 8 + .../01-data_write-assert.yaml | 6 + .../01-data_write.yaml | 30 + .../02-pg_basebackup-cluster-assert.yaml | 6 + .../02-pg_basebackup-cluster.yaml | 24 + .../03-data_test-assert.yaml | 6 + .../03-data_test.yaml | 23 + .../chainsaw-test.yaml | 64 ++ .../00-minio_cleanup-assert.yaml | 6 + .../scheduledbackups/00-minio_cleanup.yaml | 16 + .../01-scheduledbackups_cluster-assert.yaml | 37 + .../01-scheduledbackups_cluster.yaml | 36 + .../test/scheduledbackups/chainsaw-test.yaml | 27 + .../00-minio_cleanup-assert.yaml | 6 + .../00-minio_cleanup.yaml | 16 + .../01-timescale_cluster-assert.yaml | 6 + .../01-timescale_cluster.yaml | 28 + .../03-timescale_test-assert.yaml | 6 + .../03-timescale_test.yaml | 22 + .../04-data_write-assert.yaml | 6 + .../04-data_write.yaml | 54 ++ .../05-backup.yaml | 8 + .../05-backup_completed-assert.yaml | 10 + .../05-backup_running-assert.yaml | 10 + .../05-checkpoint.yaml | 27 + .../06-post_backup_data_write-assert.yaml | 6 + .../06-post_backup_data_write.yaml | 27 + ...7-recovery_backup_pitr_cluster-assert.yaml | 6 + .../07-recovery_backup_pitr_cluster.yaml | 48 ++ .../08-data_test-assert.yaml | 6 + .../08-data_test.yaml | 27 + .../chainsaw-test.yaml | 129 ++++ charts/vshnpostgresql/values.schema.json | 703 ++++++++++++++++++ charts/vshnpostgresql/values.yaml | 530 +++++++++++++ 146 files changed, 5888 insertions(+) create mode 100644 charts/vshnpostgresql/Chart.yaml create mode 100644 charts/vshnpostgresql/README.md create mode 100644 charts/vshnpostgresql/README.md.gotmpl create mode 100644 charts/vshnpostgresql/docs/Getting Started.md create mode 100644 charts/vshnpostgresql/docs/Recovery.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md create mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md create mode 100644 charts/vshnpostgresql/examples/basic.yaml create mode 100644 charts/vshnpostgresql/examples/custom-queries.yaml create mode 100644 charts/vshnpostgresql/examples/image-catalog-ref.yaml create mode 100644 charts/vshnpostgresql/examples/image-catalog.yaml create mode 100644 charts/vshnpostgresql/examples/pgbouncer.yaml create mode 100644 charts/vshnpostgresql/examples/postgis.yaml create mode 100644 charts/vshnpostgresql/examples/recovery-backup.yaml create mode 100644 charts/vshnpostgresql/examples/recovery-object_store.yaml create mode 100644 charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml create mode 100644 charts/vshnpostgresql/examples/standalone-s3.yaml create mode 100644 charts/vshnpostgresql/examples/timescaledb.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-ha-critical.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-ha-warning.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-high_connection-critical.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-high_connection-warning.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-high_replication_lag.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-instances_on_same_node.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-critical.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-warning.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-offline.yaml create mode 100644 charts/vshnpostgresql/prometheus_rules/cluster-zone_spread-warning.yaml create mode 100644 charts/vshnpostgresql/templates/NOTES.txt create mode 100644 charts/vshnpostgresql/templates/_backup.tpl create mode 100644 charts/vshnpostgresql/templates/_barman_object_store.tpl create mode 100644 charts/vshnpostgresql/templates/_bootstrap.tpl create mode 100644 charts/vshnpostgresql/templates/_colorize.tpl create mode 100644 charts/vshnpostgresql/templates/_external_source_cluster.tpl create mode 100644 charts/vshnpostgresql/templates/_helpers.tpl create mode 100644 charts/vshnpostgresql/templates/backup-azure-creds.yaml create mode 100644 charts/vshnpostgresql/templates/backup-google-creds.yaml create mode 100644 charts/vshnpostgresql/templates/backup-s3-creds.yaml create mode 100644 charts/vshnpostgresql/templates/ca-bundle.yaml create mode 100644 charts/vshnpostgresql/templates/cluster.yaml create mode 100644 charts/vshnpostgresql/templates/image-catalog-timescaledb-ha.yaml create mode 100644 charts/vshnpostgresql/templates/image-catalog.yaml create mode 100644 charts/vshnpostgresql/templates/pooler.yaml create mode 100644 charts/vshnpostgresql/templates/prometheus-rule.yaml create mode 100644 charts/vshnpostgresql/templates/recovery-azure-creds.yaml create mode 100644 charts/vshnpostgresql/templates/recovery-google-creds.yaml create mode 100644 charts/vshnpostgresql/templates/recovery-pg_basebackup-password.yaml create mode 100644 charts/vshnpostgresql/templates/recovery-s3-creds.yaml create mode 100644 charts/vshnpostgresql/templates/scheduled-backups.yaml create mode 100644 charts/vshnpostgresql/templates/tests/ping.yaml create mode 100644 charts/vshnpostgresql/templates/user-metrics.yaml create mode 100644 charts/vshnpostgresql/test/monitoring/01-monitoring_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/monitoring/01-monitoring_cluster.yaml create mode 100644 charts/vshnpostgresql/test/monitoring/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/pooler/01-pooler_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/pooler/01-pooler_cluster.yaml create mode 100644 charts/vshnpostgresql/test/pooler/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-cluster-configuration/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/00-source-cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/00-source-cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/00-source-superuser-password.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/01-data_write-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/01-data_write.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/02-import-cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/02-import-cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/03-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/03-data_test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/05-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/05-data_test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-import/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_completed-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_running-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-checkpoint.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-minio-backup-restore/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test.yaml create mode 100644 charts/vshnpostgresql/test/postgresql-pg_basebackup/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup-assert.yaml create mode 100644 charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup.yaml create mode 100644 charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster.yaml create mode 100644 charts/vshnpostgresql/test/scheduledbackups/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_completed-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_running-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/05-checkpoint.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test-assert.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test.yaml create mode 100644 charts/vshnpostgresql/test/timescale-minio-backup-restore/chainsaw-test.yaml create mode 100644 charts/vshnpostgresql/values.schema.json create mode 100644 charts/vshnpostgresql/values.yaml diff --git a/charts/vshnpostgresql/Chart.yaml b/charts/vshnpostgresql/Chart.yaml new file mode 100644 index 0000000..6e0bfd4 --- /dev/null +++ b/charts/vshnpostgresql/Chart.yaml @@ -0,0 +1,34 @@ +# +# Copyright © contributors to CloudNativePG, established as +# CloudNativePG a Series of LF Projects, LLC. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# +apiVersion: v2 +name: cluster +description: Deploys and manages a CloudNativePG cluster and its associated resources. +icon: https://raw.githubusercontent.com/cloudnative-pg/artwork/main/cloudnativepg-logo.svg +type: application +version: 0.3.1 +sources: + - https://github.com/cloudnative-pg/charts +keywords: + - postgresql + - postgres + - database +home: https://cloudnative-pg.io +maintainers: + - name: itay-grudev + email: itay+cloudnativepg-charts+github.com@grudev.com diff --git a/charts/vshnpostgresql/README.md b/charts/vshnpostgresql/README.md new file mode 100644 index 0000000..9af61a4 --- /dev/null +++ b/charts/vshnpostgresql/README.md @@ -0,0 +1,311 @@ +# cluster + +![Version: 0.3.1](https://img.shields.io/badge/Version-0.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) + +> **Warning** +> ### This chart is under active development. +> ### Advised caution when using in production! + +A note on the chart's purpose +----------------------------- + +This is an opinionated chart that is designed to provide a subset of simple, stable and safe configurations using the +CloudNativePG operator. It is designed to provide a simple way to perform recovery operations to decrease your RTO. + +It is not designed to be a one size fits all solution. If you need a more complicated setup we strongly recommend that +you either: + +* use the operator directly +* create your own chart +* use Kustomize to modify the chart's resources + +**_Note_** that the latter option carries it's own risks as the chart configuration may change, especially before it +reaches a stable release. + +That being said, we welcome PRs that improve the chart, but please keep in mind that we don't plan to support every +single configuration that the operator provides and we may reject PRs that add too much complexity and maintenance +difficulty to the chart. + +Getting Started +--------------- + +### Installing the Operator +Skip this step if the CNPG operator is already installed in your cluster. + +```console +helm repo add cnpg https://cloudnative-pg.github.io/charts +helm upgrade --install cnpg \ +--namespace cnpg-system \ +--create-namespace \ +cnpg/cloudnative-pg +``` + +### Setting up a CNPG Cluster + +```console +helm repo add cnpg https://cloudnative-pg.github.io/charts +helm upgrade --install cnpg \ +--namespace cnpg-database \ +--create-namespace \ +--values values.yaml \ +cnpg/cluster +``` + +A more detailed guide can be found in the [Getting Started docs](<./docs/Getting Started.md>). + +Cluster Configuration +--------------------- + +### Database types + +Currently the chart supports two database types. These are configured via the `type` parameter. These are: +* `postgresql` - A standard PostgreSQL database. +* `postgis` - A PostgreSQL database with the PostGIS extension installed. + +Depending on the type the chart will use a different Docker image and fill in some initial setup, like extension installation. + +### Modes of operation + +The chart has three modes of operation. These are configured via the `mode` parameter: +* `standalone` - Creates new or updates an existing CNPG cluster. This is the default mode. +* `replica` - Creates a replica cluster from an existing CNPG cluster. **_Note_ that this mode is not yet supported.** +* `recovery` - Recovers a CNPG cluster from a backup, object store or via pg_basebackup. + +### Backup configuration + +CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object +store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are +stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following +providers are supported: + +* S3 or S3-compatible stores, like MinIO +* Microsoft Azure Blob Storage +* Google Cloud Storage + +Additionally you can specify the following parameters: +* `backups.retentionPolicy` - The retention policy for backups. Defaults to `30d`. +* `backups.scheduledBackups` - An array of scheduled backups containing a name and a crontab schedule. Example: +```yaml +backups: + scheduledBackups: + - name: daily-backup + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self +``` + +Each backup adapter takes it's own set of parameters, listed in the [Configuration options](#Configuration-options) section +below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, +`backup.azure`, or `backup.google`. + +Recovery +-------- + +There is a separate document outlining the recovery procedure here: **[Recovery](docs/Recovery.md)** + +Examples +-------- + +There are several configuration examples in the [examples](examples) directory. Refer to them for a basic setup and +refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/current/) for more advanced configurations. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| backups.azure.connectionString | string | `""` | | +| backups.azure.containerName | string | `""` | | +| backups.azure.inheritFromAzureAD | bool | `false` | | +| backups.azure.path | string | `"/"` | | +| backups.azure.serviceName | string | `"blob"` | | +| backups.azure.storageAccount | string | `""` | | +| backups.azure.storageKey | string | `""` | | +| backups.azure.storageSasToken | string | `""` | | +| backups.data.compression | string | `"gzip"` | Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | +| backups.data.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. | +| backups.data.jobs | int | `2` | Number of data files to be archived or restored in parallel. | +| backups.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | +| backups.enabled | bool | `false` | You need to configure backups manually, so backups are disabled by default. | +| backups.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | +| backups.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | +| backups.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" | +| backups.google.applicationCredentials | string | `""` | | +| backups.google.bucket | string | `""` | | +| backups.google.gkeEnvironment | bool | `false` | | +| backups.google.path | string | `"/"` | | +| backups.provider | string | `"s3"` | One of `s3`, `azure` or `google` | +| backups.retentionPolicy | string | `"30d"` | Retention policy for backups | +| backups.s3.accessKey | string | `""` | | +| backups.s3.bucket | string | `""` | | +| backups.s3.inheritFromIAMRole | bool | `false` | Use the role based authentication without providing explicitly the keys | +| backups.s3.path | string | `"/"` | | +| backups.s3.region | string | `""` | | +| backups.s3.secretKey | string | `""` | | +| backups.scheduledBackups[0].backupOwnerReference | string | `"self"` | Backup owner reference | +| backups.scheduledBackups[0].method | string | `"barmanObjectStore"` | Backup method, can be `barmanObjectStore` (default) or `volumeSnapshot` | +| backups.scheduledBackups[0].name | string | `"daily-backup"` | Scheduled backup name | +| backups.scheduledBackups[0].schedule | string | `"0 0 0 * * *"` | Schedule in cron format | +| backups.secret.create | bool | `true` | Whether to create a secret for the backup credentials | +| backups.secret.name | string | `""` | Name of the backup credentials secret | +| backups.wal.compression | string | `"gzip"` | WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | +| backups.wal.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. | +| backups.wal.maxParallel | int | `1` | Number of WAL files to be archived or restored in parallel. | +| cluster.additionalLabels | object | `{}` | | +| cluster.affinity | object | `{"topologyKey":"topology.kubernetes.io/zone"}` | Affinity/Anti-affinity rules for Pods. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-AffinityConfiguration | +| cluster.annotations | object | `{}` | | +| cluster.certificates | object | `{}` | The configuration for the CA and related certificates. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-CertificatesConfiguration | +| cluster.enablePDB | bool | `true` | Allow to disable PDB, mainly useful for upgrade of single-instance clusters or development purposes See: https://cloudnative-pg.io/documentation/current/kubernetes_upgrade/#pod-disruption-budgets | +| cluster.enableSuperuserAccess | bool | `true` | When this option is enabled, the operator will use the SuperuserSecret to update the postgres user password. If the secret is not present, the operator will automatically create one. When this option is disabled, the operator will ignore the SuperuserSecret content, delete it when automatically created, and then blank the password of the postgres user by setting it to NULL. | +| cluster.env | list | `[]` | Env follows the Env format to pass environment variables to the pods created in the cluster | +| cluster.envFrom | list | `[]` | EnvFrom follows the EnvFrom format to pass environment variables sources to the pods to be used by Env | +| cluster.imageCatalogRef | object | `{}` | Reference to `ImageCatalog` of `ClusterImageCatalog`, if specified takes precedence over `cluster.imageName` | +| cluster.imageName | string | `""` | Name of the container image, supporting both tags (:) and digests for deterministic and repeatable deployments: :@sha256: | +| cluster.imagePullPolicy | string | `"IfNotPresent"` | Image pull policy. One of Always, Never or IfNotPresent. If not defined, it defaults to IfNotPresent. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images | +| cluster.imagePullSecrets | list | `[]` | The list of pull secrets to be used to pull the images. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-LocalObjectReference | +| cluster.initdb | object | `{}` | BootstrapInitDB is the configuration of the bootstrap process when initdb is used. See: https://cloudnative-pg.io/documentation/current/bootstrap/ See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-bootstrapinitdb | +| cluster.instances | int | `3` | Number of instances | +| cluster.logLevel | string | `"info"` | The instances' log level, one of the following values: error, warning, info (default), debug, trace | +| cluster.monitoring.customQueries | list | `[]` | Custom Prometheus metrics Will be stored in the ConfigMap | +| cluster.monitoring.customQueriesSecret | list | `[]` | The list of secrets containing the custom queries | +| cluster.monitoring.disableDefaultQueries | bool | `false` | Whether the default queries should be injected. Set it to true if you don't want to inject default queries into the cluster. | +| cluster.monitoring.enabled | bool | `false` | Whether to enable monitoring | +| cluster.monitoring.podMonitor.enabled | bool | `true` | Whether to enable the PodMonitor | +| cluster.monitoring.podMonitor.metricRelabelings | list | `[]` | The list of metric relabelings for the PodMonitor. Applied to samples before ingestion. | +| cluster.monitoring.podMonitor.relabelings | list | `[]` | The list of relabelings for the PodMonitor. Applied to samples before scraping. | +| cluster.monitoring.prometheusRule.enabled | bool | `true` | Whether to enable the PrometheusRule automated alerts | +| cluster.monitoring.prometheusRule.excludeRules | list | `[]` | Exclude specified rules | +| cluster.postgresGID | int | `-1` | The GID of the postgres user inside the image, defaults to 26 | +| cluster.postgresUID | int | `-1` | The UID of the postgres user inside the image, defaults to 26 | +| cluster.postgresql.ldap | object | `{}` | PostgreSQL LDAP configuration (see https://cloudnative-pg.io/documentation/current/postgresql_conf/#ldap-configuration) | +| cluster.postgresql.parameters | object | `{}` | PostgreSQL configuration options (postgresql.conf) | +| cluster.postgresql.pg_hba | list | `[]` | PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) | +| cluster.postgresql.pg_ident | list | `[]` | PostgreSQL User Name Maps rules (lines to be appended to the pg_ident.conf file) | +| cluster.postgresql.shared_preload_libraries | list | `[]` | Lists of shared preload libraries to add to the default ones | +| cluster.postgresql.synchronous | object | `{}` | Quorum-based Synchronous Replication | +| cluster.primaryUpdateMethod | string | `"switchover"` | Method to follow to upgrade the primary server during a rolling update procedure, after all replicas have been successfully updated. It can be switchover (default) or restart. | +| cluster.primaryUpdateStrategy | string | `"unsupervised"` | Strategy to follow to upgrade the primary server during a rolling update procedure, after all replicas have been successfully updated: it can be automated (unsupervised - default) or manual (supervised) | +| cluster.priorityClassName | string | `""` | | +| cluster.resources | object | `{}` | Resources requirements of every generated Pod. Please refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for more information. We strongly advise you use the same setting for limits and requests so that your cluster pods are given a Guaranteed QoS. See: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ | +| cluster.roles | list | `[]` | This feature enables declarative management of existing roles, as well as the creation of new roles if they are not already present in the database. See: https://cloudnative-pg.io/documentation/current/declarative_role_management/ | +| cluster.serviceAccountTemplate | object | `{}` | Configure the metadata of the generated service account | +| cluster.services | object | `{}` | Customization of service definitions. Please refer to https://cloudnative-pg.io/documentation/current/service_management/ | +| cluster.storage.size | string | `"8Gi"` | | +| cluster.storage.storageClass | string | `""` | | +| cluster.superuserSecret | string | `""` | | +| cluster.walStorage.enabled | bool | `false` | | +| cluster.walStorage.size | string | `"1Gi"` | | +| cluster.walStorage.storageClass | string | `""` | | +| fullnameOverride | string | `""` | Override the full name of the chart | +| imageCatalog.create | bool | `true` | Whether to provision an image catalog. If imageCatalog.images is empty this option will be ignored. | +| imageCatalog.images | list | `[]` | List of images to be provisioned in an image catalog. | +| mode | string | `"standalone"` | Cluster mode of operation. Available modes: * `standalone` - default mode. Creates new or updates an existing CNPG cluster. * `replica` - Creates a replica cluster from an existing CNPG cluster. # TODO * `recovery` - Same as standalone but creates a cluster from a backup, object store or via pg_basebackup. | +| nameOverride | string | `""` | Override the name of the chart | +| namespaceOverride | string | `""` | Override the namespace of the chart | +| poolers | list | `[]` | List of PgBouncer poolers | +| recovery.azure.connectionString | string | `""` | | +| recovery.azure.containerName | string | `""` | | +| recovery.azure.inheritFromAzureAD | bool | `false` | | +| recovery.azure.path | string | `"/"` | | +| recovery.azure.serviceName | string | `"blob"` | | +| recovery.azure.storageAccount | string | `""` | | +| recovery.azure.storageKey | string | `""` | | +| recovery.azure.storageSasToken | string | `""` | | +| recovery.backupName | string | `""` | Backup Recovery Method | +| recovery.clusterName | string | `""` | The original cluster name when used in backups. Also known as serverName. | +| recovery.database | string | `"app"` | Name of the database used by the application. Default: `app`. | +| recovery.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | +| recovery.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | +| recovery.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | +| recovery.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" Leave empty if using the default S3 endpoint | +| recovery.google.applicationCredentials | string | `""` | | +| recovery.google.bucket | string | `""` | | +| recovery.google.gkeEnvironment | bool | `false` | | +| recovery.google.path | string | `"/"` | | +| recovery.import.databases | list | `[]` | Databases to import | +| recovery.import.pgDumpExtraOptions | list | `[]` | List of custom options to pass to the `pg_dump` command. IMPORTANT: Use these options with caution and at your own risk, as the operator does not validate their content. Be aware that certain options may conflict with the operator's intended functionality or design. | +| recovery.import.pgRestoreExtraOptions | list | `[]` | List of custom options to pass to the `pg_restore` command. IMPORTANT: Use these options with caution and at your own risk, as the operator does not validate their content. Be aware that certain options may conflict with the operator's intended functionality or design. | +| recovery.import.postImportApplicationSQL | list | `[]` | List of SQL queries to be executed as a superuser in the application database right after is imported. To be used with extreme care. Only available in microservice type. | +| recovery.import.roles | list | `[]` | Roles to import | +| recovery.import.schemaOnly | bool | `false` | When set to true, only the pre-data and post-data sections of pg_restore are invoked, avoiding data import. | +| recovery.import.source.database | string | `""` | | +| recovery.import.source.host | string | `""` | | +| recovery.import.source.passwordSecret.create | bool | `false` | Whether to create a secret for the password | +| recovery.import.source.passwordSecret.key | string | `"password"` | The key in the secret containing the password | +| recovery.import.source.passwordSecret.name | string | `""` | Name of the secret containing the password | +| recovery.import.source.passwordSecret.value | string | `""` | The password value to use when creating the secret | +| recovery.import.source.port | int | `5432` | | +| recovery.import.source.sslCertSecret.key | string | `""` | | +| recovery.import.source.sslCertSecret.name | string | `""` | | +| recovery.import.source.sslKeySecret.key | string | `""` | | +| recovery.import.source.sslKeySecret.name | string | `""` | | +| recovery.import.source.sslMode | string | `"verify-full"` | | +| recovery.import.source.sslRootCertSecret.key | string | `""` | | +| recovery.import.source.sslRootCertSecret.name | string | `""` | | +| recovery.import.source.username | string | `""` | | +| recovery.import.type | string | `"microservice"` | One of `microservice` or `monolith.` See: https://cloudnative-pg.io/documentation/current/database_import/#how-it-works | +| recovery.method | string | `"backup"` | Available recovery methods: * `backup` - Recovers a CNPG cluster from a CNPG backup (PITR supported) Needs to be on the same cluster in the same namespace. * `object_store` - Recovers a CNPG cluster from a barman object store (PITR supported). * `pg_basebackup` - Recovers a CNPG cluster viaa streaming replication protocol. Useful if you want to migrate databases to CloudNativePG, even from outside Kubernetes. * `import` - Import one or more databases from an existing Postgres cluster. | +| recovery.owner | string | `""` | Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. | +| recovery.pgBaseBackup.database | string | `"app"` | Name of the database used by the application. Default: `app`. | +| recovery.pgBaseBackup.owner | string | `""` | Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. | +| recovery.pgBaseBackup.secret | string | `""` | Name of the secret containing the initial credentials for the owner of the user database. If empty a new secret will be created from scratch | +| recovery.pgBaseBackup.source.database | string | `"app"` | | +| recovery.pgBaseBackup.source.host | string | `""` | | +| recovery.pgBaseBackup.source.passwordSecret.create | bool | `false` | Whether to create a secret for the password | +| recovery.pgBaseBackup.source.passwordSecret.key | string | `"password"` | The key in the secret containing the password | +| recovery.pgBaseBackup.source.passwordSecret.name | string | `""` | Name of the secret containing the password | +| recovery.pgBaseBackup.source.passwordSecret.value | string | `""` | The password value to use when creating the secret | +| recovery.pgBaseBackup.source.port | int | `5432` | | +| recovery.pgBaseBackup.source.sslCertSecret.key | string | `""` | | +| recovery.pgBaseBackup.source.sslCertSecret.name | string | `""` | | +| recovery.pgBaseBackup.source.sslKeySecret.key | string | `""` | | +| recovery.pgBaseBackup.source.sslKeySecret.name | string | `""` | | +| recovery.pgBaseBackup.source.sslMode | string | `"verify-full"` | | +| recovery.pgBaseBackup.source.sslRootCertSecret.key | string | `""` | | +| recovery.pgBaseBackup.source.sslRootCertSecret.name | string | `""` | | +| recovery.pgBaseBackup.source.username | string | `""` | | +| recovery.pitrTarget.time | string | `""` | Time in RFC3339 format | +| recovery.provider | string | `"s3"` | One of `s3`, `azure` or `google` | +| recovery.s3.accessKey | string | `""` | | +| recovery.s3.bucket | string | `""` | | +| recovery.s3.inheritFromIAMRole | bool | `false` | Use the role based authentication without providing explicitly the keys | +| recovery.s3.path | string | `"/"` | | +| recovery.s3.region | string | `""` | | +| recovery.s3.secretKey | string | `""` | | +| recovery.secret.create | bool | `true` | Whether to create a secret for the backup credentials | +| recovery.secret.name | string | `""` | Name of the backup credentials secret | +| type | string | `"postgresql"` | Type of the CNPG database. Available types: * `postgresql` * `postgis` * `timescaledb` | +| version.postgis | string | `"3.4"` | If using PostGIS, specify the version | +| version.postgresql | string | `"16"` | PostgreSQL major version to use | +| version.timescaledb | string | `"2.15"` | If using TimescaleDB, specify the version | +| poolers[].name | string | `` | Name of the pooler resource | +| poolers[].instances | number | `1` | The number of replicas we want | +| poolers[].type | [PoolerType][PoolerType] | `rw` | Type of service to forward traffic to. Default: `rw`. | +| poolers[].poolMode | [PgBouncerPoolMode][PgBouncerPoolMode] | `session` | The pool mode. Default: `session`. | +| poolers[].authQuerySecret | [LocalObjectReference][LocalObjectReference] | `{}` | The credentials of the user that need to be used for the authentication query. | +| poolers[].authQuery | string | `{}` | The credentials of the user that need to be used for the authentication query. | +| poolers[].parameters | map[string]string | `{}` | Additional parameters to be passed to PgBouncer - please check the CNPG documentation for a list of options you can configure | +| poolers[].template | [PodTemplateSpec][PodTemplateSpec] | `{}` | The template of the Pod to be created | +| poolers[].template | [ServiceTemplateSpec][ServiceTemplateSpec] | `{}` | Template for the Service to be created | +| poolers[].pg_hba | []string | `{}` | PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) | +| poolers[].monitoring.enabled | bool | `false` | Whether to enable monitoring for the Pooler. | +| poolers[].monitoring.podMonitor.enabled | bool | `true` | Create a podMonitor for the Pooler. | + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| itay-grudev | | | + +Features that require feedback +------------------------------ + +Please raise a ticket tested any of the following features and they have worked. +Alternatively a ticket and a PR if you have found that something needs a change to work properly. + +- [ ] Google Cloud Storage Backups +- [ ] Google Cloud Storage Recovery + +TODO +---- +* IAM Role for S3 Service Account +* Automatic provisioning of a Alert Manager configuration + diff --git a/charts/vshnpostgresql/README.md.gotmpl b/charts/vshnpostgresql/README.md.gotmpl new file mode 100644 index 0000000..66e5256 --- /dev/null +++ b/charts/vshnpostgresql/README.md.gotmpl @@ -0,0 +1,158 @@ +{{ template "chart.header" . }} + + +{{ template "chart.deprecationWarning" . }} + + +{{ template "chart.badgesSection" . }} + + +> **Warning** +> ### This chart is under active development. +> ### Advised caution when using in production! + + +A note on the chart's purpose +----------------------------- + +This is an opinionated chart that is designed to provide a subset of simple, stable and safe configurations using the +CloudNativePG operator. It is designed to provide a simple way to perform recovery operations to decrease your RTO. + +It is not designed to be a one size fits all solution. If you need a more complicated setup we strongly recommend that +you either: + +* use the operator directly +* create your own chart +* use Kustomize to modify the chart's resources + +**_Note_** that the latter option carries it's own risks as the chart configuration may change, especially before it +reaches a stable release. + +That being said, we welcome PRs that improve the chart, but please keep in mind that we don't plan to support every +single configuration that the operator provides and we may reject PRs that add too much complexity and maintenance +difficulty to the chart. + + +Getting Started +--------------- + +### Installing the Operator +Skip this step if the CNPG operator is already installed in your cluster. + +```console +helm repo add cnpg https://cloudnative-pg.github.io/charts +helm upgrade --install cnpg \ +--namespace cnpg-system \ +--create-namespace \ +cnpg/cloudnative-pg +``` + +### Setting up a CNPG Cluster + +```console +helm repo add cnpg https://cloudnative-pg.github.io/charts +helm upgrade --install cnpg \ +--namespace cnpg-database \ +--create-namespace \ +--values values.yaml \ +cnpg/cluster +``` + +A more detailed guide can be found in the [Getting Started docs](<./docs/Getting Started.md>). + + +Cluster Configuration +--------------------- + +### Database types + +Currently the chart supports two database types. These are configured via the `type` parameter. These are: +* `postgresql` - A standard PostgreSQL database. +* `postgis` - A PostgreSQL database with the PostGIS extension installed. + +Depending on the type the chart will use a different Docker image and fill in some initial setup, like extension installation. + +### Modes of operation + +The chart has three modes of operation. These are configured via the `mode` parameter: +* `standalone` - Creates new or updates an existing CNPG cluster. This is the default mode. +* `replica` - Creates a replica cluster from an existing CNPG cluster. **_Note_ that this mode is not yet supported.** +* `recovery` - Recovers a CNPG cluster from a backup, object store or via pg_basebackup. + +### Backup configuration + +CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object +store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are +stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following +providers are supported: + +* S3 or S3-compatible stores, like MinIO +* Microsoft Azure Blob Storage +* Google Cloud Storage + +Additionally you can specify the following parameters: +* `backups.retentionPolicy` - The retention policy for backups. Defaults to `30d`. +* `backups.scheduledBackups` - An array of scheduled backups containing a name and a crontab schedule. Example: +```yaml +backups: + scheduledBackups: + - name: daily-backup + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self +``` + +Each backup adapter takes it's own set of parameters, listed in the [Configuration options](#Configuration-options) section +below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, +`backup.azure`, or `backup.google`. + + +Recovery +-------- + +There is a separate document outlining the recovery procedure here: **[Recovery](docs/Recovery.md)** + + +Examples +-------- + +There are several configuration examples in the [examples](examples) directory. Refer to them for a basic setup and +refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/current/) for more advanced configurations. + + +{{ template "chart.requirementsSection" . }} + + +{{ template "chart.valuesSection" . }} +| poolers[].name | string | `` | Name of the pooler resource | +| poolers[].instances | number | `1` | The number of replicas we want | +| poolers[].type | [PoolerType][PoolerType] | `rw` | Type of service to forward traffic to. Default: `rw`. | +| poolers[].poolMode | [PgBouncerPoolMode][PgBouncerPoolMode] | `session` | The pool mode. Default: `session`. | +| poolers[].authQuerySecret | [LocalObjectReference][LocalObjectReference] | `{}` | The credentials of the user that need to be used for the authentication query. | +| poolers[].authQuery | string | `{}` | The credentials of the user that need to be used for the authentication query. | +| poolers[].parameters | map[string]string | `{}` | Additional parameters to be passed to PgBouncer - please check the CNPG documentation for a list of options you can configure | +| poolers[].template | [PodTemplateSpec][PodTemplateSpec] | `{}` | The template of the Pod to be created | +| poolers[].template | [ServiceTemplateSpec][ServiceTemplateSpec] | `{}` | Template for the Service to be created | +| poolers[].pg_hba | []string | `{}` | PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) | +| poolers[].monitoring.enabled | bool | `false` | Whether to enable monitoring for the Pooler. | +| poolers[].monitoring.podMonitor.enabled | bool | `true` | Create a podMonitor for the Pooler. | + +{{ template "chart.maintainersSection" . }} + + +Features that require feedback +------------------------------ + +Please raise a ticket tested any of the following features and they have worked. +Alternatively a ticket and a PR if you have found that something needs a change to work properly. + +- [ ] Google Cloud Storage Backups +- [ ] Google Cloud Storage Recovery + + +TODO +---- +* IAM Role for S3 Service Account +* Automatic provisioning of a Alert Manager configuration + + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/vshnpostgresql/docs/Getting Started.md b/charts/vshnpostgresql/docs/Getting Started.md new file mode 100644 index 0000000..2e3b660 --- /dev/null +++ b/charts/vshnpostgresql/docs/Getting Started.md @@ -0,0 +1,106 @@ +# Getting Started + +The CNPG cluster chart follows a convention over configuration approach. This means that the chart will create a reasonable +CNPG setup with sensible defaults. However, you can override these defaults to create a more customized setup. Note that +you still need to configure backups and monitoring separately. The chart will not install a Prometheus stack for you. + +_**Note,**_ that this is an opinionated chart. It does not support all configuration options that CNPG supports. If you +need a highly customized setup, you should manage your cluster via a Kubernetes CNPG cluster manifest instead of this chart. +Refer to the [CNPG documentation](https://cloudnative-pg.io/documentation/current/) in that case. + +## Installing the operator + +To begin, make sure you install the CNPG operator in you cluster. It can be installed via a Helm chart as shown below or +ir can be installed via a Kubernetes manifest. For more information see the [CNPG documentation](https://cloudnative-pg.io/documentation/current/installation_upgrade/). + +```console +helm repo add cnpg https://cloudnative-pg.github.io/charts +helm upgrade --install cnpg \ + --namespace cnpg-system \ + --create-namespace \ + cnpg/cloudnative-pg +``` + +## Creating a cluster configuration + +Once you have the operator installed, the next step is to prepare the cluster configuration. Whether this will be managed +via a GitOps solution or directly via Helm is up to you. The following sections outlines the important steps in both cases. + +### Choosing the database type + +Currently the chart supports two database types. These are configured via the `type` parameter. These are: +* `postgresql` - A standard PostgreSQL database. +* `postgis` - A PostgreSQL database with the PostGIS extension installed. + +Depending on the type the chart will use a different Docker image and fill in some initial setup, like extension installation. + +### Choosing the mode of operation + +The chart has three modes of operation. These are configured via the `mode` parameter. If this is your first cluster, you +are likely looking for the `standalone` option. +* `standalone` - Creates new or updates an existing CNPG cluster. This is the default mode. +* `replica` - Creates a replica cluster from an existing CNPG cluster. **_Note_ that this mode is not yet supported.** +* `recovery` - Recovers a CNPG cluster from a backup, object store or via pg_basebackup. + +### Backup configuration + +Most importantly you should configure your backup storage. + +CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object +store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are +stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following +providers are supported: + +* S3 or S3-compatible stores, like MinIO +* Microsoft Azure Blob Storage +* Google Cloud Storage + +Additionally you can specify the following parameters: +* `backups.retentionPolicy` - The retention policy for backups. Defaults to `30d`. +* `backups.scheduledBackups` - An array of scheduled backups containing a name and a crontab schedule. Example: + ```yaml + backups: + scheduledBackups: + - name: daily-backup + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + ``` + +Each backup adapter takes it's own set of parameters, listed in the [Configuration options](../README.md#Configuration-options) section +below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, +`backup.azure`, or `backup.google`. + +### Cluster configuration + +There are several important cluster options. Here are the most important ones: + +`cluster.instances` - The number of instances in the cluster. Defaults to `1`, but you should set this to `3` for production. +`cluster.imageName` - This allows you to override the Docker image used for the cluster. The chart will choose a default + for you based on the setting you chose for `type`. If you need to run a configuration that is not supported, you can + create your own Docker image. You can use the [postgres-containers](https://github.com/cloudnative-pg/postgres-containers) + repository for a starting point. + You will likely need to set your own repository access credentials via: `cluster.imagePullPolicy` and `cluster.imagePullSecrets`. +`cluster.storage.size` - The size of the persistent volume claim for the cluster. Defaults to `8Gi`. Every instance will + have it's own persistent volume claim. +`cluster.storage.storageClass` - The storage class to use for the persistent volume claim. +`cluster.resources` - The resource limits and requests for the cluster. You are strongly advised to use the same values + for both limits and requests to ensure a [Guaranteed QoS](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#guaranteed). +`cluster.affinity.topologyKey` - The chart sets it to `topology.kubernetes.io/zone` by default which is useful if you are + running a production cluster in a multi AZ cluster (highly recommended). If you are running a single AZ cluster, you may + want to change that to `kubernetes.io/hostname` to ensure that cluster instances are not provisioned on the same node. +`cluster.postgresql` - Allows you to override PostgreSQL configuration parameters example: + ```yaml + cluster: + postgresql: + max_connections: "200" + shared_buffers: "2GB" + ``` +`cluster.initSQL` - Allows you to run custom SQL queries during the cluster initialization. This is useful for creating +extensions, schemas and databases. Note that these are as a superuser. + +For a full list - refer to the Helm chart [configuration options](../README.md#Configuration-options). + +## Examples + +There are several configuration examples in the [examples](../examples) directory. Refer to them for a basic setup and +refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/current/) for more advanced configurations. diff --git a/charts/vshnpostgresql/docs/Recovery.md b/charts/vshnpostgresql/docs/Recovery.md new file mode 100644 index 0000000..1a7a915 --- /dev/null +++ b/charts/vshnpostgresql/docs/Recovery.md @@ -0,0 +1,27 @@ +Recovery +======== + +This chart can be used to initiate a recovery operation of a CNPG cluster no matter if it was created with the chart or not. + +CNPG does not support recovery in-place. Instead you need to create a new cluster that will be bootstrapped from the existing one or from a backup. + +You can find more information about the recovery process in the [CNPG documentation](https://cloudnative-pg.io/documentation/current/backup_recovery). + +There are 3 types of recovery possible with CNPG: +* Recovery from a backup object in the same Kubernetes namespace. +* Recovery from a Barman Object Store, that could be located anywhere. +* Streaming replication from an operating cluster using `pg_basebackup`. + +When performing a recovery you are strongly advised to use the same configuration and PostgreSQL version as the original cluster. + +To begin, create a `values.yaml` that contains the following: + +1. Set `mode: recovery` to indicate that you want to perform bootstrap the new cluster from an existing one. +2. Set the `recovery.method` to the type of recovery you want to perform. +3. Set either the `recovery.backupName` or the Barman Object Store configuration - i.e. `recovery.provider` and appropriate S3, Azure or GCS configuration. In case of `pg_basebackup` complete the `recovery.pgBaseBackup` section. +4. Optionally set the `recovery.pitrTarget.time` in RFC3339 format to perform a point-in-time recovery (not applicable for `pgBaseBackup`). +5. Retain the identical PostgreSQL version and configuration as the original cluster. +6. Make sure you don't use the same backup section name as the original cluster. We advise you change the `path` within the storage location if you want to reuse the same storage location/bucket. + One pattern is adding a version number at the end of the path, e.g. `/v1` or `/v2` after each recovery procedure. + +Example recovery configurations can be found in the [examples](../examples) directory. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md new file mode 100644 index 0000000..8be576c --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md @@ -0,0 +1,49 @@ +CNPGClusterHACritical +===================== + +Meaning +------- + +The `CNPGClusterHACritical` alert is triggered when the CloudNativePG cluster has no ready standby replicas. + +This can happen during either a normal failover or automated minor version upgrades in a cluster with 2 or less +instances. The replaced instance may need some time to catch-up with the cluster primary instance. + +This alarm will be always triggered if your cluster is configured to run with only 1 instance. In this case you +may want to silence it. + +Impact +------ + +Having no available replicas puts your cluster at a severe risk if the primary instance fails. The primary instance is +still online and able to serve queries, although connections to the `-ro` endpoint will fail. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Get the status of the CloudNativePG cluster instances: + +```bash +kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide +``` + +Check the logs of the affected CloudNativePG instances: + +```bash +kubectl logs --namespace pod/ +``` + +Check the CloudNativePG operator logs: + +```bash +kubectl logs --namespace cnpg-system -l "app.kubernetes.io/name=cloudnative-pg" +``` + +Mitigation +---------- + +Refer to the [CloudNativePG Failure Modes](https://cloudnative-pg.io/documentation/current/failure_modes/) +and [CloudNativePG Troubleshooting](https://cloudnative-pg.io/documentation/current/troubleshooting/) documentation for +more information on how to troubleshoot and mitigate this issue. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md new file mode 100644 index 0000000..80acfad --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md @@ -0,0 +1,51 @@ +CNPGClusterHAWarning +==================== + +Meaning +------- + +The `CNPGClusterHAWarning` alert is triggered when the CloudNativePG cluster ready standby replicas are less than `2`. + +This alarm will be always triggered if your cluster is configured to run with less than `3` instances. In this case you +may want to silence it. + +Impact +------ + +Having less than two available replicas puts your cluster at risk if another instance fails. The cluster is still able +to operate normally, although the `-ro` and `-r` endpoints operate at reduced capacity. + +This can happen during a normal failover or automated minor version upgrades. The replaced instance may need some time +to catch-up with the cluster primary instance which will trigger the alert if the operation takes more than 5 minutes. + +At `0` available ready replicas, a `CNPGClusterHACritical` alert will be triggered. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Get the status of the CloudNativePG cluster instances: + +```bash +kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide +``` + +Check the logs of the affected CloudNativePG instances: + +```bash +kubectl logs --namespace pod/ +``` + +Check the CloudNativePG operator logs: + +```bash +kubectl logs --namespace cnpg-system -l "app.kubernetes.io/name=cloudnative-pg" +``` + +Mitigation +---------- + +Refer to the [CloudNativePG Failure Modes](https://cloudnative-pg.io/documentation/current/failure_modes/) +and [CloudNativePG Troubleshooting](https://cloudnative-pg.io/documentation/current/troubleshooting/) documentation for +more information on how to troubleshoot and mitigate this issue. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md new file mode 100644 index 0000000..2003421 --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md @@ -0,0 +1,24 @@ +CNPGClusterHighConnectionsCritical +================================== + +Meaning +------- + +This alert is triggered when the number of connections to the CloudNativePG cluster instance exceeds 95% of its capacity. + +Impact +------ + +At 100% capacity, the CloudNativePG cluster instance will not be able to accept new connections. This will result in a service +disruption. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Mitigation +---------- + +* Increase the maximum number of connections by increasing the `max_connections` PostgreSQL parameter. +* Use connection pooling by enabling PgBouncer to reduce the number of connections to the database. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md new file mode 100644 index 0000000..636579f --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md @@ -0,0 +1,24 @@ +CNPGClusterHighConnectionsWarning +================================= + +Meaning +------- + +This alert is triggered when the number of connections to the CloudNativePG cluster instance exceeds 85% of its capacity. + +Impact +------ + +At 100% capacity, the CloudNativePG cluster instance will not be able to accept new connections. This will result in a service +disruption. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Mitigation +---------- + +* Increase the maximum number of connections by increasing the `max_connections` PostgreSQL parameter. +* Use connection pooling by enabling PgBouncer to reduce the number of connections to the database. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md new file mode 100644 index 0000000..78963ce --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md @@ -0,0 +1,31 @@ +CNPGClusterHighReplicationLag +============================= + +Meaning +------- + +This alert is triggered when the replication lag of the CloudNativePG cluster exceed `1s`. + +Impact +------ + +High replication lag can cause the cluster replicas become out of sync. Queries to the `-r` and `-ro` endpoints may return stale data. +In the event of a failover, there may be data loss for the time period of the lag. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +High replication lag can be caused by a number of factors, including: +* Network issues +* High load on the primary or replicas +* Long running queries +* Suboptimal PostgreSQL configuration, in particular small numbers of `max_wal_senders`. + +```yaml +kubectl exec --namespace --stdin --tty services/-rw -- psql -c "SELECT * from pg_stat_replication;" +``` + +Mitigation +---------- diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md new file mode 100644 index 0000000..df309ff --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md @@ -0,0 +1,28 @@ +CNPGClusterInstancesOnSameNode +============================ + +Meaning +------- + +The `CNPGClusterInstancesOnSameNode` alert is raised when two or more database pods are scheduled on the same node. + +Impact +------ + +A failure or scheduled downtime of a single node will lead to a potential service disruption and/or data loss. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +```bash +kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide +``` + +Mitigation +---------- + +1. Verify you have more than a single node with no taints, preventing pods to be scheduled there. +2. Verify your [affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) configuration. +3. For more information, please refer to the ["Scheduling"](https://cloudnative-pg.io/documentation/current/scheduling/) section in the documentation diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md new file mode 100644 index 0000000..5b73552 --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md @@ -0,0 +1,31 @@ +CNPGClusterLowDiskSpaceCritical +=============================== + +Meaning +------- + +This alert is triggered when the disk space on the CloudNativePG cluster exceeds 90%. It can be triggered by either: + +* the PVC hosting the `PGDATA` (`storage` section) +* the PVC hosting WAL files (`walStorage` section), where applicable +* any PVC hosting a tablespace (`tablespaces` section) + +Impact +------ + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Excessive disk space usage can lead fragmentation negatively impacting performance. Reaching 100% disk usage will result +in downtime and data loss. + +Diagnosis +--------- + +Mitigation +---------- + +If you experience issues with the WAL (Write-Ahead Logging) volume and have +set up continuous archiving, ensure that WAL archiving is functioning +correctly. This is crucial to avoid a buildup of WAL files in the `pg_wal` +folder. Monitor the `cnpg_collector_pg_wal_archive_status` metric, specifically +ensuring that the number of `ready` files does not increase linearly. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md new file mode 100644 index 0000000..36e56ac --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md @@ -0,0 +1,31 @@ +CNPGClusterLowDiskSpaceWarning +============================== + +Meaning +------- + +This alert is triggered when the disk space on the CloudNativePG cluster exceeds 90%. It can be triggered by either: + +* the PVC hosting the `PGDATA` (`storage` section) +* the PVC hosting WAL files (`walStorage` section), where applicable +* any PVC hosting a tablespace (`tablespaces` section) + +Impact +------ + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Excessive disk space usage can lead fragmentation negatively impacting performance. Reaching 100% disk usage will result +in downtime and data loss. + +Diagnosis +--------- + +Mitigation +---------- + +If you experience issues with the WAL (Write-Ahead Logging) volume and have +set up continuous archiving, ensure that WAL archiving is functioning +correctly. This is crucial to avoid a buildup of WAL files in the `pg_wal` +folder. Monitor the `cnpg_collector_pg_wal_archive_status` metric, specifically +ensuring that the number of `ready` files does not increase linearly. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md new file mode 100644 index 0000000..0e69db1 --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md @@ -0,0 +1,43 @@ +CNPGClusterOffline +================== + +Meaning +------- + +The `CNPGClusterOffline` alert is triggered when there are no ready CloudNativePG instances. + +Impact +------ + +Having an offline cluster means your applications will not be able to access the database, leading to potential service +disruption. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Get the status of the CloudNativePG cluster instances: + +```bash +kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide +``` + +Check the logs of the affected CloudNativePG instances: + +```bash +kubectl logs --namespace pod/ +``` + +Check the CloudNativePG operator logs: + +```bash +kubectl logs --namespace cnpg-system -l "app.kubernetes.io/name=cloudnative-pg" +``` + +Mitigation +---------- + +Refer to the [CloudNativePG Failure Modes](https://cloudnative-pg.io/documentation/current/failure_modes/) +and [CloudNativePG Troubleshooting](https://cloudnative-pg.io/documentation/current/troubleshooting/) documentation for +more information on how to troubleshoot and mitigate this issue. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md new file mode 100644 index 0000000..c5bdb05 --- /dev/null +++ b/charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md @@ -0,0 +1,37 @@ +CNPGClusterZoneSpreadWarning +============================ + +Meaning +------- + +The `CNPGClusterZoneSpreadWarning` alert is raised when pods are not evenly distributed across availability zones. To be +more accurate, the alert is raised when the number of `pods > zones < 3`. + +Impact +------ + +The uneven distribution of pods across availability zones can lead to a single point of failure if a zone goes down. + +Diagnosis +--------- + +Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). + +Get the status of the CloudNativePG cluster instances: + +```bash +kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide +``` + +Get the nodes and their respective zones: + +```bash +kubectl get nodes --label-columns topology.kubernetes.io/zone +``` + +Mitigation +---------- + +1. Verify you have more than a single node with no taints, preventing pods to be scheduled in each availability zone. +2. Verify your [affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) configuration. +3. Delete the pods and their respective PVC that are not in the desired availability zone and allow the operator to repair the cluster. diff --git a/charts/vshnpostgresql/examples/basic.yaml b/charts/vshnpostgresql/examples/basic.yaml new file mode 100644 index 0000000..b4c15bb --- /dev/null +++ b/charts/vshnpostgresql/examples/basic.yaml @@ -0,0 +1,8 @@ +type: postgresql +mode: standalone +version: + postgresql: "16" +cluster: + instances: 1 +backups: + enabled: false diff --git a/charts/vshnpostgresql/examples/custom-queries.yaml b/charts/vshnpostgresql/examples/custom-queries.yaml new file mode 100644 index 0000000..7995202 --- /dev/null +++ b/charts/vshnpostgresql/examples/custom-queries.yaml @@ -0,0 +1,24 @@ +type: postgresql +mode: standalone + +cluster: + instances: 1 + monitoring: + enabled: true + customQueries: + - name: "pg_cache_hit" + query: | + SELECT + current_database() as datname, + sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio + FROM pg_statio_user_tables; + metrics: + - datname: + usage: "LABEL" + description: "Name of the database database" + - ratio: + usage: GAUGE + description: "Cache hit ratio" + +backups: + enabled: false diff --git a/charts/vshnpostgresql/examples/image-catalog-ref.yaml b/charts/vshnpostgresql/examples/image-catalog-ref.yaml new file mode 100644 index 0000000..e4833a3 --- /dev/null +++ b/charts/vshnpostgresql/examples/image-catalog-ref.yaml @@ -0,0 +1,12 @@ +type: postgresql +mode: standalone +version: + major: "16" + timescaledb: "2.15" +cluster: + instances: 1 + imageCatalogRef: + kind: ImageCatalog + name: my-image-catalog +backups: + enabled: false diff --git a/charts/vshnpostgresql/examples/image-catalog.yaml b/charts/vshnpostgresql/examples/image-catalog.yaml new file mode 100644 index 0000000..c610229 --- /dev/null +++ b/charts/vshnpostgresql/examples/image-catalog.yaml @@ -0,0 +1,14 @@ +type: postgresql +mode: standalone +version: + major: "16" + timescaledb: "2.15" +cluster: + instances: 1 +backups: + enabled: false +imageCatalog: + create: true + images: + - major: 16 + image: my-custom-postgres-image:mytag diff --git a/charts/vshnpostgresql/examples/pgbouncer.yaml b/charts/vshnpostgresql/examples/pgbouncer.yaml new file mode 100644 index 0000000..94d4987 --- /dev/null +++ b/charts/vshnpostgresql/examples/pgbouncer.yaml @@ -0,0 +1,34 @@ +type: postgresql +mode: standalone + +cluster: + instances: 1 + monitoring: + enabled: true + podMonitor: + enabled: true + +backups: + enabled: false + +poolers: + - name: rw + type: rw + instances: 1 + monitoring: + enabled: true + podMonitor: + enabled: true + relabelings: + - targetLabel: type + replacement: rw + - name: ro + type: ro + instances: 1 + monitoring: + enabled: true + podMonitor: + enabled: true + relabelings: + - targetLabel: type + replacement: ro diff --git a/charts/vshnpostgresql/examples/postgis.yaml b/charts/vshnpostgresql/examples/postgis.yaml new file mode 100644 index 0000000..168ac9f --- /dev/null +++ b/charts/vshnpostgresql/examples/postgis.yaml @@ -0,0 +1,9 @@ +type: postgis +mode: standalone +version: + postgresql: "16" + postgis: "3.4" +cluster: + instances: 1 +backups: + enabled: false diff --git a/charts/vshnpostgresql/examples/recovery-backup.yaml b/charts/vshnpostgresql/examples/recovery-backup.yaml new file mode 100644 index 0000000..c478e7a --- /dev/null +++ b/charts/vshnpostgresql/examples/recovery-backup.yaml @@ -0,0 +1,23 @@ +type: postgresql +mode: recovery + +recovery: + method: backup + backupName: "database-clustermarket-database-daily-backup-1683244800" + +cluster: + instances: 1 + +backups: + provider: s3 + s3: + region: "eu-west-1" + bucket: "db-backups" + path: "/v1-restore" + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + scheduledBackups: + - name: daily-backup # Daily at midnight + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + retentionPolicy: "30d" \ No newline at end of file diff --git a/charts/vshnpostgresql/examples/recovery-object_store.yaml b/charts/vshnpostgresql/examples/recovery-object_store.yaml new file mode 100644 index 0000000..060f532 --- /dev/null +++ b/charts/vshnpostgresql/examples/recovery-object_store.yaml @@ -0,0 +1,31 @@ +type: postgresql +mode: recovery + +recovery: + method: object_store + clusterName: "cluster-name-to-recover-from" + provider: s3 + s3: + region: "eu-west-1" + bucket: "db-backups" + path: "/v1-restore" + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + +cluster: + instances: 1 + +backups: + endpointURL: "https://cm-db-chart-test.ams3.digitaloceanspaces.com" + provider: s3 + s3: + region: "eu-west-1" + bucket: "db-backups" + path: "/v1-restore" + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + scheduledBackups: + - name: daily-backup # Daily at midnight + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml b/charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml new file mode 100644 index 0000000..05358bf --- /dev/null +++ b/charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml @@ -0,0 +1,15 @@ +type: postgresql +mode: "recovery" + +recovery: + method: "pg_basebackup" + pgBaseBackup: + sourceHost: "source-db.foo.com" + sourceUsername: "streaming_replica" + existingPasswordSecret: "source-db-replica-password" + +cluster: + instances: 1 + +backups: + enabled: false \ No newline at end of file diff --git a/charts/vshnpostgresql/examples/standalone-s3.yaml b/charts/vshnpostgresql/examples/standalone-s3.yaml new file mode 100644 index 0000000..44a4bb1 --- /dev/null +++ b/charts/vshnpostgresql/examples/standalone-s3.yaml @@ -0,0 +1,20 @@ +type: postgresql +mode: standalone + +cluster: + instances: 1 + +backups: + enabled: true + provider: s3 + s3: + region: "eu-west-1" + bucket: "db-backups" + path: "/v1" + accessKey: "AWS_S3_ACCESS_KEY" + secretKey: "AWS_S3_SECRET_KEY" + scheduledBackups: + - name: daily-backup # Daily at midnight + schedule: "0 0 0 * * *" # Daily at midnight + backupOwnerReference: self + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/examples/timescaledb.yaml b/charts/vshnpostgresql/examples/timescaledb.yaml new file mode 100644 index 0000000..328b6c1 --- /dev/null +++ b/charts/vshnpostgresql/examples/timescaledb.yaml @@ -0,0 +1,9 @@ +type: timescaledb +mode: standalone +version: + postgresql: "15.7" + timescaledb: "2.15" +cluster: + instances: 1 +backups: + enabled: false diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-ha-critical.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-ha-critical.yaml new file mode 100644 index 0000000..246a5af --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-ha-critical.yaml @@ -0,0 +1,26 @@ +{{- $alert := "CNPGClusterHACritical" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Cluster has no standby replicas! + description: |- + CloudNativePG Cluster "{{ .labels.job }}" has no ready standby replicas. Your cluster at a severe + risk of data loss and downtime if the primary instance fails. + + The primary instance is still online and able to serve queries, although connections to the `-ro` endpoint + will fail. The `-r` endpoint os operating at reduced capacity and all traffic is being served by the main. + + This can happen during a normal fail-over or automated minor version upgrades in a cluster with 2 or less + instances. The replaced instance may need some time to catch-up with the cluster primary instance. + + This alarm will be always trigger if your cluster is configured to run with only 1 instance. In this + case you may want to silence it. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterHACritical.md +expr: | + max by (job) (cnpg_pg_replication_streaming_replicas{namespace="{{ .namespace }}"} - cnpg_pg_replication_is_wal_receiver_up{namespace="{{ .namespace }}"}) < 1 +for: 5m +labels: + severity: critical + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-ha-warning.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-ha-warning.yaml new file mode 100644 index 0000000..736ddf3 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-ha-warning.yaml @@ -0,0 +1,24 @@ +{{- $alert := "CNPGClusterHAWarning" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Cluster less than 2 standby replicas. + description: |- + CloudNativePG Cluster "{{ .labels.job }}" has only {{ .value }} standby replicas, putting + your cluster at risk if another instance fails. The cluster is still able to operate normally, although + the `-ro` and `-r` endpoints operate at reduced capacity. + + This can happen during a normal fail-over or automated minor version upgrades. The replaced instance may + need some time to catch-up with the cluster primary instance. + + This alarm will be constantly triggered if your cluster is configured to run with less than 3 instances. + In this case you may want to silence it. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterHAWarning.md +expr: | + max by (job) (cnpg_pg_replication_streaming_replicas{namespace="{{ .namespace }}"} - cnpg_pg_replication_is_wal_receiver_up{namespace="{{ .namespace }}"}) < 2 +for: 5m +labels: + severity: warning + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-high_connection-critical.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-high_connection-critical.yaml new file mode 100644 index 0000000..df13ce3 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-high_connection-critical.yaml @@ -0,0 +1,17 @@ +{{- $alert := "CNPGClusterHighConnectionsCritical" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Instance maximum number of connections critical! + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" instance {{ .labels.pod }} is using {{ .value }}% of + the maximum number of connections. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterHighConnectionsCritical.md +expr: | + sum by (pod) (cnpg_backends_total{namespace="{{ .namespace }}", pod=~"{{ .podSelector }}"}) / max by (pod) (cnpg_pg_settings_setting{name="max_connections", namespace="{{ .namespace }}", pod=~"{{ .podSelector }}"}) * 100 > 95 +for: 5m +labels: + severity: critical + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-high_connection-warning.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-high_connection-warning.yaml new file mode 100644 index 0000000..73cc783 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-high_connection-warning.yaml @@ -0,0 +1,17 @@ +{{- $alert := "CNPGClusterHighConnectionsWarning" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Instance is approaching the maximum number of connections. + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" instance {{ .labels.pod }} is using {{ .value }}% of + the maximum number of connections. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterHighConnectionsWarning.md +expr: | + sum by (pod) (cnpg_backends_total{namespace="{{ .namespace }}", pod=~"{{ .podSelector }}"}) / max by (pod) (cnpg_pg_settings_setting{name="max_connections", namespace="{{ .namespace }}", pod=~"{{ .podSelector }}"}) * 100 > 80 +for: 5m +labels: + severity: warning + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-high_replication_lag.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-high_replication_lag.yaml new file mode 100644 index 0000000..660db25 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-high_replication_lag.yaml @@ -0,0 +1,19 @@ +{{- $alert := "CNPGClusterHighReplicationLag" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Cluster high replication lag + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" is experiencing a high replication lag of + {{ .value }}ms. + + High replication lag indicates network issues, busy instances, slow queries or suboptimal configuration. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterHighReplicationLag.md +expr: | + max(cnpg_pg_replication_lag{namespace="{{ .namespace }}",pod=~"{{ .podSelector }}"}) * 1000 > 1000 +for: 5m +labels: + severity: warning + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-instances_on_same_node.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-instances_on_same_node.yaml new file mode 100644 index 0000000..aafcfab --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-instances_on_same_node.yaml @@ -0,0 +1,19 @@ +{{- $alert := "CNPGClusterInstancesOnSameNode" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Cluster instances are located on the same node. + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" has {{ .value }} + instances on the same node {{ .labels.node }}. + + A failure or scheduled downtime of a single node will lead to a potential service disruption and/or data loss. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterInstancesOnSameNode.md +expr: | + count by (node) (kube_pod_info{namespace="{{ .namespace }}", pod=~"{{ .podSelector }}"}) > 1 +for: 5m +labels: + severity: warning + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-critical.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-critical.yaml new file mode 100644 index 0000000..c211bc6 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-critical.yaml @@ -0,0 +1,24 @@ +{{- $alert := "CNPGClusterLowDiskSpaceCritical" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Instance is running out of disk space! + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" is running extremely low on disk space. Check attached PVCs! + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md +expr: | + max(max by(persistentvolumeclaim) (1 - kubelet_volume_stats_available_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}"} / kubelet_volume_stats_capacity_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}"})) > 0.9 OR + max(max by(persistentvolumeclaim) (1 - kubelet_volume_stats_available_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-wal"} / kubelet_volume_stats_capacity_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-wal"})) > 0.9 OR + max(sum by (namespace,persistentvolumeclaim) (kubelet_volume_stats_used_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-tbs.*"}) + / + sum by (namespace,persistentvolumeclaim) (kubelet_volume_stats_capacity_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-tbs.*"}) + * + on(namespace, persistentvolumeclaim) group_left(volume) + kube_pod_spec_volumes_persistentvolumeclaims_info{pod=~"{{ .podSelector }}"} + ) > 0.9 +for: 5m +labels: + severity: critical + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-warning.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-warning.yaml new file mode 100644 index 0000000..5ed3653 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-low_disk_space-warning.yaml @@ -0,0 +1,24 @@ +{{- $alert := "CNPGClusterLowDiskSpaceWarning" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Instance is running out of disk space. + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" is running low on disk space. Check attached PVCs. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md +expr: | + max(max by(persistentvolumeclaim) (1 - kubelet_volume_stats_available_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}"} / kubelet_volume_stats_capacity_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}"})) > 0.7 OR + max(max by(persistentvolumeclaim) (1 - kubelet_volume_stats_available_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-wal"} / kubelet_volume_stats_capacity_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-wal"})) > 0.7 OR + max(sum by (namespace,persistentvolumeclaim) (kubelet_volume_stats_used_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-tbs.*"}) + / + sum by (namespace,persistentvolumeclaim) (kubelet_volume_stats_capacity_bytes{namespace="{{ .namespace }}", persistentvolumeclaim=~"{{ .podSelector }}-tbs.*"}) + * + on(namespace, persistentvolumeclaim) group_left(volume) + kube_pod_spec_volumes_persistentvolumeclaims_info{pod=~"{{ .podSelector }}"} + ) > 0.7 +for: 5m +labels: + severity: warning + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-offline.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-offline.yaml new file mode 100644 index 0000000..4206c02 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-offline.yaml @@ -0,0 +1,19 @@ +{{- $alert := "CNPGClusterOffline" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Cluster has no running instances! + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" has no ready instances. + + Having an offline cluster means your applications will not be able to access the database, leading to + potential service disruption and/or data loss. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterOffline.md +expr: | + (count(cnpg_collector_up{namespace="{{ .namespace }}",pod=~"{{ .podSelector }}"}) OR on() vector(0)) == 0 +for: 5m +labels: + severity: critical + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/prometheus_rules/cluster-zone_spread-warning.yaml b/charts/vshnpostgresql/prometheus_rules/cluster-zone_spread-warning.yaml new file mode 100644 index 0000000..41fa400 --- /dev/null +++ b/charts/vshnpostgresql/prometheus_rules/cluster-zone_spread-warning.yaml @@ -0,0 +1,18 @@ +{{- $alert := "CNPGClusterZoneSpreadWarning" -}} +{{- if not (has $alert .excludeRules) -}} +alert: {{ $alert }} +annotations: + summary: CNPG Cluster instances in the same zone. + description: |- + CloudNativePG Cluster "{{ .namespace }}/{{ .cluster }}" has instances in the same availability zone. + + A disaster in one availability zone will lead to a potential service disruption and/or data loss. + runbook_url: https://github.com/cloudnative-pg/charts/blob/main/charts/cluster/docs/runbooks/CNPGClusterZoneSpreadWarning.md +expr: | + {{ .Values.cluster.instances }} > count(count by (label_topology_kubernetes_io_zone) (kube_pod_info{namespace="{{ .namespace }}", pod=~"{{ .podSelector }}"} * on(node,instance) group_left(label_topology_kubernetes_io_zone) kube_node_labels)) < 3 +for: 5m +labels: + severity: warning + namespace: {{ .namespace }} + cnpg_cluster: {{ .cluster }} +{{- end -}} diff --git a/charts/vshnpostgresql/templates/NOTES.txt b/charts/vshnpostgresql/templates/NOTES.txt new file mode 100644 index 0000000..5e96a74 --- /dev/null +++ b/charts/vshnpostgresql/templates/NOTES.txt @@ -0,0 +1,102 @@ +{{- if .Values.pooler -}} + {{ fail ".Values.pooler has been deprecated. Use .Values.poolers instead." }} +{{- end -}} + +{{- if gt (omit .Values.cluster.postgresql "parameters" "synchronous" "pg_hba" "pg_ident" "syncReplicaElectionConstraint" "shared_preload_libraries" "ldap" "promotionTimeout" "enableAlterSystem" | keys | len) 0 -}} + {{ fail ".Values.cluster.postgresql has been deprecated. Use .Values.cluster.postgresql.parameters instead." }} +{{- end -}} + + +{{ if .Release.IsInstall }} +The {{ include "cluster.color-info" (include "cluster.fullname" .) }} has been installed successfully. +{{ else if .Release.IsUpgrade }} +The {{ include "cluster.color-info" (include "cluster.fullname" .) }} has been upgraded successfully. +{{ end }} + + ██████ ██ ██ ████ ██ ██ ██ ███████ ████████ + ██░░░░██ ░██ ░██░██░██ ░██ ░██ ░░ ░██░░░░██ ██░░░░░░██ + ██ ░░ ░██ ██████ ██ ██ ░██░██░░██ ░██ ██████ ██████ ██ ██ ██ █████ ░██ ░██ ██ ░░ +░██ ░██ ██░░░░██░██ ░██ ██████░██ ░░██ ░██ ░░░░░░██ ░░░██░ ░██░██ ░██ ██░░░██░███████ ░██ +░██ ░██░██ ░██░██ ░██ ██░░░██░██ ░░██░██ ███████ ░██ ░██░░██ ░██ ░███████░██░░░░ ░██ █████ +░░██ ██ ░██░██ ░██░██ ░██░██ ░██░██ ░░████ ██░░░░██ ░██ ░██ ░░████ ░██░░░░ ░██ ░░██ ░░░░██ + ░░██████ ███░░██████ ░░██████░░██████░██ ░░███░░████████ ░░██ ░██ ░░██ ░░██████░██ ░░████████ + ░░░░░░ ░░░ ░░░░░░ ░░░░░░ ░░░░░░ ░░ ░░░ ░░░░░░░░ ░░ ░░ ░░ ░░░░░░ ░░ ░░░░░░░░ + +Cheatsheet +---------- + +Run Helm Tests: +{{ include "cluster.color-info" (printf "helm test --namespace %s %s" .Release.Namespace .Release.Name) }} + +Get a list of all base backups: +{{ include "cluster.color-info" (printf "kubectl --namespace %s get backups --selector cnpg.io/cluster=%s" .Release.Namespace (include "cluster.fullname" .)) }} + +Connect to the cluster's primary instance: +{{ include "cluster.color-info" (printf "kubectl --namespace %s exec --stdin --tty services/%s-rw -- bash" .Release.Namespace (include "cluster.fullname" .)) }} + +Configuration +------------- + +{{- $redundancyColor := "" -}} +{{- if lt (int .Values.cluster.instances) 2 }} + {{- $redundancyColor = "error" -}} +{{- else if lt (int .Values.cluster.instances) 3 -}} + {{- $redundancyColor = "warning" -}} +{{- else -}} + {{- $redundancyColor = "ok" -}} +{{- end }} + +{{- $scheduledBackups := (first .Values.backups.scheduledBackups).name -}} +{{- range (rest .Values.backups.scheduledBackups) -}} + {{ $scheduledBackups = printf "%s, %s" $scheduledBackups .name }} +{{- end -}} +{{- if eq (len .Values.backups.scheduledBackups) 0 }} + {{- $scheduledBackups = "None" -}} +{{- end -}} + +{{- $mode := .Values.mode -}} +{{- $source := "" -}} +{{- if eq .Values.mode "recovery" }} +{{- $mode = printf "%s (%s)" .Values.mode .Values.recovery.method -}} + {{- if eq .Values.recovery.method "pg_basebackup" }} + {{- $source = printf "postgresql://%s@%s:%.0f/%s" .Values.recovery.pgBaseBackup.source.username .Values.recovery.pgBaseBackup.source.host .Values.recovery.pgBaseBackup.source.port .Values.recovery.pgBaseBackup.source.database -}} + {{- end -}} +{{- end -}} + +{{- $image := (include "cluster.image" .) | fromYaml -}} +{{- if $image.imageCatalogRef -}} + {{- $image = printf "%s: %s(%s)" $image.imageCatalogRef.kind $image.imageCatalogRef.name (include "cluster.postgresqlMajor" .) -}} +{{- else if $image.imageName -}} + {{- $image = $image.imageName -}} +{{- end }} + +╭───────────────────┬──────────────────────────────────────────────────────────╮ +│ Configuration │ Value │ +┝━━━━━━━━━━━━━━━━━━━┿━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┥ +│ Cluster mode │ {{ printf "%-56s" $mode }} │ +│ Type │ {{ printf "%-56s" .Values.type }} │ +│ Image │ {{ include "cluster.color-info" (printf "%-56s" $image) }} │ +{{- if eq .Values.mode "recovery" }} +│ Source │ {{ printf "%-56s" $source }} │ +{{- end }} +│ Instances │ {{ include (printf "%s%s" "cluster.color-" $redundancyColor) (printf "%-56s" (toString .Values.cluster.instances)) }} │ +│ Backups │ {{ include (printf "%s%s" "cluster.color-" (ternary "ok" "error" .Values.backups.enabled)) (printf "%-56s" (ternary "Enabled" "Disabled" .Values.backups.enabled)) }} │ +{{- if .Values.backups.enabled }} +│ Backup Provider │ {{ printf "%-56s" (title .Values.backups.provider) }} │ +│ Scheduled Backups │ {{ printf "%-56s" $scheduledBackups }} │ +{{- end }} +│ Storage │ {{ printf "%-56s" .Values.cluster.storage.size }} │ +│ Storage Class │ {{ printf "%-56s" (default "Default" .Values.cluster.storage.storageClass) }} │ +│ PGBouncer │ {{ printf "%-56s" (ternary "Enabled" "Disabled" (gt (len .Values.poolers) 0)) }} │ +│ Monitoring │ {{ include (printf "%s%s" "cluster.color-" (ternary "ok" "error" .Values.cluster.monitoring.enabled)) (printf "%-56s" (ternary "Enabled" "Disabled" .Values.cluster.monitoring.enabled)) }} │ +╰───────────────────┴──────────────────────────────────────────────────────────╯ + +{{ if not .Values.backups.enabled }} + {{- include "cluster.color-error" "Warning! Backups not enabled. Recovery will not be possible! Do not use this configuration in production.\n" }} +{{ end -}} + +{{ if lt (int .Values.cluster.instances) 2 }} + {{- include "cluster.color-error" "Warning! Instance failure will lead to downtime and/or data loss!\n" }} +{{- else if lt (int .Values.cluster.instances) 3 -}} + {{- include "cluster.color-warning" "Warning! Single instance redundancy available only. Instance failure will put the cluster at risk.\n" }} +{{ end -}} diff --git a/charts/vshnpostgresql/templates/_backup.tpl b/charts/vshnpostgresql/templates/_backup.tpl new file mode 100644 index 0000000..60270ea --- /dev/null +++ b/charts/vshnpostgresql/templates/_backup.tpl @@ -0,0 +1,23 @@ +{{- define "cluster.backup" -}} +{{- if .Values.backups.enabled }} +backup: + target: "prefer-standby" + retentionPolicy: {{ .Values.backups.retentionPolicy }} + barmanObjectStore: + wal: + compression: {{ .Values.backups.wal.compression }} + {{- if .Values.backups.wal.encryption }} + encryption: {{ .Values.backups.wal.encryption }} + {{- end }} + maxParallel: {{ .Values.backups.wal.maxParallel }} + data: + compression: {{ .Values.backups.data.compression }} + {{- if .Values.backups.data.encryption }} + encryption: {{ .Values.backups.data.encryption }} + {{- end }} + jobs: {{ .Values.backups.data.jobs }} + + {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.backups "secretPrefix" "backup" }} + {{- include "cluster.barmanObjectStoreConfig" $d | nindent 2 }} +{{- end }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/_barman_object_store.tpl b/charts/vshnpostgresql/templates/_barman_object_store.tpl new file mode 100644 index 0000000..c00e412 --- /dev/null +++ b/charts/vshnpostgresql/templates/_barman_object_store.tpl @@ -0,0 +1,75 @@ +{{- define "cluster.barmanObjectStoreConfig" -}} + +{{- if .scope.endpointURL }} + endpointURL: {{ .scope.endpointURL | quote }} +{{- end }} + +{{- if or (.scope.endpointCA.create) (.scope.endpointCA.name) }} + endpointCA: + name: {{.scope.endpointCA.name }} + key: {{ .scope.endpointCA.key }} +{{- end }} + +{{- if .scope.destinationPath }} + destinationPath: {{ .scope.destinationPath }} +{{- end }} + +{{- if eq .scope.provider "s3" }} + {{- if empty .scope.endpointURL }} + endpointURL: "https://s3.{{ required "You need to specify S3 region if endpointURL is not specified." .scope.s3.region }}.amazonaws.com" + {{- end }} + {{- if empty .scope.destinationPath }} + destinationPath: "s3://{{ required "You need to specify S3 bucket if destinationPath is not specified." .scope.s3.bucket }}{{ .scope.s3.path }}" + {{- end }} + {{- $secretName := coalesce .scope.secret.name (printf "%s-%s-s3-creds" .chartFullname .secretPrefix) }} + s3Credentials: + {{- if .scope.s3.inheritFromIAMRole }} + inheritFromIAMRole: true + {{- else }} + accessKeyId: + name: {{ $secretName }} + key: ACCESS_KEY_ID + secretAccessKey: + name: {{ $secretName }} + key: ACCESS_SECRET_KEY + {{- end }} +{{- else if eq .scope.provider "azure" }} + {{- if empty .scope.destinationPath }} + destinationPath: "https://{{ required "You need to specify Azure storageAccount if destinationPath is not specified." .scope.azure.storageAccount }}.{{ .scope.azure.serviceName }}.core.windows.net/{{ .scope.azure.containerName }}{{ .scope.azure.path }}" + {{- end }} + {{- $secretName := coalesce .scope.secret.name (printf "%s-%s-azure-creds" .chartFullname .secretPrefix) }} + azureCredentials: + {{- if .scope.azure.inheritFromAzureAD }} + inheritFromAzureAD: true + {{- else if .scope.azure.connectionString }} + connectionString: + name: {{ $secretName }} + key: AZURE_CONNECTION_STRING + {{- else }} + storageAccount: + name: {{ $secretName }} + key: AZURE_STORAGE_ACCOUNT + {{- if .scope.azure.storageKey }} + storageKey: + name: {{ $secretName }} + key: AZURE_STORAGE_KEY + {{- else }} + storageSasToken: + name: {{ $secretName }} + key: AZURE_STORAGE_SAS_TOKEN + {{- end }} + {{- end }} +{{- else if eq .scope.provider "google" }} + {{- if empty .scope.destinationPath }} + destinationPath: "gs://{{ required "You need to specify Google storage bucket if destinationPath is not specified." .scope.google.bucket }}{{ .scope.google.path }}" + {{- end }} + {{- $secretName := coalesce .scope.secret.name (printf "%s-%s-google-creds" .chartFullname .secretPrefix) }} + googleCredentials: + gkeEnvironment: {{ .scope.google.gkeEnvironment }} +{{- if not .scope.google.gkeEnvironment }} + applicationCredentials: + name: {{ $secretName }} + key: APPLICATION_CREDENTIALS +{{- end }} +{{- end -}} +{{- end -}} diff --git a/charts/vshnpostgresql/templates/_bootstrap.tpl b/charts/vshnpostgresql/templates/_bootstrap.tpl new file mode 100644 index 0000000..95bedd2 --- /dev/null +++ b/charts/vshnpostgresql/templates/_bootstrap.tpl @@ -0,0 +1,112 @@ +{{- define "cluster.bootstrap" -}} +{{- if eq .Values.mode "standalone" }} +bootstrap: + initdb: + {{- with .Values.cluster.initdb }} + {{- with (omit . "postInitApplicationSQL" "owner" "import") }} + {{- . | toYaml | nindent 4 }} + {{- end }} + {{- end }} + {{- if .Values.cluster.initdb.owner }} + owner: {{ tpl .Values.cluster.initdb.owner . }} + {{- end }} + {{- if or (eq .Values.type "postgis") (eq .Values.type "timescaledb") (not (empty .Values.cluster.initdb.postInitApplicationSQL)) }} + postInitApplicationSQL: + {{- if eq .Values.type "postgis" }} + - CREATE EXTENSION IF NOT EXISTS postgis; + - CREATE EXTENSION IF NOT EXISTS postgis_topology; + - CREATE EXTENSION IF NOT EXISTS fuzzystrmatch; + - CREATE EXTENSION IF NOT EXISTS postgis_tiger_geocoder; + {{- else if eq .Values.type "timescaledb" }} + - CREATE EXTENSION IF NOT EXISTS timescaledb; + {{- end }} + {{- with .Values.cluster.initdb }} + {{- range .postInitApplicationSQL }} + {{- printf "- %s" . | nindent 6 }} + {{- end -}} + {{- end -}} + {{- end }} +{{- else if eq .Values.mode "recovery" -}} +bootstrap: +{{- if eq .Values.recovery.method "pg_basebackup" }} + pg_basebackup: + source: pgBaseBackupSource + {{ with .Values.recovery.pgBaseBackup.database }} + database: {{ . }} + {{- end }} + {{ with .Values.recovery.pgBaseBackup.owner }} + owner: {{ . }} + {{- end }} + {{ with .Values.recovery.pgBaseBackup.secret }} + secret: + {{- toYaml . | nindent 6 }} + {{- end }} + +externalClusters: + {{- include "cluster.externalSourceCluster" (list "pgBaseBackupSource" .Values.recovery.pgBaseBackup.source) | nindent 2 }} + +{{- else if eq .Values.recovery.method "import" }} + initdb: + {{- with .Values.cluster.initdb }} + {{- with (omit . "owner" "import") }} + {{- . | toYaml | nindent 4 }} + {{- end }} + {{- end }} + {{- if .Values.cluster.initdb.owner }} + owner: {{ tpl .Values.cluster.initdb.owner . }} + {{- end }} + import: + source: + externalCluster: importSource + type: {{ .Values.recovery.import.type }} + databases: {{ .Values.recovery.import.databases | toJson }} + {{ with .Values.recovery.import.roles }} + roles: {{ . | toJson }} + {{- end }} + {{ with .Values.recovery.import.postImportApplicationSQL }} + postImportApplicationSQL: + {{- . | toYaml | nindent 6 }} + {{- end }} + schemaOnly: {{ .Values.recovery.import.schemaOnly }} + {{ with .Values.recovery.import.pgDumpExtraOptions }} + pgDumpExtraOptions: + {{- . | toYaml | nindent 6 }} + {{- end }} + {{ with .Values.recovery.import.pgRestoreExtraOptions }} + pgRestoreExtraOptions: + {{- . | toYaml | nindent 6 }} + {{- end }} + +externalClusters: + {{- include "cluster.externalSourceCluster" (list "importSource" .Values.recovery.import.source) | nindent 2 }} + +{{- else }} + recovery: + {{- with .Values.recovery.pitrTarget.time }} + recoveryTarget: + targetTime: {{ . }} + {{- end }} + {{ with .Values.recovery.database }} + database: {{ . }} + {{- end }} + {{ with .Values.recovery.owner }} + owner: {{ . }} + {{- end }} + {{- if eq .Values.recovery.method "backup" }} + backup: + name: {{ .Values.recovery.backupName }} + {{- else if eq .Values.recovery.method "object_store" }} + source: objectStoreRecoveryCluster + +externalClusters: + - name: objectStoreRecoveryCluster + barmanObjectStore: + serverName: {{ .Values.recovery.clusterName }} + {{- $d := dict "chartFullname" (include "cluster.fullname" .) "scope" .Values.recovery "secretPrefix" "recovery" -}} + {{- include "cluster.barmanObjectStoreConfig" $d | nindent 4 }} + {{- end }} +{{- end }} +{{- else }} + {{ fail "Invalid cluster mode!" }} +{{- end }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/_colorize.tpl b/charts/vshnpostgresql/templates/_colorize.tpl new file mode 100644 index 0000000..35b2ba1 --- /dev/null +++ b/charts/vshnpostgresql/templates/_colorize.tpl @@ -0,0 +1,12 @@ +{{- define "cluster.color-error" }} + {{- printf "\033[0;31m%s\033[0m" . -}} +{{- end }} +{{- define "cluster.color-ok" }} + {{- printf "\033[0;32m%s\033[0m" . -}} +{{- end }} +{{- define "cluster.color-warning" }} + {{- printf "\033[0;33m%s\033[0m" . -}} +{{- end }} +{{- define "cluster.color-info" }} + {{- printf "\033[0;34m%s\033[0m" . -}} +{{- end }} \ No newline at end of file diff --git a/charts/vshnpostgresql/templates/_external_source_cluster.tpl b/charts/vshnpostgresql/templates/_external_source_cluster.tpl new file mode 100644 index 0000000..6d21e20 --- /dev/null +++ b/charts/vshnpostgresql/templates/_external_source_cluster.tpl @@ -0,0 +1,33 @@ +{{- define "cluster.externalSourceCluster" -}} +{{- $name := first . -}} +{{- $config := last . -}} +- name: {{ first . }} + connectionParameters: + host: {{ $config.host | quote }} + port: {{ $config.port | quote }} + user: {{ $config.username | quote }} + {{- with $config.database }} + dbname: {{ . | quote }} + {{- end }} + sslmode: {{ $config.sslMode | quote }} + {{- if $config.passwordSecret.name }} + password: + name: {{ $config.passwordSecret.name }} + key: {{ $config.passwordSecret.key }} + {{- end }} + {{- if $config.sslKeySecret.name }} + sslKey: + name: {{ $config.sslKeySecret.name }} + key: {{ $config.sslKeySecret.key }} + {{- end }} + {{- if $config.sslCertSecret.name }} + sslCert: + name: {{ $config.sslCertSecret.name }} + key: {{ $config.sslCertSecret.key }} + {{- end }} + {{- if $config.sslRootCertSecret.name }} + sslRootCert: + name: {{ $config.sslRootCertSecret.name }} + key: {{ $config.sslRootCertSecret.key }} + {{- end }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/_helpers.tpl b/charts/vshnpostgresql/templates/_helpers.tpl new file mode 100644 index 0000000..2bae419 --- /dev/null +++ b/charts/vshnpostgresql/templates/_helpers.tpl @@ -0,0 +1,146 @@ +{{/* +Allow the release namespace to be overridden for multi-namespace deployments in combined charts +*/}} +{{- define "cluster.namespace" -}} + {{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} + {{- else -}} + {{- .Release.Namespace -}} + {{- end -}} +{{- end -}} + +{{/* +Expand the name of the chart. +*/}} +{{- define "cluster.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "cluster.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "cluster.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "cluster.labels" -}} +helm.sh/chart: {{ include "cluster.chart" . }} +{{ include "cluster.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "cluster.selectorLabels" -}} +app.kubernetes.io/name: {{ include "cluster.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +app.kubernetes.io/part-of: cloudnative-pg +{{- end }} + +{{/* +Whether we need to use TimescaleDB defaults +*/}} +{{- define "cluster.useTimescaleDBDefaults" -}} +{{ and (eq .Values.type "timescaledb") .Values.imageCatalog.create (empty .Values.cluster.imageCatalogRef.name) (empty .Values.imageCatalog.images) (empty .Values.cluster.imageName) }} +{{- end -}} + +{{/* +Get the PostgreSQL major version from .Values.version.postgresql +*/}} +{{- define "cluster.postgresqlMajor" -}} +{{ index (regexSplit "\\." (toString .Values.version.postgresql) 2) 0 }} +{{- end -}} + +{{/* +Cluster Image Name +If a custom imageName is available, use it, otherwise use the defaults based on the .Values.type +*/}} +{{- define "cluster.imageName" -}} + {{- if .Values.cluster.imageName -}} + {{- .Values.cluster.imageName -}} + {{- else if eq .Values.type "postgresql" -}} + {{- printf "ghcr.io/cloudnative-pg/postgresql:%s" .Values.version.postgresql -}} + {{- else if eq .Values.type "postgis" -}} + {{- printf "ghcr.io/cloudnative-pg/postgis:%s-%s" .Values.version.postgresql .Values.version.postgis -}} + {{- else -}} + {{ fail "Invalid cluster type!" }} + {{- end }} +{{- end -}} + +{{/* +Cluster Image +If imageCatalogRef defined, use it, otherwise calculate ordinary imageName. +*/}} +{{- define "cluster.image" }} +{{- if .Values.cluster.imageCatalogRef.name }} +imageCatalogRef: + apiGroup: postgresql.cnpg.io + {{- toYaml .Values.cluster.imageCatalogRef | nindent 2 }} + major: {{ include "cluster.postgresqlMajor" . }} +{{- else if and .Values.imageCatalog.create (not (empty .Values.imageCatalog.images )) }} +imageCatalogRef: + apiGroup: postgresql.cnpg.io + kind: ImageCatalog + name: {{ include "cluster.fullname" . }} + major: {{ include "cluster.postgresqlMajor" . }} +{{- else if eq (include "cluster.useTimescaleDBDefaults" .) "true" -}} +imageCatalogRef: + apiGroup: postgresql.cnpg.io + kind: ImageCatalog + name: {{ include "cluster.fullname" . }}-timescaledb-ha + major: {{ include "cluster.postgresqlMajor" . }} +{{- else }} +imageName: {{ include "cluster.imageName" . }} +{{- end }} +{{- end }} + +{{/* +Postgres UID +*/}} +{{- define "cluster.postgresUID" -}} + {{- if ge (int .Values.cluster.postgresUID) 0 -}} + {{- .Values.cluster.postgresUID }} + {{- else if and (eq (include "cluster.useTimescaleDBDefaults" .) "true") (eq .Values.type "timescaledb") -}} + {{- 1000 -}} + {{- else -}} + {{- 26 -}} + {{- end -}} +{{- end -}} + +{{/* +Postgres GID +*/}} +{{- define "cluster.postgresGID" -}} + {{- if ge (int .Values.cluster.postgresGID) 0 -}} + {{- .Values.cluster.postgresGID }} + {{- else if and (eq (include "cluster.useTimescaleDBDefaults" .) "true") (eq .Values.type "timescaledb") -}} + {{- 1000 -}} + {{- else -}} + {{- 26 -}} + {{- end -}} +{{- end -}} diff --git a/charts/vshnpostgresql/templates/backup-azure-creds.yaml b/charts/vshnpostgresql/templates/backup-azure-creds.yaml new file mode 100644 index 0000000..7d384ea --- /dev/null +++ b/charts/vshnpostgresql/templates/backup-azure-creds.yaml @@ -0,0 +1,12 @@ +{{- if and .Values.backups.enabled (eq .Values.backups.provider "azure") .Values.backups.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-backup-azure-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + AZURE_CONNECTION_STRING: {{ .Values.backups.azure.connectionString | b64enc | quote }} + AZURE_STORAGE_ACCOUNT: {{ .Values.backups.azure.storageAccount | b64enc | quote }} + AZURE_STORAGE_KEY: {{ .Values.backups.azure.storageKey | b64enc | quote }} + AZURE_STORAGE_SAS_TOKEN: {{ .Values.backups.azure.storageSasToken | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/backup-google-creds.yaml b/charts/vshnpostgresql/templates/backup-google-creds.yaml new file mode 100644 index 0000000..1b1f52f --- /dev/null +++ b/charts/vshnpostgresql/templates/backup-google-creds.yaml @@ -0,0 +1,9 @@ +{{- if and .Values.backups.enabled (eq .Values.backups.provider "google") .Values.backups.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-backup-google-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + APPLICATION_CREDENTIALS: {{ .Values.backups.google.applicationCredentials | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/backup-s3-creds.yaml b/charts/vshnpostgresql/templates/backup-s3-creds.yaml new file mode 100644 index 0000000..5585732 --- /dev/null +++ b/charts/vshnpostgresql/templates/backup-s3-creds.yaml @@ -0,0 +1,10 @@ +{{- if and .Values.backups.enabled (eq .Values.backups.provider "s3") (not .Values.backups.s3.inheritFromIAMRole) .Values.backups.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-backup-s3-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + ACCESS_KEY_ID: {{ required ".Values.backups.s3.accessKey is required, but not specified." .Values.backups.s3.accessKey | b64enc | quote }} + ACCESS_SECRET_KEY: {{ required ".Values.backups.s3.secretKey is required, but not specified." .Values.backups.s3.secretKey | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/ca-bundle.yaml b/charts/vshnpostgresql/templates/ca-bundle.yaml new file mode 100644 index 0000000..8f46f5a --- /dev/null +++ b/charts/vshnpostgresql/templates/ca-bundle.yaml @@ -0,0 +1,10 @@ +{{- if .Values.backups.endpointCA.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ .Values.backups.endpointCA.name | default (printf "%s-ca-bundle" (include "cluster.fullname" .)) | quote }} + namespace: {{ include "cluster.namespace" . }} +data: + {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" | quote }}: {{ .Values.backups.endpointCA.value }} + +{{- end }} diff --git a/charts/vshnpostgresql/templates/cluster.yaml b/charts/vshnpostgresql/templates/cluster.yaml new file mode 100644 index 0000000..bb9ea77 --- /dev/null +++ b/charts/vshnpostgresql/templates/cluster.yaml @@ -0,0 +1,145 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: {{ include "cluster.fullname" . }} + namespace: {{ include "cluster.namespace" . }} + {{- with .Values.cluster.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{- include "cluster.labels" . | nindent 4 }} + {{- with .Values.cluster.additionalLabels }} + {{ toYaml . | nindent 4 }} + {{- end }} +spec: + instances: {{ .Values.cluster.instances }} + {{- include "cluster.image" . | nindent 2 }} + imagePullPolicy: {{ .Values.cluster.imagePullPolicy }} + {{- with .Values.cluster.imagePullSecrets }} + imagePullSecrets: + {{- . | toYaml | nindent 4 }} + {{- end }} + postgresUID: {{ include "cluster.postgresUID" . }} + postgresGID: {{ include "cluster.postgresGID" . }} + storage: + size: {{ .Values.cluster.storage.size }} + {{- if not (empty .Values.cluster.storage.storageClass) }} + storageClass: {{ .Values.cluster.storage.storageClass }} + {{- end }} + {{- if .Values.cluster.walStorage.enabled }} + walStorage: + size: {{ .Values.cluster.walStorage.size }} + {{- if not (empty .Values.cluster.walStorage.storageClass) }} + storageClass: {{ .Values.cluster.walStorage.storageClass }} + {{- end }} + {{- end }} + {{- with .Values.cluster.resources }} + resources: + {{- toYaml . | nindent 4 }} + {{ end }} + {{- with .Values.cluster.affinity }} + affinity: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.cluster.env }} + env: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.cluster.envFrom }} + envFrom: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if .Values.cluster.priorityClassName }} + priorityClassName: {{ .Values.cluster.priorityClassName }} + {{- end }} + + primaryUpdateMethod: {{ .Values.cluster.primaryUpdateMethod }} + primaryUpdateStrategy: {{ .Values.cluster.primaryUpdateStrategy }} + logLevel: {{ .Values.cluster.logLevel }} + {{- with .Values.cluster.certificates }} + certificates: + {{- toYaml . | nindent 4 }} + {{ end }} + enableSuperuserAccess: {{ .Values.cluster.enableSuperuserAccess }} + {{- with .Values.cluster.superuserSecret }} + superuserSecret: + name: {{ . }} + {{ end }} + enablePDB: {{ .Values.cluster.enablePDB }} + postgresql: + {{- if or (eq .Values.type "timescaledb") (not (empty .Values.cluster.postgresql.shared_preload_libraries)) }} + shared_preload_libraries: + {{- if eq .Values.type "timescaledb" }} + - timescaledb + {{- end }} + {{- with .Values.cluster.postgresql.shared_preload_libraries }} + {{- toYaml . | nindent 6 }} + {{- end }} + {{- end }} + {{- with .Values.cluster.postgresql.pg_hba }} + pg_hba: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.cluster.postgresql.pg_ident }} + pg_ident: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.cluster.postgresql.ldap }} + ldap: + {{- toYaml . | nindent 6 }} + {{- end}} + {{- with .Values.cluster.postgresql.synchronous }} + synchronous: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- with .Values.cluster.postgresql.parameters }} + parameters: + {{- toYaml . | nindent 6 }} + {{- end }} + + {{- if not (and (empty .Values.cluster.roles) (empty .Values.cluster.services)) }} + managed: + {{- with .Values.cluster.services }} + services: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- with .Values.cluster.roles }} + roles: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- end }} + + {{- with .Values.cluster.serviceAccountTemplate }} + serviceAccountTemplate: + {{- toYaml . | nindent 4 }} + {{- end }} + + monitoring: + enablePodMonitor: {{ and .Values.cluster.monitoring.enabled .Values.cluster.monitoring.podMonitor.enabled }} + disableDefaultQueries: {{ .Values.cluster.monitoring.disableDefaultQueries }} + {{- if not (empty .Values.cluster.monitoring.customQueries) }} + customQueriesConfigMap: + - name: {{ include "cluster.fullname" . }}-monitoring + key: custom-queries + {{- end }} + {{- if not (empty .Values.cluster.monitoring.customQueriesSecret) }} + {{- with .Values.cluster.monitoring.customQueriesSecret }} + customQueriesSecret: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- end }} + {{- if not (empty .Values.cluster.monitoring.podMonitor.relabelings) }} + {{- with .Values.cluster.monitoring.podMonitor.relabelings }} + podMonitorRelabelings: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- end }} + {{- if not (empty .Values.cluster.monitoring.podMonitor.metricRelabelings) }} + {{- with .Values.cluster.monitoring.podMonitor.metricRelabelings }} + podMonitorMetricRelabelings: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- end }} + {{ include "cluster.bootstrap" . | nindent 2 }} + {{ include "cluster.backup" . | nindent 2 }} diff --git a/charts/vshnpostgresql/templates/image-catalog-timescaledb-ha.yaml b/charts/vshnpostgresql/templates/image-catalog-timescaledb-ha.yaml new file mode 100644 index 0000000..1a4422d --- /dev/null +++ b/charts/vshnpostgresql/templates/image-catalog-timescaledb-ha.yaml @@ -0,0 +1,19 @@ +{{- if eq (include "cluster.useTimescaleDBDefaults" .) "true" -}} +apiVersion: postgresql.cnpg.io/v1 +kind: ImageCatalog +metadata: + name: {{ include "cluster.fullname" . }}-timescaledb-ha + namespace: {{ include "cluster.namespace" . }} +spec: + images: + - major: 12 + image: timescale/timescaledb-ha:pg12-ts{{ .Values.version.timescaledb }} + - major: 13 + image: timescale/timescaledb-ha:pg13-ts{{ .Values.version.timescaledb }} + - major: 14 + image: timescale/timescaledb-ha:pg14-ts{{ .Values.version.timescaledb }} + - major: 15 + image: timescale/timescaledb-ha:pg15-ts{{ .Values.version.timescaledb }} + - major: 16 + image: timescale/timescaledb-ha:pg16-ts{{ .Values.version.timescaledb }} +{{ end }} diff --git a/charts/vshnpostgresql/templates/image-catalog.yaml b/charts/vshnpostgresql/templates/image-catalog.yaml new file mode 100644 index 0000000..e67e76f --- /dev/null +++ b/charts/vshnpostgresql/templates/image-catalog.yaml @@ -0,0 +1,13 @@ +{{ if and .Values.imageCatalog.create (not (empty .Values.imageCatalog.images )) }} +apiVersion: postgresql.cnpg.io/v1 +kind: ImageCatalog +metadata: + name: {{ include "cluster.fullname" . }} + namespace: {{ include "cluster.namespace" . }} +spec: + images: + {{- range $image := .Values.imageCatalog.images }} + - image: {{ $image.image }} + major: {{ $image.major }} + {{- end }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/pooler.yaml b/charts/vshnpostgresql/templates/pooler.yaml new file mode 100644 index 0000000..f97e8d9 --- /dev/null +++ b/charts/vshnpostgresql/templates/pooler.yaml @@ -0,0 +1,49 @@ +{{- range .Values.poolers }} +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Pooler +metadata: + name: {{ include "cluster.fullname" $ }}-pooler-{{ .name }} + namespace: {{ include "cluster.namespace" $ }} +spec: + cluster: + name: {{ include "cluster.fullname" $ }} + instances: {{ .instances }} + type: {{ default "rw" .type }} + pgbouncer: + poolMode: {{ default "session" .poolMode }} + {{- with .authQuerySecret }} + authQuerySecret: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .authQuery }} + authQuery: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .parameters }} + parameters: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .pg_hba }} + pg_hba: + {{- toYaml . | nindent 6 }} + {{- end }} + {{ with .monitoring }} + monitoring: + {{- if not (empty .podMonitor) }} + enablePodMonitor: {{ and .enabled .podMonitor.enabled }} + {{- with .podMonitor.relabelings }} + podMonitorRelabelings: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- with .podMonitor.metricRelabelings }} + podMonitorMetricRelabelings: + {{- toYaml . | nindent 6 }} + {{ end }} + {{- end }} + {{- end }} + {{- with .template }} + template: + {{- . | toYaml | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/prometheus-rule.yaml b/charts/vshnpostgresql/templates/prometheus-rule.yaml new file mode 100644 index 0000000..360b479 --- /dev/null +++ b/charts/vshnpostgresql/templates/prometheus-rule.yaml @@ -0,0 +1,30 @@ +{{- if and .Values.cluster.monitoring.enabled .Values.cluster.monitoring.prometheusRule.enabled -}} +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + labels: + {{- include "cluster.labels" . | nindent 4 }} + {{- with .Values.cluster.additionalLabels }} + {{ toYaml . | nindent 4 }} + {{- end }} + name: {{ include "cluster.fullname" . }}-alert-rules + namespace: {{ include "cluster.namespace" . }} +spec: + groups: + - name: cloudnative-pg/{{ include "cluster.fullname" . }} + rules: + {{- $dict := dict "excludeRules" .Values.cluster.monitoring.prometheusRule.excludeRules -}} + {{- $_ := set $dict "value" "{{ $value }}" -}} + {{- $_ := set $dict "namespace" .Release.Namespace -}} + {{- $_ := set $dict "cluster" (include "cluster.fullname" .) -}} + {{- $_ := set $dict "labels" (dict "job" "{{ $labels.job }}" "node" "{{ $labels.node }}" "pod" "{{ $labels.pod }}") -}} + {{- $_ := set $dict "podSelector" (printf "%s-([1-9][0-9]*)$" (include "cluster.fullname" .)) -}} + {{- $_ := set $dict "Values" .Values -}} + {{- $_ := set $dict "Template" .Template -}} + {{- range $path, $_ := .Files.Glob "prometheus_rules/**.yaml" }} + {{- $tpl := tpl ($.Files.Get $path) $dict | nindent 10 | trim -}} + {{- with $tpl }} + - {{ $tpl }} + {{- end -}} + {{- end -}} +{{ end }} diff --git a/charts/vshnpostgresql/templates/recovery-azure-creds.yaml b/charts/vshnpostgresql/templates/recovery-azure-creds.yaml new file mode 100644 index 0000000..fc4f676 --- /dev/null +++ b/charts/vshnpostgresql/templates/recovery-azure-creds.yaml @@ -0,0 +1,12 @@ +{{- if and (eq .Values.mode "recovery" ) (eq .Values.recovery.method "object_store") (eq .Values.recovery.provider "azure") .Values.recovery.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-recovery-azure-creds" (include "cluster.fullname" .)) .Values.recovery.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + AZURE_CONNECTION_STRING: {{ .Values.recovery.azure.connectionString | b64enc | quote }} + AZURE_STORAGE_ACCOUNT: {{ .Values.recovery.azure.storageAccount | b64enc | quote }} + AZURE_STORAGE_KEY: {{ .Values.recovery.azure.storageKey | b64enc | quote }} + AZURE_STORAGE_SAS_TOKEN: {{ .Values.recovery.azure.storageSasToken | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/recovery-google-creds.yaml b/charts/vshnpostgresql/templates/recovery-google-creds.yaml new file mode 100644 index 0000000..013e9d7 --- /dev/null +++ b/charts/vshnpostgresql/templates/recovery-google-creds.yaml @@ -0,0 +1,9 @@ +{{- if and (eq .Values.mode "recovery" ) (eq .Values.recovery.method "object_store") (eq .Values.recovery.provider "google") .Values.recovery.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-recovery-google-creds" (include "cluster.fullname" .)) .Values.recovery.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + APPLICATION_CREDENTIALS: {{ .Values.recovery.google.applicationCredentials | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/recovery-pg_basebackup-password.yaml b/charts/vshnpostgresql/templates/recovery-pg_basebackup-password.yaml new file mode 100644 index 0000000..b6f46a2 --- /dev/null +++ b/charts/vshnpostgresql/templates/recovery-pg_basebackup-password.yaml @@ -0,0 +1,9 @@ +{{- if and (eq .Values.mode "recovery") (eq .Values.recovery.method "pg_basebackup") .Values.recovery.pgBaseBackup.source.passwordSecret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-pg-basebackup-password" (include "cluster.fullname" .)) .Values.recovery.pgBaseBackup.source.passwordSecret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + {{ .Values.recovery.pgBaseBackup.source.passwordSecret.key }}: {{ required ".Values.recovery.pgBaseBackup.source.passwordSecret.value required when creating a password secret." .Values.recovery.pgBaseBackup.source.passwordSecret.value | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/recovery-s3-creds.yaml b/charts/vshnpostgresql/templates/recovery-s3-creds.yaml new file mode 100644 index 0000000..d70ed21 --- /dev/null +++ b/charts/vshnpostgresql/templates/recovery-s3-creds.yaml @@ -0,0 +1,10 @@ +{{- if and (eq .Values.mode "recovery" ) (eq .Values.recovery.method "object_store") (eq .Values.recovery.provider "s3") (not .Values.recovery.s3.inheritFromIAMRole) .Values.recovery.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-recovery-s3-creds" (include "cluster.fullname" .)) .Values.recovery.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + ACCESS_KEY_ID: {{ required ".Values.recovery.s3.accessKey is required, but not specified." .Values.recovery.s3.accessKey | b64enc | quote }} + ACCESS_SECRET_KEY: {{ required ".Values.recovery.s3.secretKey is required, but not specified." .Values.recovery.s3.secretKey | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/scheduled-backups.yaml b/charts/vshnpostgresql/templates/scheduled-backups.yaml new file mode 100644 index 0000000..47a0717 --- /dev/null +++ b/charts/vshnpostgresql/templates/scheduled-backups.yaml @@ -0,0 +1,19 @@ +{{ if .Values.backups.enabled }} +{{ $context := . -}} +{{ range .Values.backups.scheduledBackups -}} +--- +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: {{ include "cluster.fullname" $context }}-{{ .name }} + namespace: {{ include "cluster.namespace" $ }} + labels: {{ include "cluster.labels" $context | nindent 4 }} +spec: + immediate: true + schedule: {{ .schedule | quote }} + method: {{ .method }} + backupOwnerReference: {{ .backupOwnerReference }} + cluster: + name: {{ include "cluster.fullname" $context }} +{{ end -}} +{{ end }} diff --git a/charts/vshnpostgresql/templates/tests/ping.yaml b/charts/vshnpostgresql/templates/tests/ping.yaml new file mode 100644 index 0000000..aa911bd --- /dev/null +++ b/charts/vshnpostgresql/templates/tests/ping.yaml @@ -0,0 +1,44 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "cluster.fullname" . }}-ping-test + namespace: {{ include "cluster.namespace" . }} + labels: + app.kubernetes.io/component: database-ping-test + annotations: + "helm.sh/hook": test + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + template: + metadata: + name: {{ include "cluster.fullname" . }}-ping-test + labels: + app.kubernetes.io/component: database-ping-test + spec: + restartPolicy: Never + containers: + - name: alpine + image: alpine:3.17 + command: [ 'sh' ] + env: + - name: PGUSER + valueFrom: + secretKeyRef: + name: {{ include "cluster.fullname" . }}-app + key: username + - name: PGPASS + valueFrom: + secretKeyRef: + name: {{ include "cluster.fullname" . }}-app + key: password + - name: PGDBNAME + valueFrom: + secretKeyRef: + name: {{ include "cluster.fullname" . }}-app + key: dbname + optional: true + args: + - "-c" + - >- + apk add postgresql-client && + psql "postgresql://$PGUSER:$PGPASS@{{ include "cluster.fullname" . }}-rw.{{ include "cluster.namespace" . }}.svc.cluster.local:5432/${PGDBNAME:-$PGUSER}" -c 'SELECT 1' diff --git a/charts/vshnpostgresql/templates/user-metrics.yaml b/charts/vshnpostgresql/templates/user-metrics.yaml new file mode 100644 index 0000000..2ec310e --- /dev/null +++ b/charts/vshnpostgresql/templates/user-metrics.yaml @@ -0,0 +1,24 @@ +{{- if not (empty .Values.cluster.monitoring.customQueries) }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "cluster.fullname" . }}-monitoring + namespace: {{ include "cluster.namespace" . }} + labels: + cnpg.io/reload: "" + {{- include "cluster.labels" . | nindent 4 }} +data: + custom-queries: | + {{- range .Values.cluster.monitoring.customQueries }} + {{ .name }}: + query: {{ .query | quote }} + {{- with .target_databases }} + target_databases: {{ . | toJson }} + {{- end }} + {{- with .predicate_query }} + predicate_query: {{ tpl . $ | quote }} + {{- end }} + metrics: + {{- .metrics | toYaml | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/vshnpostgresql/test/monitoring/01-monitoring_cluster-assert.yaml b/charts/vshnpostgresql/test/monitoring/01-monitoring_cluster-assert.yaml new file mode 100644 index 0000000..017ac59 --- /dev/null +++ b/charts/vshnpostgresql/test/monitoring/01-monitoring_cluster-assert.yaml @@ -0,0 +1,135 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: monitoring-cluster + labels: + foo: bar + annotations: + foo: bar +spec: + instances: 2 + storage: + size: 256Mi + storageClass: standard + monitoring: + disableDefaultQueries: true + customQueriesConfigMap: + - name: monitoring-cluster-monitoring + key: custom-queries + enablePodMonitor: true + podMonitorRelabelings: + - action: replace + replacement: test + targetLabel: environment + - action: replace + replacement: alpha + targetLabel: team + podMonitorMetricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: monitoring-cluster +spec: + selector: + matchLabels: + cnpg.io/cluster: monitoring-cluster + podMetricsEndpoints: + - bearerTokenSecret: + key: '' + name: '' + relabelings: + - targetLabel: environment + replacement: test + - targetLabel: team + replacement: alpha + metricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: monitoring-cluster-pooler-rw +spec: + selector: + matchLabels: + cnpg.io/poolerName: monitoring-cluster-pooler-rw + podMetricsEndpoints: + - bearerTokenSecret: + key: '' + name: '' + relabelings: + - targetLabel: type + replacement: rw + action: replace + - targetLabel: team + replacement: alpha + action: replace + metricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster +--- +apiVersion: monitoring.coreos.com/v1 +kind: PodMonitor +metadata: + name: monitoring-cluster-pooler-ro +spec: + selector: + matchLabels: + cnpg.io/poolerName: monitoring-cluster-pooler-ro + podMetricsEndpoints: + - bearerTokenSecret: + key: '' + name: '' + relabelings: + - targetLabel: type + replacement: ro + action: replace + - targetLabel: team + replacement: alpha + action: replace + metricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster +--- +apiVersion: monitoring.coreos.com/v1 +kind: PrometheusRule +metadata: + name: monitoring-cluster-alert-rules +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: monitoring-cluster-monitoring +data: + custom-queries: | + pg_cache_hit_ratio: + query: "SELECT current_database() as datname, sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio FROM pg_statio_user_tables;" + target_databases: ["*"] + predicate_query: "SELECT 'postgresql';" + metrics: + - datname: + description: Name of the database + usage: LABEL + - ratio: + description: Cache hit ratio + usage: GAUGE diff --git a/charts/vshnpostgresql/test/monitoring/01-monitoring_cluster.yaml b/charts/vshnpostgresql/test/monitoring/01-monitoring_cluster.yaml new file mode 100644 index 0000000..314fccf --- /dev/null +++ b/charts/vshnpostgresql/test/monitoring/01-monitoring_cluster.yaml @@ -0,0 +1,80 @@ +type: postgresql +mode: standalone +cluster: + instances: 2 + storage: + size: 256Mi + storageClass: standard + monitoring: + enabled: true + disableDefaultQueries: true + customQueries: + - name: "pg_cache_hit_ratio" + query: "SELECT current_database() as datname, sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio FROM pg_statio_user_tables;" + target_databases: ["*"] + predicate_query: "SELECT '{{ .Values.type }}';" + metrics: + - datname: + usage: "LABEL" + description: "Name of the database" + - ratio: + usage: GAUGE + description: "Cache hit ratio" + podMonitor: + relabelings: + - targetLabel: environment + replacement: test + - targetLabel: team + replacement: alpha + metricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster + additionalLabels: + foo: bar + annotations: + foo: bar +backups: + enabled: false +poolers: + - name: rw + type: rw + instances: 1 + monitoring: + enabled: true + podMonitor: + enabled: true + relabelings: + - targetLabel: type + replacement: rw + - targetLabel: team + replacement: alpha + metricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster + - name: ro + type: ro + instances: 1 + monitoring: + enabled: true + podMonitor: + enabled: true + relabelings: + - targetLabel: type + replacement: ro + - targetLabel: team + replacement: alpha + metricRelabelings: + - action: replace + sourceLabels: + - cluster + targetLabel: cnpg_cluster + - action: labeldrop + regex: cluster diff --git a/charts/vshnpostgresql/test/monitoring/chainsaw-test.yaml b/charts/vshnpostgresql/test/monitoring/chainsaw-test.yaml new file mode 100644 index 0000000..ce647a4 --- /dev/null +++ b/charts/vshnpostgresql/test/monitoring/chainsaw-test.yaml @@ -0,0 +1,29 @@ +## +# This is a test that checks if PodMonitors, ConfigMaps and PrometheusRules are correctly provisioned when requested. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: monitoring +spec: + timeouts: + apply: 1s + assert: 20s + cleanup: 30s + steps: + - name: Install the monitoring cluster + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./01-monitoring_cluster.yaml \ + --wait \ + monitoring ../../ + - assert: + file: ./01-monitoring_cluster-assert.yaml + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE monitoring diff --git a/charts/vshnpostgresql/test/pooler/01-pooler_cluster-assert.yaml b/charts/vshnpostgresql/test/pooler/01-pooler_cluster-assert.yaml new file mode 100644 index 0000000..db23167 --- /dev/null +++ b/charts/vshnpostgresql/test/pooler/01-pooler_cluster-assert.yaml @@ -0,0 +1,37 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pooler-cluster-pooler-rw +status: + readyReplicas: 2 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: pooler-cluster-pooler-ro +status: + readyReplicas: 2 +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Pooler +metadata: + name: pooler-cluster-pooler-rw +spec: + cluster: + name: pooler-cluster + instances: 2 + pgbouncer: + poolMode: transaction + type: rw +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Pooler +metadata: + name: pooler-cluster-pooler-ro +spec: + cluster: + name: pooler-cluster + instances: 2 + pgbouncer: + poolMode: session + type: ro diff --git a/charts/vshnpostgresql/test/pooler/01-pooler_cluster.yaml b/charts/vshnpostgresql/test/pooler/01-pooler_cluster.yaml new file mode 100644 index 0000000..8fcbf65 --- /dev/null +++ b/charts/vshnpostgresql/test/pooler/01-pooler_cluster.yaml @@ -0,0 +1,17 @@ +type: postgresql +mode: standalone +cluster: + instances: 2 + storage: + size: 256Mi + storageClass: standard +backups: + enabled: false +poolers: + - name: rw + type: rw + instances: 2 + poolMode: transaction + - name: ro + type: ro + instances: 2 diff --git a/charts/vshnpostgresql/test/pooler/chainsaw-test.yaml b/charts/vshnpostgresql/test/pooler/chainsaw-test.yaml new file mode 100644 index 0000000..427b84e --- /dev/null +++ b/charts/vshnpostgresql/test/pooler/chainsaw-test.yaml @@ -0,0 +1,30 @@ +## +# This is a test that verifies that non-default configuration options are correctly propagated to the CNPG cluster. +# P.S. This test is not designed to have a good running configuration, it is designed to test the configuration propagation! +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: pooler +spec: + timeouts: + apply: 1s + assert: 20s + cleanup: 30s + steps: + - name: Install the non-default configuration cluster + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./01-pooler_cluster.yaml \ + --wait \ + pooler ../../ + - assert: + file: ./01-pooler_cluster-assert.yaml + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE pooler diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml new file mode 100644 index 0000000..bc5cce7 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster-assert.yaml @@ -0,0 +1,133 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: non-default-configuration-cluster + labels: + foo: bar + annotations: + foo: bar +spec: + imageName: ghcr.io/cloudnative-pg/crazycustomimage:99.99 + imagePullPolicy: Always + postgresUID: 1001 + postgresGID: 1002 + instances: 2 + postgresql: + ldap: + server: 'openldap.default.svc.cluster.local' + bindSearchAuth: + baseDN: 'ou=org,dc=example,dc=com' + bindDN: 'cn=admin,dc=example,dc=com' + bindPassword: + name: 'ldapBindPassword' + key: 'data' + searchAttribute: 'uid' + parameters: + max_connections: "42" + pg_hba: + - host all 1.2.3.4/32 trust + pg_ident: + - mymap /^(.*)@mydomain\.com$ \1 + shared_preload_libraries: + - pgaudit + synchronous: + method: any + number: 1 + bootstrap: + initdb: + database: mydb + owner: dante + secret: + name: mydb-secret + postInitApplicationSQL: + - CREATE TABLE mytable (id serial PRIMARY KEY, name VARCHAR(255)); + postInitTemplateSQL: + - CREATE TABLE mytable (id serial PRIMARY KEY, name VARCHAR(255)); + postInitSQL: + - CREATE TABLE mytable (id serial PRIMARY KEY, name VARCHAR(255)); + superuserSecret: + name: supersecret-secret + enableSuperuserAccess: true + enablePDB: false + certificates: + serverCASecret: ca-secret + serverTLSSecret: tls-secret + replicationTLSSecret: replication-tls-secret + clientCASecret: client-ca-secret + imagePullSecrets: + - name: image-pull-secret + storage: + size: 256Mi + storageClass: standard + walStorage: + size: 256Mi + storageClass: standard + affinity: + topologyKey: kubernetes.io/hostname + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - node1 + - node2 + env: + - name: MY_CUSTOM_FLAG + value: enabled + - name: MY_CUSTROM_ENV + valueFrom: + configMapKeyRef: + name: my-custom-env + key: env + optional: true + - name: MY_CUSTOM_SECRET_ENV + valueFrom: + secretKeyRef: + name: my-custom-secret + key: secret + optional: true + envFrom: + - configMapRef: + name: global-envs + optional: true + - secretRef: + name: db-credentials + optional: true + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 100m + memory: 256Mi + priorityClassName: mega-high + primaryUpdateStrategy: supervised + primaryUpdateMethod: restart + logLevel: warning + managed: + roles: + - name: dante + ensure: present + comment: Dante Alighieri + login: true + inRoles: + - pg_monitor + - pg_signal_backend + services: + additional: + - selectorType: rw + serviceTemplate: + metadata: + name: "test-lb" + labels: + test-label: "true" + annotations: + test-annotation: "true" + spec: + type: LoadBalancer + serviceAccountTemplate: + metadata: + annotations: + my-annotation: my-service-account diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml new file mode 100644 index 0000000..90f1a68 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/01-non_default_configuration_cluster.yaml @@ -0,0 +1,132 @@ +type: postgresql +mode: standalone +cluster: + instances: 2 + imageName: ghcr.io/cloudnative-pg/crazycustomimage:99.99 + imagePullPolicy: Always + imagePullSecrets: + - name: "image-pull-secret" + storage: + size: 256Mi + storageClass: standard + walStorage: + enabled: true + size: 256Mi + storageClass: standard + postgresUID: 1001 + postgresGID: 1002 + resources: + requests: + cpu: 100m + memory: 256Mi + limits: + cpu: 100m + memory: 256Mi + priorityClassName: mega-high + primaryUpdateMethod: restart + primaryUpdateStrategy: supervised + logLevel: warning + affinity: + topologyKey: kubernetes.io/hostname + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: kubernetes.io/hostname + operator: In + values: + - node1 + - node2 + env: + - name: MY_CUSTOM_FLAG + value: enabled + - name: MY_CUSTROM_ENV + valueFrom: + configMapKeyRef: + name: my-custom-env + key: env + optional: true + - name: MY_CUSTOM_SECRET_ENV + valueFrom: + secretKeyRef: + name: my-custom-secret + key: secret + optional: true + envFrom: + - configMapRef: + name: global-envs + optional: true + - secretRef: + name: db-credentials + optional: true + certificates: + serverCASecret: ca-secret + serverTLSSecret: tls-secret + replicationTLSSecret: replication-tls-secret + clientCASecret: client-ca-secret + enableSuperuserAccess: true + superuserSecret: supersecret-secret + enablePDB: false + services: + additional: + - selectorType: rw + serviceTemplate: + metadata: + name: "test-lb" + labels: + test-label: "true" + annotations: + test-annotation: "true" + spec: + type: LoadBalancer + roles: + - name: dante + ensure: present + comment: Dante Alighieri + login: true + inRoles: + - pg_monitor + - pg_signal_backend + postgresql: + ldap: + server: 'openldap.default.svc.cluster.local' + bindSearchAuth: + baseDN: 'ou=org,dc=example,dc=com' + bindDN: 'cn=admin,dc=example,dc=com' + bindPassword: + name: 'ldapBindPassword' + key: 'data' + searchAttribute: 'uid' + parameters: + max_connections: "42" + pg_hba: + - host all 1.2.3.4/32 trust + pg_ident: + - mymap /^(.*)@mydomain\.com$ \1 + shared_preload_libraries: + - pgaudit + synchronous: + method: any + number: 1 + initdb: + database: mydb + owner: dante + secret: + name: mydb-secret + postInitApplicationSQL: + - CREATE TABLE mytable (id serial PRIMARY KEY, name VARCHAR(255)); + postInitTemplateSQL: + - CREATE TABLE mytable (id serial PRIMARY KEY, name VARCHAR(255)); + postInitSQL: + - CREATE TABLE mytable (id serial PRIMARY KEY, name VARCHAR(255)); + additionalLabels: + foo: bar + annotations: + foo: bar + serviceAccountTemplate: + metadata: + annotations: + my-annotation: my-service-account + +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner-assert.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner-assert.yaml new file mode 100644 index 0000000..90c023a --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: recovery-object-store-database-owner-cluster +spec: + bootstrap: + recovery: + source: objectStoreRecoveryCluster + database: my-special-database + owner: me diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner.yaml new file mode 100644 index 0000000..21349ed --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/02-recovery_object_store_database_owner.yaml @@ -0,0 +1,15 @@ +type: postgresql +mode: recovery + +recovery: + method: object_store + database: my-special-database + owner: me + s3: + bucket: "mybucket" + accessKey: "minio" + secretKey: "minio123" + region: "local" + +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner-assert.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner-assert.yaml new file mode 100644 index 0000000..67f6780 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner-assert.yaml @@ -0,0 +1,11 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: recovery-backup-database-owner-cluster +spec: + bootstrap: + recovery: + backup: + name: post-init-backup + database: my-special-database + owner: me diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner.yaml new file mode 100644 index 0000000..e131cb3 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/03-recovery_backup_database_owner.yaml @@ -0,0 +1,16 @@ +type: postgresql +mode: recovery + +recovery: + method: backup + backupName: "post-init-backup" + database: my-special-database + owner: me + s3: + bucket: "mybucket" + accessKey: "minio" + secretKey: "minio123" + region: "local" + +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-cluster-configuration/chainsaw-test.yaml b/charts/vshnpostgresql/test/postgresql-cluster-configuration/chainsaw-test.yaml new file mode 100644 index 0000000..9eeb457 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-cluster-configuration/chainsaw-test.yaml @@ -0,0 +1,56 @@ +## +# This is a test that verifies that non-default configuration options are correctly propagated to the CNPG cluster. +# P.S. This test is not designed to have a good running configuration, it is designed to test the configuration propagation! +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: postgresql-cluster-configuration +spec: + timeouts: + apply: 1s + assert: 5s + cleanup: 30s + steps: + - name: Install the non-default configuration cluster + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./01-non_default_configuration_cluster.yaml \ + --wait \ + non-default-configuration ../../ + - assert: + file: ./01-non_default_configuration_cluster-assert.yaml + - name: Install object-store recovery-cluster for specific database and owner + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./02-recovery_object_store_database_owner.yaml \ + --wait \ + recovery-object-store-database-owner ../../ + - assert: + file: ./02-recovery_object_store_database_owner-assert.yaml + - name: Install backup recovery-cluster for specific database and owner + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./03-recovery_backup_database_owner.yaml \ + --wait \ + recovery-backup-database-owner ../../ + - assert: + file: ./03-recovery_backup_database_owner-assert.yaml + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE non-default-configuration + helm uninstall --namespace $NAMESPACE recovery-object-store-database-owner + helm uninstall --namespace $NAMESPACE recovery-backup-database-owner diff --git a/charts/vshnpostgresql/test/postgresql-import/00-source-cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-import/00-source-cluster-assert.yaml new file mode 100644 index 0000000..90ea90f --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/00-source-cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: source-cluster +status: + readyInstances: 1 diff --git a/charts/vshnpostgresql/test/postgresql-import/00-source-cluster.yaml b/charts/vshnpostgresql/test/postgresql-import/00-source-cluster.yaml new file mode 100644 index 0000000..790e208 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/00-source-cluster.yaml @@ -0,0 +1,9 @@ +type: postgresql +mode: "standalone" +cluster: + instances: 1 + superuserSecret: source-cluster-superuser + storage: + size: 256Mi +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-import/00-source-superuser-password.yaml b/charts/vshnpostgresql/test/postgresql-import/00-source-superuser-password.yaml new file mode 100644 index 0000000..b88a808 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/00-source-superuser-password.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: source-cluster-superuser +type: Opaque +data: + username: "cG9zdGdyZXM=" + password: "cG9zdGdyZXM=" diff --git a/charts/vshnpostgresql/test/postgresql-import/01-data_write-assert.yaml b/charts/vshnpostgresql/test/postgresql-import/01-data_write-assert.yaml new file mode 100644 index 0000000..831f963 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/01-data_write-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-import/01-data_write.yaml b/charts/vshnpostgresql/test/postgresql-import/01-data_write.yaml new file mode 100644 index 0000000..138fa8a --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/01-data_write.yaml @@ -0,0 +1,33 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-write + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: source-cluster-superuser + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: source-cluster-superuser + key: password + - name: DB_URI + value: postgres://$(DB_USER):$(DB_PASS)@source-cluster-rw:5432 + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + set -e + apk --no-cache add postgresql-client + psql "$DB_URI" -c "CREATE DATABASE mygooddb;" + psql "$DB_URI/mygooddb" -c "CREATE TABLE mygoodtable (id serial PRIMARY KEY);" + psql "$DB_URI/mygooddb" -c "INSERT INTO mygoodtable VALUES (314159265);" + psql "$DB_URI/mygooddb" -c "CREATE TABLE mybadtable (id serial PRIMARY KEY);" diff --git a/charts/vshnpostgresql/test/postgresql-import/02-import-cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-import/02-import-cluster-assert.yaml new file mode 100644 index 0000000..a194edc --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/02-import-cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: import-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-import/02-import-cluster.yaml b/charts/vshnpostgresql/test/postgresql-import/02-import-cluster.yaml new file mode 100644 index 0000000..b2de4cc --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/02-import-cluster.yaml @@ -0,0 +1,32 @@ +type: postgresql +mode: "recovery" +recovery: + method: "import" + import: + type: "microservice" + databases: [ "mygooddb" ] + pgDumpExtraOptions: + - --table=mygood* + source: + host: "source-cluster-rw" + username: "postgres" + passwordSecret: + name: source-cluster-superuser + key: password + sslMode: "require" + sslKeySecret: + name: source-cluster-replication + key: tls.key + sslCertSecret: + name: source-cluster-replication + key: tls.crt + +cluster: + instances: 2 + storage: + size: 256Mi + initdb: + database: mygooddb + +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-import/03-data_test-assert.yaml b/charts/vshnpostgresql/test/postgresql-import/03-data_test-assert.yaml new file mode 100644 index 0000000..04df941 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/03-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-import/03-data_test.yaml b/charts/vshnpostgresql/test/postgresql-import/03-data_test.yaml new file mode 100644 index 0000000..0c516d7 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/03-data_test.yaml @@ -0,0 +1,29 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: import-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + set -e + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" + echo "mygoodtable exist" + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mybadtable$$)' --csv -q 2>/dev/null)" = "f" + echo "mybadtable doesn't exist" + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT EXISTS (SELECT FROM mygoodtable WHERE id = 314159265)' --csv -q 2>/dev/null)" = "t" + echo "mygoodtable contains the desired value" diff --git a/charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only-assert.yaml b/charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only-assert.yaml new file mode 100644 index 0000000..f461b2b --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: import-schemaonly-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only.yaml b/charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only.yaml new file mode 100644 index 0000000..001e58b --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/04-import-cluster-schema_only.yaml @@ -0,0 +1,33 @@ +type: postgresql +mode: "recovery" +recovery: + method: "import" + import: + type: "microservice" + databases: [ "mygooddb" ] + pgRestoreExtraOptions: + - --table=mygoodtable + schemaOnly: true + source: + host: "source-cluster-rw" + username: "postgres" + passwordSecret: + name: source-cluster-superuser + key: password + sslMode: "require" + sslKeySecret: + name: source-cluster-replication + key: tls.key + sslCertSecret: + name: source-cluster-replication + key: tls.crt + +cluster: + instances: 2 + storage: + size: 256Mi + initdb: + database: mygooddb + +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-import/05-data_test-assert.yaml b/charts/vshnpostgresql/test/postgresql-import/05-data_test-assert.yaml new file mode 100644 index 0000000..b29534f --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/05-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-schemaonly +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-import/05-data_test.yaml b/charts/vshnpostgresql/test/postgresql-import/05-data_test.yaml new file mode 100644 index 0000000..0508468 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/05-data_test.yaml @@ -0,0 +1,29 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-schemaonly +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: import-schemaonly-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + set -e + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" + echo "mygoodtable exist" + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mybadtable$$)' --csv -q 2>/dev/null)" = "f" + echo "mybadtable doesn't exist" + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT COUNT(*) FROM mygoodtable' --csv -q 2>/dev/null)" = "0" + echo "mygoodtable is empty" diff --git a/charts/vshnpostgresql/test/postgresql-import/chainsaw-test.yaml b/charts/vshnpostgresql/test/postgresql-import/chainsaw-test.yaml new file mode 100644 index 0000000..f4b431f --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-import/chainsaw-test.yaml @@ -0,0 +1,97 @@ +## +# This test the CNPG PostgreSQL import capability. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: postgresql-import +spec: + timeouts: + apply: 1s + assert: 2m + cleanup: 1m + steps: + - name: Install the external PostgreSQL cluster + try: + - apply: + file: ./00-source-superuser-password.yaml + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./00-source-cluster.yaml \ + --wait \ + source ../../ + - assert: + file: ./00-source-cluster-assert.yaml + - apply: + file: ./01-data_write.yaml + - assert: + file: ./01-data_write-assert.yaml + - name: Install the import cluster + timeouts: + assert: 5m + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./02-import-cluster.yaml \ + --wait \ + import ../../ + - assert: + file: ./02-import-cluster-assert.yaml + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + - name: Verify the data exists + try: + - apply: + file: ./03-data_test.yaml + - assert: + file: ./03-data_test-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=data-test + - name: Install the schema-only import cluster + timeouts: + assert: 5m + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./04-import-cluster-schema_only.yaml \ + --wait \ + import-schemaonly ../../ + - assert: + file: ./04-import-cluster-schema_only-assert.yaml + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + - name: Verify only the schema exists + try: + - apply: + file: ./05-data_test.yaml + - assert: + file: ./05-data_test-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=data-test-schemaonly + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE source + helm uninstall --namespace $NAMESPACE import + helm uninstall --namespace $NAMESPACE import-schemaonly diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup-assert.yaml new file mode 100644 index 0000000..9c0f3eb --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: minio-cleanup +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup.yaml new file mode 100644 index 0000000..97cfc73 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/00-minio_cleanup.yaml @@ -0,0 +1,16 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: minio-cleanup +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: minio-cleanup + image: minio/mc + command: ['sh', '-c'] + args: + - | + mc alias set myminio https://minio.minio.svc.cluster.local minio minio123 + mc rm --recursive --force myminio/mybucket/postgresql-minio-backup-restore diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster-assert.yaml new file mode 100644 index 0000000..0663e78 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: standalone-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml new file mode 100644 index 0000000..7db3fe9 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/01-standalone_cluster.yaml @@ -0,0 +1,27 @@ +type: postgresql +mode: standalone + +cluster: + instances: 2 + storage: + size: 256Mi + +backups: + enabled: true + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/postgresql-minio-backup-restore/v1" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write-assert.yaml new file mode 100644 index 0000000..831f963 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write.yaml new file mode 100644 index 0000000..e674d8b --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/02-data_write.yaml @@ -0,0 +1,23 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-write + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: standalone-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + psql "$DB_URI" -c "CREATE TABLE mygoodtable (id serial PRIMARY KEY);" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup.yaml new file mode 100644 index 0000000..c3afd46 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: post-init-backup +spec: + method: barmanObjectStore + cluster: + name: standalone-cluster diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_completed-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_completed-assert.yaml new file mode 100644 index 0000000..7b1e9e5 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_completed-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: post-init-backup +spec: + cluster: + name: standalone-cluster + method: barmanObjectStore +status: + phase: completed diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_running-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_running-assert.yaml new file mode 100644 index 0000000..cbd9645 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-backup_running-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: post-init-backup +spec: + cluster: + name: standalone-cluster + method: barmanObjectStore +status: + phase: running diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-checkpoint.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-checkpoint.yaml new file mode 100644 index 0000000..52862bf --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/03-checkpoint.yaml @@ -0,0 +1,27 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: backup-checkpoint +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: create-checkpoint + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: standalone-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + END_TIME=$(( $(date +%s) + 30 )) + while [ $(date +%s) -lt $END_TIME ]; do + psql "$DB_URI" -c "SELECT pg_switch_wal();CHECKPOINT;" + sleep 5 + done diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write-assert.yaml new file mode 100644 index 0000000..ad9be77 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write-post-backup +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write.yaml new file mode 100644 index 0000000..2e56595 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/04-post_backup_data_write.yaml @@ -0,0 +1,57 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: configmap-creator-sa +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: configmap-creator +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: configmap-creator-binding +subjects: +- kind: ServiceAccount + name: configmap-creator-sa +roleRef: + kind: Role + name: configmap-creator + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write-post-backup +spec: + template: + spec: + serviceAccountName: configmap-creator-sa + restartPolicy: OnFailure + containers: + - name: data-write + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: standalone-cluster-superuser + key: uri + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client kubectl coreutils + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + DATE_NO_BAD_TABLE=$(date --rfc-3339=ns) + sleep 30 + psql "$DB_URI" -c "CREATE TABLE mybadtable (id serial PRIMARY KEY);" + kubectl create configmap date-no-bad-table --from-literal=date="$DATE_NO_BAD_TABLE" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster-assert.yaml new file mode 100644 index 0000000..90c4b24 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: recovery-backup-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml new file mode 100644 index 0000000..9eda6d9 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/05-recovery_backup_cluster.yaml @@ -0,0 +1,32 @@ +type: postgresql +mode: recovery + +cluster: + instances: 2 + storage: + size: 256Mi + +recovery: + method: backup + backupName: "post-init-backup" + provider: s3 + +backups: + enabled: true + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/postgresql-minio-backup-restore/v2" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test-assert.yaml new file mode 100644 index 0000000..2ef11b8 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-backup +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test.yaml new file mode 100644 index 0000000..86a1543 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/06-data_test.yaml @@ -0,0 +1,23 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-backup +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: recovery-backup-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster-assert.yaml new file mode 100644 index 0000000..f869303 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: recovery-object-store-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml new file mode 100644 index 0000000..7f059e3 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/07-recovery_object_store_cluster.yaml @@ -0,0 +1,48 @@ +type: postgresql +mode: recovery + +cluster: + instances: 2 + storage: + size: 256Mi + +recovery: + method: object_store + clusterName: "standalone-cluster" + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/postgresql-minio-backup-restore/v1" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" + +backups: + enabled: true + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/postgresql-minio-backup-restore/v2" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test-assert.yaml new file mode 100644 index 0000000..36eb4ff --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-object-store +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test.yaml new file mode 100644 index 0000000..94ac2c3 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/08-data_test.yaml @@ -0,0 +1,23 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-object-store +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: recovery-object-store-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster-assert.yaml new file mode 100644 index 0000000..2b6b965 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: recovery-backup-pitr-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml new file mode 100644 index 0000000..c2731b3 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/09-recovery_backup_pitr_cluster.yaml @@ -0,0 +1,48 @@ +type: postgresql +mode: recovery + +cluster: + instances: 2 + storage: + size: 256Mi + +recovery: + method: backup + backupName: "post-init-backup" + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/postgresql-minio-backup-restore/v1" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" + +backups: + enabled: true + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/postgresql-minio-backup-restore/v2" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test-assert.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test-assert.yaml new file mode 100644 index 0000000..6f14d5f --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-backup-pitr +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test.yaml new file mode 100644 index 0000000..5fb4faf --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/10-data_test.yaml @@ -0,0 +1,27 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-backup-pitr +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: recovery-backup-pitr-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + set -e + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" + echo "Good table exists" + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mybadtable$$)' --csv -q 2>/dev/null)" = "f" + echo "Bad table does not exist" diff --git a/charts/vshnpostgresql/test/postgresql-minio-backup-restore/chainsaw-test.yaml b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/chainsaw-test.yaml new file mode 100644 index 0000000..79a7d2d --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-minio-backup-restore/chainsaw-test.yaml @@ -0,0 +1,148 @@ +## +# This test sets up a CNPG cluster with MinIO backups and then restores the cluster from the backup using backup, +# object store, and object store with PITR recovery. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: postgresql-minio-backup-restore +spec: + timeouts: + apply: 1s + assert: 2m + cleanup: 1m + steps: + - name: Clear the MinIO bucket + try: + - apply: + file: ./00-minio_cleanup.yaml + - assert: + file: ./00-minio_cleanup-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=minio_cleanup + - name: Install the standalone cluster + try: + - script: + content: | + kubectl -n $NAMESPACE create secret generic kube-root-ca.crt --from-literal=ca.crt="$(kubectl -n kube-system get configmaps kube-root-ca.crt -o jsonpath='{.data.ca\.crt}')" --dry-run=client -o yaml | kubectl apply -f - + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./01-standalone_cluster.yaml \ + --wait \ + standalone ../../ + - assert: + file: 01-standalone_cluster-assert.yaml + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + - name: Write some data to the cluster + try: + - apply: + file: ./02-data_write.yaml + - assert: + file: ./02-data_write-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=data-write + - name: Create a backup + try: + - apply: + file: ./03-backup.yaml + - assert: + file: ./03-backup_running-assert.yaml + - apply: + file: ./03-checkpoint.yaml + - assert: + file: ./03-backup_completed-assert.yaml + - name: Write more data to the database after the backup + try: + - apply: + file: ./04-post_backup_data_write.yaml + - assert: + file: ./04-post_backup_data_write-assert.yaml + timeouts: + apply: 1s + assert: 10m + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Backup + - name: Create a recovery cluster from backup + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./05-recovery_backup_cluster.yaml \ + --wait \ + recovery-backup ../../ + - assert: + file: ./05-recovery_backup_cluster-assert.yaml + - name: Verify the data on the backup recovery cluster exists + try: + - apply: + file: 06-data_test.yaml + - assert: + file: 06-data_test-assert.yaml + - name: Create a recovery cluster from object store + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./07-recovery_object_store_cluster.yaml \ + --wait \ + recovery-object-store ../../ + - assert: + file: ./07-recovery_object_store_cluster-assert.yaml + - name: Verify the data on the object store recovery cluster exists + try: + - apply: + file: 08-data_test.yaml + - assert: + file: 08-data_test-assert.yaml + - name: Create a recovery cluster from backup with a PITR target + try: + - script: + content: | + DATE_NO_BAD_TABLE=$(kubectl -n $NAMESPACE get configmap date-no-bad-table -o 'jsonpath={.data.date}') + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./09-recovery_backup_pitr_cluster.yaml \ + --set recovery.pitrTarget.time="$DATE_NO_BAD_TABLE" \ + --wait \ + recovery-backup-pitr ../../ + - assert: + file: ./09-recovery_backup_pitr_cluster-assert.yaml + - name: Verify the pre-backup data on the recovery cluster exists but not the post-backup data + try: + - apply: + file: 10-data_test.yaml + - assert: + file: 10-data_test-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + selector: batch.kubernetes.io/job-name=data-test-backup-pitr + - podLogs: + selector: batch.kubernetes.io/job-name=data-test-backup-pitr + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE standalone + helm uninstall --namespace $NAMESPACE recovery-backup + helm uninstall --namespace $NAMESPACE recovery-object-store + helm uninstall --namespace $NAMESPACE recovery-backup-pitr diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster-assert.yaml new file mode 100644 index 0000000..90ea90f --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: source-cluster +status: + readyInstances: 1 diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster.yaml new file mode 100644 index 0000000..5d0baa1 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/00-source-cluster.yaml @@ -0,0 +1,8 @@ +type: postgresql +mode: "standalone" +cluster: + instances: 1 + storage: + size: 256Mi +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write-assert.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write-assert.yaml new file mode 100644 index 0000000..831f963 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write.yaml new file mode 100644 index 0000000..cc5a743 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/01-data_write.yaml @@ -0,0 +1,30 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-write + env: + - name: DB_USER + valueFrom: + secretKeyRef: + name: source-cluster-superuser + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: source-cluster-superuser + key: password + - name: DB_URI + value: postgres://$(DB_USER):$(DB_PASS)@source-cluster-rw:5432 + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + psql "$DB_URI" -c "CREATE DATABASE mygooddb;" + psql "$DB_URI/mygooddb" -c "CREATE TABLE mygoodtable (id serial PRIMARY KEY);" diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster-assert.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster-assert.yaml new file mode 100644 index 0000000..9b953d4 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: pg-basebackup-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml new file mode 100644 index 0000000..310074e --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/02-pg_basebackup-cluster.yaml @@ -0,0 +1,24 @@ +type: postgresql +mode: "recovery" +recovery: + method: "pg_basebackup" + pgBaseBackup: + source: + host: "source-cluster-rw" + database: "mygooddb" + username: "streaming_replica" + sslMode: "require" + sslKeySecret: + name: source-cluster-replication + key: tls.key + sslCertSecret: + name: source-cluster-replication + key: tls.crt + +cluster: + instances: 2 + storage: + size: 256Mi + +backups: + enabled: false diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test-assert.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test-assert.yaml new file mode 100644 index 0000000..04df941 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test.yaml new file mode 100644 index 0000000..40eb902 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/03-data_test.yaml @@ -0,0 +1,23 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: pg-basebackup-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + test "$(psql "${DB_URI}mygooddb" -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" diff --git a/charts/vshnpostgresql/test/postgresql-pg_basebackup/chainsaw-test.yaml b/charts/vshnpostgresql/test/postgresql-pg_basebackup/chainsaw-test.yaml new file mode 100644 index 0000000..85f2d97 --- /dev/null +++ b/charts/vshnpostgresql/test/postgresql-pg_basebackup/chainsaw-test.yaml @@ -0,0 +1,64 @@ +## +# This is a test that provisions a regular (non CNPG) PostgreSQL cluster and attempts to perform a pg_basebackup recovery. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: postgresql-pg-basebackup +spec: + timeouts: + apply: 1s + assert: 2m + cleanup: 1m + steps: + - name: Install the external PostgreSQL cluster + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./00-source-cluster.yaml \ + --wait \ + source ../../ + - assert: + file: ./00-source-cluster-assert.yaml + - apply: + file: ./01-data_write.yaml + - assert: + file: ./01-data_write-assert.yaml + - name: Install the pg_basebackup cluster + timeouts: + assert: 5m + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./02-pg_basebackup-cluster.yaml \ + --wait \ + pg-basebackup ../../ + - assert: + file: ./02-pg_basebackup-cluster-assert.yaml + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + - name: Verify the data from step 1 exists + try: + - apply: + file: ./03-data_test.yaml + - assert: + file: ./03-data_test-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=data-test + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE source + helm uninstall --namespace $NAMESPACE pg-basebackup diff --git a/charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup-assert.yaml b/charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup-assert.yaml new file mode 100644 index 0000000..9c0f3eb --- /dev/null +++ b/charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: minio-cleanup +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup.yaml b/charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup.yaml new file mode 100644 index 0000000..90151a9 --- /dev/null +++ b/charts/vshnpostgresql/test/scheduledbackups/00-minio_cleanup.yaml @@ -0,0 +1,16 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: minio-cleanup +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: minio-cleanup + image: minio/mc + command: ['sh', '-c'] + args: + - | + mc alias set myminio https://minio.minio.svc.cluster.local minio minio123 + mc rm --recursive --force myminio/mybucket/scheduledbackups diff --git a/charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster-assert.yaml b/charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster-assert.yaml new file mode 100644 index 0000000..a3af1a2 --- /dev/null +++ b/charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster-assert.yaml @@ -0,0 +1,37 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: scheduledbackups-cluster +status: + readyInstances: 1 +--- +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: scheduledbackups-cluster-daily-backup +spec: + immediate: true + schedule: "0 0 0 * * *" + method: barmanObjectStore + backupOwnerReference: self + cluster: + name: scheduledbackups-cluster +--- +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: scheduledbackups-cluster-weekly-backup +spec: + immediate: true + schedule: "0 0 0 * * 1" + method: barmanObjectStore + backupOwnerReference: self + cluster: + name: scheduledbackups-cluster +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +spec: + method: barmanObjectStore + cluster: + name: scheduledbackups-cluster diff --git a/charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster.yaml b/charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster.yaml new file mode 100644 index 0000000..c5ea25b --- /dev/null +++ b/charts/vshnpostgresql/test/scheduledbackups/01-scheduledbackups_cluster.yaml @@ -0,0 +1,36 @@ +type: postgresql +mode: standalone + +cluster: + instances: 1 + storage: + size: 256Mi + +backups: + enabled: true + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/scheduledbackups/v1" + accessKey: "minio" + secretKey: "minio123" + region: "local" + retentionPolicy: "30d" + scheduledBackups: + - name: daily-backup + schedule: "0 0 0 * * *" + backupOwnerReference: self + method: barmanObjectStore + - name: weekly-backup + schedule: "0 0 0 * * 1" + backupOwnerReference: self + method: barmanObjectStore + diff --git a/charts/vshnpostgresql/test/scheduledbackups/chainsaw-test.yaml b/charts/vshnpostgresql/test/scheduledbackups/chainsaw-test.yaml new file mode 100644 index 0000000..b72c53f --- /dev/null +++ b/charts/vshnpostgresql/test/scheduledbackups/chainsaw-test.yaml @@ -0,0 +1,27 @@ +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: scheduledbackups +spec: + timeouts: + apply: 1s + assert: 1m + cleanup: 5m + steps: + - name: Install the a cluster with ScheduledBackups + try: + - script: + content: | + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./01-scheduledbackups_cluster.yaml \ + --wait \ + scheduledbackups ../../ + - assert: + file: ./01-scheduledbackups_cluster-assert.yaml + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE scheduledbackups diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup-assert.yaml new file mode 100644 index 0000000..9c0f3eb --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: minio-cleanup +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup.yaml new file mode 100644 index 0000000..ce71b1e --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/00-minio_cleanup.yaml @@ -0,0 +1,16 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: minio-cleanup +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: minio-cleanup + image: minio/mc + command: ['sh', '-c'] + args: + - | + mc alias set myminio https://minio.minio.svc.cluster.local minio minio123 + mc rm --recursive --force myminio/mybucket/timescale diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster-assert.yaml new file mode 100644 index 0000000..3bbd2f8 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: timescale-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster.yaml new file mode 100644 index 0000000..f84117f --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/01-timescale_cluster.yaml @@ -0,0 +1,28 @@ +type: timescaledb +mode: standalone + +cluster: + instances: 2 + storage: + size: 256Mi + +backups: + enabled: true + + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/timescale/v1" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test-assert.yaml new file mode 100644 index 0000000..aa63a21 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: timescale-test +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test.yaml new file mode 100644 index 0000000..9b7581f --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/03-timescale_test.yaml @@ -0,0 +1,22 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: timescale-test +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: timescale-cluster-app + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM pg_extension WHERE extname = '\''timescaledb'\'')' --csv -q 2>/dev/null)" = "t" \ No newline at end of file diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write-assert.yaml new file mode 100644 index 0000000..831f963 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write.yaml new file mode 100644 index 0000000..b827de1 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/04-data_write.yaml @@ -0,0 +1,54 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: configmap-creator-sa +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: configmap-creator +rules: +- apiGroups: [""] + resources: ["configmaps"] + verbs: ["create"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: configmap-creator-binding +subjects: +- kind: ServiceAccount + name: configmap-creator-sa +roleRef: + kind: Role + name: configmap-creator + apiGroup: rbac.authorization.k8s.io +--- +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write +spec: + template: + spec: + serviceAccountName: configmap-creator-sa + restartPolicy: OnFailure + containers: + - name: data-write + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: timescale-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client kubectl coreutils + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + psql "$DB_URI" -c "CREATE TABLE mygoodtable (id serial PRIMARY KEY);" + sleep 5 + DATE_NO_BAD_TABLE=$(date --rfc-3339=ns) + kubectl create configmap date-no-bad-table --from-literal=date="$DATE_NO_BAD_TABLE" + sleep 5 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup.yaml new file mode 100644 index 0000000..be5e4b1 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: post-init-backup +spec: + method: barmanObjectStore + cluster: + name: timescale-cluster diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_completed-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_completed-assert.yaml new file mode 100644 index 0000000..040b1a4 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_completed-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: post-init-backup +spec: + cluster: + name: timescale-cluster + method: barmanObjectStore +status: + phase: completed diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_running-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_running-assert.yaml new file mode 100644 index 0000000..dc35727 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-backup_running-assert.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: post-init-backup +spec: + cluster: + name: timescale-cluster + method: barmanObjectStore +status: + phase: running diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-checkpoint.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-checkpoint.yaml new file mode 100644 index 0000000..3ba7fc7 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/05-checkpoint.yaml @@ -0,0 +1,27 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: backup-checkpoint +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: create-checkpoint + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: timescale-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + END_TIME=$(( $(date +%s) + 30 )) + while [ $(date +%s) -lt $END_TIME ]; do + psql "$DB_URI" -c "SELECT pg_switch_wal();CHECKPOINT;" + sleep 5 + done diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write-assert.yaml new file mode 100644 index 0000000..ad9be77 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write-post-backup +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write.yaml new file mode 100644 index 0000000..8585b24 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/06-post_backup_data_write.yaml @@ -0,0 +1,27 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-write-post-backup +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-write + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: timescale-cluster-superuser + key: uri + - name: NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + psql "$DB_URI" -c "CREATE TABLE mybadtable (id serial PRIMARY KEY);" diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster-assert.yaml new file mode 100644 index 0000000..2b6b965 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: recovery-backup-pitr-cluster +status: + readyInstances: 2 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster.yaml new file mode 100644 index 0000000..7e9c38f --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/07-recovery_backup_pitr_cluster.yaml @@ -0,0 +1,48 @@ +type: timescaledb +mode: recovery + +cluster: + instances: 2 + storage: + size: 256Mi + +recovery: + method: backup + backupName: "post-init-backup" + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/timescale/v1" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" + +backups: + enabled: true + provider: s3 + endpointURL: "https://minio.minio.svc.cluster.local" + endpointCA: + name: kube-root-ca.crt + key: ca.crt + wal: + encryption: "" + data: + encryption: "" + s3: + bucket: "mybucket" + path: "/timescale/v2" + accessKey: "minio" + secretKey: "minio123" + region: "local" + scheduledBackups: [] + retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test-assert.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test-assert.yaml new file mode 100644 index 0000000..6f14d5f --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test-assert.yaml @@ -0,0 +1,6 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-backup-pitr +status: + succeeded: 1 diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test.yaml new file mode 100644 index 0000000..5fb4faf --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/08-data_test.yaml @@ -0,0 +1,27 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: data-test-backup-pitr +spec: + template: + spec: + restartPolicy: OnFailure + containers: + - name: data-test + env: + - name: DB_URI + valueFrom: + secretKeyRef: + name: recovery-backup-pitr-cluster-superuser + key: uri + image: alpine:3.19 + command: ['sh', '-c'] + args: + - | + apk --no-cache add postgresql-client + DB_URI=$(echo $DB_URI | sed "s|/\*|/|" ) + set -e + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mygoodtable$$)' --csv -q 2>/dev/null)" = "t" + echo "Good table exists" + test "$(psql $DB_URI -t -c 'SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = $$mybadtable$$)' --csv -q 2>/dev/null)" = "f" + echo "Bad table does not exist" diff --git a/charts/vshnpostgresql/test/timescale-minio-backup-restore/chainsaw-test.yaml b/charts/vshnpostgresql/test/timescale-minio-backup-restore/chainsaw-test.yaml new file mode 100644 index 0000000..4961533 --- /dev/null +++ b/charts/vshnpostgresql/test/timescale-minio-backup-restore/chainsaw-test.yaml @@ -0,0 +1,129 @@ +## +# This test sets up a timescale cluster with MinIO backups and ensured that timescale extensions are installed and +# PITR recovery is enabled and working. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: timescale +spec: + timeouts: + apply: 1s + assert: 5m + cleanup: 1m + steps: + - name: Clear the MinIO bucket + try: + - apply: + file: ./00-minio_cleanup.yaml + - assert: + file: ./00-minio_cleanup-assert.yaml + - name: Install a standalone timescale cluster + try: + - script: + content: | + kubectl -n $NAMESPACE create secret generic kube-root-ca.crt --from-literal=ca.crt="$(kubectl -n kube-system get configmaps kube-root-ca.crt -o jsonpath='{.data.ca\.crt}')" --dry-run=client -o yaml | kubectl apply -f - + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./01-timescale_cluster.yaml \ + --wait \ + timescale ../../ + - assert: + file: ./01-timescale_cluster-assert.yaml + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + - podLogs: + selector: cnpg.io/cluster=timescale-cluster + - name: Verify timescale extensions are installed + timeouts: + apply: 1s + assert: 30s + try: + - apply: + file: 03-timescale_test.yaml + - assert: + file: 03-timescale_test-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=data-test + - name: Write some data to the cluster + timeouts: + apply: 1s + assert: 30s + try: + - apply: + file: 04-data_write.yaml + - assert: + file: 04-data_write-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + - podLogs: + selector: batch.kubernetes.io/job-name=data-test + - name: Create a backup + try: + - apply: + file: ./05-backup.yaml + - assert: + file: ./05-backup_running-assert.yaml + - apply: + file: ./05-checkpoint.yaml + - assert: + file: ./05-backup_completed-assert.yaml + - name: Write more data to the database after the backup + try: + - apply: + file: ./06-post_backup_data_write.yaml + - assert: + file: ./06-post_backup_data_write-assert.yaml + timeouts: + apply: 1s + assert: 10m + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Backup + - name: Create a recovery cluster from backup with a PITR target + try: + - script: + content: | + DATE_NO_BAD_TABLE=$(kubectl -n $NAMESPACE get configmap date-no-bad-table -o 'jsonpath={.data.date}') + helm upgrade \ + --install \ + --namespace $NAMESPACE \ + --values ./07-recovery_backup_pitr_cluster.yaml \ + --set recovery.pitrTarget.time="$DATE_NO_BAD_TABLE" \ + --wait \ + recovery-backup-pitr ../../ + - assert: + file: ./07-recovery_backup_pitr_cluster-assert.yaml + catch: + - describe: + apiVersion: postgresql.cnpg.io/v1 + kind: Cluster + - podLogs: + selector: cnpg.io/cluster=recovery-backup-pitr-cluster + - name: Verify the pre-backup data on the recovery cluster exists but not the post-backup data + try: + - apply: + file: 08-data_test.yaml + - assert: + file: 08-data_test-assert.yaml + catch: + - describe: + apiVersion: batch/v1 + kind: Job + selector: batch.kubernetes.io/job-name=data-test-backup-pitr + - podLogs: + selector: batch.kubernetes.io/job-name=data-test-backup-pitr + - name: Cleanup + try: + - script: + content: | + helm uninstall --namespace $NAMESPACE timescale diff --git a/charts/vshnpostgresql/values.schema.json b/charts/vshnpostgresql/values.schema.json new file mode 100644 index 0000000..8890226 --- /dev/null +++ b/charts/vshnpostgresql/values.schema.json @@ -0,0 +1,703 @@ +{ + "$schema": "http://json-schema.org/schema#", + "type": "object", + "properties": { + "backups": { + "type": "object", + "properties": { + "azure": { + "type": "object", + "properties": { + "connectionString": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "inheritFromAzureAD": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "storageAccount": { + "type": "string" + }, + "storageKey": { + "type": "string" + }, + "storageSasToken": { + "type": "string" + } + } + }, + "data": { + "type": "object", + "properties": { + "compression": { + "type": "string" + }, + "encryption": { + "type": "string" + }, + "jobs": { + "type": "integer" + } + } + }, + "destinationPath": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "endpointCA": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "endpointURL": { + "type": "string" + }, + "google": { + "type": "object", + "properties": { + "applicationCredentials": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "gkeEnvironment": { + "type": "boolean" + }, + "path": { + "type": "string" + } + } + }, + "provider": { + "type": "string" + }, + "retentionPolicy": { + "type": "string" + }, + "s3": { + "type": "object", + "properties": { + "accessKey": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "inheritFromIAMRole": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secretKey": { + "type": "string" + } + } + }, + "scheduledBackups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "backupOwnerReference": { + "type": "string" + }, + "method": { + "type": "string" + }, + "name": { + "type": "string" + }, + "schedule": { + "type": "string" + } + } + } + }, + "secret": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + }, + "wal": { + "type": "object", + "properties": { + "compression": { + "type": "string" + }, + "encryption": { + "type": "string" + }, + "maxParallel": { + "type": "integer" + } + } + } + } + }, + "cluster": { + "type": "object", + "properties": { + "additionalLabels": { + "type": "object" + }, + "affinity": { + "type": "object", + "properties": { + "topologyKey": { + "type": "string" + } + } + }, + "annotations": { + "type": "object" + }, + "certificates": { + "type": "object" + }, + "enablePDB": { + "type": "boolean" + }, + "enableSuperuserAccess": { + "type": "boolean" + }, + "env": { + "type": "array" + }, + "envFrom": { + "type": "array" + }, + "imageCatalogRef": { + "type": "object" + }, + "imageName": { + "type": "string" + }, + "imagePullPolicy": { + "type": "string" + }, + "imagePullSecrets": { + "type": "array" + }, + "initdb": { + "type": "object" + }, + "instances": { + "type": "integer" + }, + "logLevel": { + "type": "string" + }, + "monitoring": { + "type": "object", + "properties": { + "customQueries": { + "type": "array" + }, + "customQueriesSecret": { + "type": "array" + }, + "disableDefaultQueries": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "podMonitor": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "metricRelabelings": { + "type": "array" + }, + "relabelings": { + "type": "array" + } + } + }, + "prometheusRule": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "excludeRules": { + "type": "array" + } + } + } + } + }, + "postgresGID": { + "type": "integer" + }, + "postgresUID": { + "type": "integer" + }, + "postgresql": { + "type": "object", + "properties": { + "ldap": { + "type": "object" + }, + "parameters": { + "type": "object" + }, + "pg_hba": { + "type": "array" + }, + "pg_ident": { + "type": "array" + }, + "shared_preload_libraries": { + "type": "array" + }, + "synchronous": { + "type": "object" + } + } + }, + "primaryUpdateMethod": { + "type": "string" + }, + "primaryUpdateStrategy": { + "type": "string" + }, + "priorityClassName": { + "type": "string" + }, + "resources": { + "type": "object" + }, + "roles": { + "type": "array" + }, + "serviceAccountTemplate": { + "type": "object" + }, + "services": { + "type": "object" + }, + "storage": { + "type": "object", + "properties": { + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + }, + "superuserSecret": { + "type": "string" + }, + "walStorage": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean" + }, + "size": { + "type": "string" + }, + "storageClass": { + "type": "string" + } + } + } + } + }, + "fullnameOverride": { + "type": "string" + }, + "imageCatalog": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "images": { + "type": "array" + } + } + }, + "mode": { + "type": "string" + }, + "nameOverride": { + "type": "string" + }, + "namespaceOverride": { + "type": "string" + }, + "poolers": { + "type": "array" + }, + "recovery": { + "type": "object", + "properties": { + "azure": { + "type": "object", + "properties": { + "connectionString": { + "type": "string" + }, + "containerName": { + "type": "string" + }, + "inheritFromAzureAD": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "serviceName": { + "type": "string" + }, + "storageAccount": { + "type": "string" + }, + "storageKey": { + "type": "string" + }, + "storageSasToken": { + "type": "string" + } + } + }, + "backupName": { + "type": "string" + }, + "clusterName": { + "type": "string" + }, + "database": { + "type": "string" + }, + "destinationPath": { + "type": "string" + }, + "endpointCA": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "endpointURL": { + "type": "string" + }, + "google": { + "type": "object", + "properties": { + "applicationCredentials": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "gkeEnvironment": { + "type": "boolean" + }, + "path": { + "type": "string" + } + } + }, + "import": { + "type": "object", + "properties": { + "databases": { + "type": "array" + }, + "pgDumpExtraOptions": { + "type": "array" + }, + "pgRestoreExtraOptions": { + "type": "array" + }, + "postImportApplicationSQL": { + "type": "array" + }, + "roles": { + "type": "array" + }, + "schemaOnly": { + "type": "boolean" + }, + "source": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "host": { + "type": "string" + }, + "passwordSecret": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "port": { + "type": "integer" + }, + "sslCertSecret": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "sslKeySecret": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "sslMode": { + "type": "string" + }, + "sslRootCertSecret": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "username": { + "type": "string" + } + } + }, + "type": { + "type": "string" + } + } + }, + "method": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "pgBaseBackup": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "secret": { + "type": "string" + }, + "source": { + "type": "object", + "properties": { + "database": { + "type": "string" + }, + "host": { + "type": "string" + }, + "passwordSecret": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "key": { + "type": "string" + }, + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + } + }, + "port": { + "type": "integer" + }, + "sslCertSecret": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "sslKeySecret": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "sslMode": { + "type": "string" + }, + "sslRootCertSecret": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "username": { + "type": "string" + } + } + } + } + }, + "pitrTarget": { + "type": "object", + "properties": { + "time": { + "type": "string" + } + } + }, + "provider": { + "type": "string" + }, + "s3": { + "type": "object", + "properties": { + "accessKey": { + "type": "string" + }, + "bucket": { + "type": "string" + }, + "inheritFromIAMRole": { + "type": "boolean" + }, + "path": { + "type": "string" + }, + "region": { + "type": "string" + }, + "secretKey": { + "type": "string" + } + } + }, + "secret": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "name": { + "type": "string" + } + } + } + } + }, + "type": { + "type": "string" + }, + "version": { + "type": "object", + "properties": { + "postgis": { + "type": "string" + }, + "postgresql": { + "type": "string" + }, + "timescaledb": { + "type": "string" + } + } + } + } +} diff --git a/charts/vshnpostgresql/values.yaml b/charts/vshnpostgresql/values.yaml new file mode 100644 index 0000000..3d5f11d --- /dev/null +++ b/charts/vshnpostgresql/values.yaml @@ -0,0 +1,530 @@ +# -- Override the name of the chart +nameOverride: "" +# -- Override the full name of the chart +fullnameOverride: "" +# -- Override the namespace of the chart +namespaceOverride: "" + +### +# -- Type of the CNPG database. Available types: +# * `postgresql` +# * `postgis` +# * `timescaledb` +type: postgresql + +version: + # -- PostgreSQL major version to use + postgresql: "16" + # -- If using TimescaleDB, specify the version + timescaledb: "2.15" + # -- If using PostGIS, specify the version + postgis: "3.4" + +### +# -- Cluster mode of operation. Available modes: +# * `standalone` - default mode. Creates new or updates an existing CNPG cluster. +# * `replica` - Creates a replica cluster from an existing CNPG cluster. # TODO +# * `recovery` - Same as standalone but creates a cluster from a backup, object store or via pg_basebackup. +mode: standalone + +recovery: + ## + # -- Available recovery methods: + # * `backup` - Recovers a CNPG cluster from a CNPG backup (PITR supported) Needs to be on the same cluster in the same namespace. + # * `object_store` - Recovers a CNPG cluster from a barman object store (PITR supported). + # * `pg_basebackup` - Recovers a CNPG cluster viaa streaming replication protocol. Useful if you want to + # migrate databases to CloudNativePG, even from outside Kubernetes. + # * `import` - Import one or more databases from an existing Postgres cluster. + method: backup + + ## -- Point in time recovery target. Specify one of the following: + pitrTarget: + # -- Time in RFC3339 format + time: "" + + ## + # -- Backup Recovery Method + backupName: "" # Name of the backup to recover from. Required if method is `backup`. + + ## + # -- The original cluster name when used in backups. Also known as serverName. + clusterName: "" + # -- Name of the database used by the application. Default: `app`. + database: app + # -- Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. + owner: "" + # -- Overrides the provider specific default endpoint. Defaults to: + # S3: https://s3..amazonaws.com" + # Leave empty if using the default S3 endpoint + endpointURL: "" + # -- Specifies a CA bundle to validate a privately signed certificate. + endpointCA: + # -- Creates a secret with the given value if true, otherwise uses an existing secret. + create: false + name: "" + key: "" + value: "" + # -- Overrides the provider specific default path. Defaults to: + # S3: s3:// + # Azure: https://..core.windows.net/ + # Google: gs:// + destinationPath: "" + # -- One of `s3`, `azure` or `google` + provider: s3 + s3: + region: "" + bucket: "" + path: "/" + accessKey: "" + secretKey: "" + # -- Use the role based authentication without providing explicitly the keys + inheritFromIAMRole: false + azure: + path: "/" + connectionString: "" + storageAccount: "" + storageKey: "" + storageSasToken: "" + containerName: "" + serviceName: blob + inheritFromAzureAD: false + google: + path: "/" + bucket: "" + gkeEnvironment: false + applicationCredentials: "" + secret: + # -- Whether to create a secret for the backup credentials + create: true + # -- Name of the backup credentials secret + name: "" + + # See https://cloudnative-pg.io/documentation/current/bootstrap/#bootstrap-from-a-live-cluster-pg_basebackup + pgBaseBackup: + # -- Name of the database used by the application. Default: `app`. + database: app + # -- Name of the secret containing the initial credentials for the owner of the user database. If empty a new secret will be created from scratch + secret: "" + # -- Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. + owner: "" + source: + host: "" + port: 5432 + username: "" + database: "app" + sslMode: "verify-full" + passwordSecret: + # -- Whether to create a secret for the password + create: false + # -- Name of the secret containing the password + name: "" + # -- The key in the secret containing the password + key: "password" + # -- The password value to use when creating the secret + value: "" + sslKeySecret: + name: "" + key: "" + sslCertSecret: + name: "" + key: "" + sslRootCertSecret: + name: "" + key: "" + + # See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-Import + import: + # -- One of `microservice` or `monolith.` + # See: https://cloudnative-pg.io/documentation/current/database_import/#how-it-works + type: "microservice" + # -- Databases to import + databases: [] + # -- Roles to import + roles: [] + # -- List of SQL queries to be executed as a superuser in the application database right after is imported. + # To be used with extreme care. Only available in microservice type. + postImportApplicationSQL: [] + # -- When set to true, only the pre-data and post-data sections of pg_restore are invoked, avoiding data import. + schemaOnly: false + # -- List of custom options to pass to the `pg_dump` command. IMPORTANT: Use these options with caution and at your + # own risk, as the operator does not validate their content. Be aware that certain options may conflict with the + # operator's intended functionality or design. + pgDumpExtraOptions: [] + # -- List of custom options to pass to the `pg_restore` command. IMPORTANT: Use these options with caution and at + # your own risk, as the operator does not validate their content. Be aware that certain options may conflict with the + # operator's intended functionality or design. + pgRestoreExtraOptions: [] + source: + host: "" + port: 5432 + username: "" + database: "" + sslMode: "verify-full" + passwordSecret: + # -- Whether to create a secret for the password + create: false + # -- Name of the secret containing the password + name: "" + # -- The key in the secret containing the password + key: "password" + # -- The password value to use when creating the secret + value: "" + sslKeySecret: + name: "" + key: "" + sslCertSecret: + name: "" + key: "" + sslRootCertSecret: + name: "" + key: "" + + +cluster: + # -- Number of instances + instances: 3 + + # -- Name of the container image, supporting both tags (:) and digests for deterministic and repeatable deployments: + # :@sha256: + imageName: "" # Default value depends on type (postgresql/postgis/timescaledb) + + # -- Reference to `ImageCatalog` of `ClusterImageCatalog`, if specified takes precedence over `cluster.imageName` + imageCatalogRef: {} + # kind: ImageCatalog + # name: postgresql + + # -- Image pull policy. One of Always, Never or IfNotPresent. If not defined, it defaults to IfNotPresent. Cannot be updated. + # More info: https://kubernetes.io/docs/concepts/containers/images#updating-images + imagePullPolicy: IfNotPresent + + # -- The list of pull secrets to be used to pull the images. + # See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-LocalObjectReference + imagePullSecrets: [] + + storage: + size: 8Gi + storageClass: "" + + walStorage: + enabled: false + size: 1Gi + storageClass: "" + + # -- The UID of the postgres user inside the image, defaults to 26 + postgresUID: -1 + + # -- The GID of the postgres user inside the image, defaults to 26 + postgresGID: -1 + + # -- Customization of service definitions. Please refer to https://cloudnative-pg.io/documentation/current/service_management/ + services: {} + + # -- Resources requirements of every generated Pod. + # Please refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for more information. + # We strongly advise you use the same setting for limits and requests so that your cluster pods are given a Guaranteed QoS. + # See: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ + resources: {} + # limits: + # cpu: 2000m + # memory: 8Gi + # requests: + # cpu: 2000m + # memory: 8Gi + + priorityClassName: "" + + # -- Method to follow to upgrade the primary server during a rolling update procedure, after all replicas have been + # successfully updated. It can be switchover (default) or restart. + primaryUpdateMethod: switchover + + # -- Strategy to follow to upgrade the primary server during a rolling update procedure, after all replicas have been + # successfully updated: it can be automated (unsupervised - default) or manual (supervised) + primaryUpdateStrategy: unsupervised + + # -- The instances' log level, one of the following values: error, warning, info (default), debug, trace + logLevel: "info" + + # -- Affinity/Anti-affinity rules for Pods. + # See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-AffinityConfiguration + affinity: + topologyKey: topology.kubernetes.io/zone + + # -- Env follows the Env format to pass environment variables to the pods created in the cluster + env: [] + # - name: MY_CUSTOM_FLAG + # value: "enabled" + # - name: MY_CUSTROM_ENV + # valueFrom: + # configMapKeyRef: + # name: my-custom-env + # key: env + # optional: true + # - name: MY_CUSTOM_SECRET_ENV + # valueFrom: + # secretKeyRef: + # name: my-custom-secret + # key: secret + # optional: true + + # -- EnvFrom follows the EnvFrom format to pass environment variables sources to the pods to be used by Env + envFrom: [] + # - configMapRef: + # name: global-envs + # optional: true + # - secretRef: + # name: db-credentials + # optional: true + + # -- The configuration for the CA and related certificates. + # See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-CertificatesConfiguration + certificates: {} + + # -- When this option is enabled, the operator will use the SuperuserSecret to update the postgres user password. + # If the secret is not present, the operator will automatically create one. + # When this option is disabled, the operator will ignore the SuperuserSecret content, delete it when automatically created, + # and then blank the password of the postgres user by setting it to NULL. + enableSuperuserAccess: true + superuserSecret: "" + + # -- Allow to disable PDB, mainly useful for upgrade of single-instance clusters or development purposes + # See: https://cloudnative-pg.io/documentation/current/kubernetes_upgrade/#pod-disruption-budgets + enablePDB: true + + # -- This feature enables declarative management of existing roles, as well as the creation of new roles if they are not + # already present in the database. + # See: https://cloudnative-pg.io/documentation/current/declarative_role_management/ + roles: [] + # - name: dante + # ensure: present + # comment: Dante Alighieri + # login: true + # superuser: false + # inRoles: + # - pg_monitor + # - pg_signal_backend + + monitoring: + # -- Whether to enable monitoring + enabled: false + podMonitor: + # -- Whether to enable the PodMonitor + enabled: true + # --The list of relabelings for the PodMonitor. + # Applied to samples before scraping. + relabelings: [] + # -- The list of metric relabelings for the PodMonitor. + # Applied to samples before ingestion. + metricRelabelings: [] + prometheusRule: + # -- Whether to enable the PrometheusRule automated alerts + enabled: true + # -- Exclude specified rules + excludeRules: [] + # - CNPGClusterZoneSpreadWarning + # -- Whether the default queries should be injected. + # Set it to true if you don't want to inject default queries into the cluster. + disableDefaultQueries: false + # -- Custom Prometheus metrics + # Will be stored in the ConfigMap + customQueries: [] + # - name: "pg_cache_hit_ratio" + # query: "SELECT current_database() as datname, sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio FROM pg_statio_user_tables;" + # target_databases: ["*"] + # predicate_query: "SELECT '{{ .Values.version.postgresql }}';" + # metrics: + # - datname: + # usage: "LABEL" + # description: "Name of the database" + # - ratio: + # usage: GAUGE + # description: "Cache hit ratio" + # -- The list of secrets containing the custom queries + customQueriesSecret: [] + # - name: custom-queries-secret + # key: custom-queries + + postgresql: + # -- PostgreSQL configuration options (postgresql.conf) + parameters: {} + # max_connections: 300 + # -- Quorum-based Synchronous Replication + synchronous: {} + # method: any + # number: 1 + # -- PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) + pg_hba: [] + # - host all all 10.244.0.0/16 md5 + # -- PostgreSQL User Name Maps rules (lines to be appended to the pg_ident.conf file) + pg_ident: [] + # - mymap /^(.*)@mydomain\.com$ \1 + # -- Lists of shared preload libraries to add to the default ones + shared_preload_libraries: [] + # - pgaudit + # -- PostgreSQL LDAP configuration (see https://cloudnative-pg.io/documentation/current/postgresql_conf/#ldap-configuration) + ldap: {} + # https://cloudnative-pg.io/documentation/current/postgresql_conf/#ldap-configuration + # server: 'openldap.default.svc.cluster.local' + # bindSearchAuth: + # baseDN: 'ou=org,dc=example,dc=com' + # bindDN: 'cn=admin,dc=example,dc=com' + # bindPassword: + # name: 'ldapBindPassword' + # key: 'data' + # searchAttribute: 'uid' + + + # -- BootstrapInitDB is the configuration of the bootstrap process when initdb is used. + # See: https://cloudnative-pg.io/documentation/current/bootstrap/ + # See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-bootstrapinitdb + initdb: {} + # database: app + # owner: "" # Defaults to the database name + # secret: + # name: "" # Name of the secret containing the initial credentials for the owner of the user database. If empty a new secret will be created from scratch + # options: [] + # encoding: UTF8 + # postInitSQL: + # - CREATE EXTENSION IF NOT EXISTS vector; + # postInitApplicationSQL: [] + # postInitTemplateSQL: [] + + # -- Configure the metadata of the generated service account + serviceAccountTemplate: {} + + additionalLabels: {} + annotations: {} + + +backups: + # -- You need to configure backups manually, so backups are disabled by default. + enabled: false + + # -- Overrides the provider specific default endpoint. Defaults to: + # S3: https://s3..amazonaws.com" + endpointURL: "" # Leave empty if using the default S3 endpoint + # -- Specifies a CA bundle to validate a privately signed certificate. + endpointCA: + # -- Creates a secret with the given value if true, otherwise uses an existing secret. + create: false + name: "" + key: "" + value: "" + + # -- Overrides the provider specific default path. Defaults to: + # S3: s3:// + # Azure: https://..core.windows.net/ + # Google: gs:// + destinationPath: "" + # -- One of `s3`, `azure` or `google` + provider: s3 + s3: + region: "" + bucket: "" + path: "/" + accessKey: "" + secretKey: "" + # -- Use the role based authentication without providing explicitly the keys + inheritFromIAMRole: false + azure: + path: "/" + connectionString: "" + storageAccount: "" + storageKey: "" + storageSasToken: "" + containerName: "" + serviceName: blob + inheritFromAzureAD: false + google: + path: "/" + bucket: "" + gkeEnvironment: false + applicationCredentials: "" + secret: + # -- Whether to create a secret for the backup credentials + create: true + # -- Name of the backup credentials secret + name: "" + + wal: + # -- WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. + compression: gzip + # -- Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. + encryption: AES256 + # -- Number of WAL files to be archived or restored in parallel. + maxParallel: 1 + data: + # -- Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. + compression: gzip + # -- Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. + encryption: AES256 + # -- Number of data files to be archived or restored in parallel. + jobs: 2 + + scheduledBackups: + - + # -- Scheduled backup name + name: daily-backup + # -- Schedule in cron format + schedule: "0 0 0 * * *" + # -- Backup owner reference + backupOwnerReference: self + # -- Backup method, can be `barmanObjectStore` (default) or `volumeSnapshot` + method: barmanObjectStore + + # -- Retention policy for backups + retentionPolicy: "30d" + +imageCatalog: + # -- Whether to provision an image catalog. If imageCatalog.images is empty this option will be ignored. + create: true + # -- List of images to be provisioned in an image catalog. + images: [] + # - image: ghcr.io/your_repo/your_image:your_tag + # major: 16 + +# -- List of PgBouncer poolers +poolers: [] + # - + # # -- Pooler name + # name: rw + # # -- PgBouncer type of service to forward traffic to. + # type: rw + # # -- PgBouncer pooling mode + # poolMode: transaction + # # -- Number of PgBouncer instances + # instances: 3 + # # -- PgBouncer configuration parameters + # parameters: + # max_client_conn: "1000" + # default_pool_size: "25" + # monitoring: + # # -- Whether to enable monitoring + # enabled: false + # podMonitor: + # # -- Whether to enable the PodMonitor + # enabled: true + # # -- Custom PgBouncer deployment template. + # # Use to override image, specify resources, etc. + # template: {} + # - + # # -- Pooler name + # name: ro + # # -- PgBouncer type of service to forward traffic to. + # type: ro + # # -- PgBouncer pooling mode + # poolMode: transaction + # # -- Number of PgBouncer instances + # instances: 3 + # # -- PgBouncer configuration parameters + # parameters: + # max_client_conn: "1000" + # default_pool_size: "25" + # monitoring: + # # -- Whether to enable monitoring + # enabled: false + # podMonitor: + # # -- Whether to enable the PodMonitor + # enabled: true + # # -- Custom PgBouncer deployment template. + # # Use to override image, specify resources, etc. + # template: {} From e0a172bde6af090d31d3c2e72cfeb07042736fdd Mon Sep 17 00:00:00 2001 From: Mike Ditton Date: Mon, 10 Nov 2025 10:51:51 +0100 Subject: [PATCH 2/6] Add Apache-2.0 license for vshnpostgresql chart Since the upstream helmcharts for cloud native pg are licensed under the Apache-2.0 license, we have to give special notice for this chart and use the same license accordingly. --- README.md | 11 ++ charts/vshnpostgresql/LICENSE | 176 ++++++++++++++++++++++++++++++++ charts/vshnpostgresql/NOTICE | 20 ++++ charts/vshnpostgresql/README.md | 7 ++ 4 files changed, 214 insertions(+) create mode 100644 charts/vshnpostgresql/LICENSE create mode 100644 charts/vshnpostgresql/NOTICE diff --git a/README.md b/README.md index df96a58..7c665f3 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,17 @@ helm repo add appcat https://charts.appcat.ch | --- | --- | | [![chart downloads](https://img.shields.io/github/downloads/vshn/appcat-charts/vshnmariadb-0.0.10/total)](https://github.com/vshn/appcat-charts/releases/tag/vshnmariadb-0.0.10) | [vshnmariadb](charts/vshnmariadb/README.md) | +## Licensing + +This repository contains charts under different licenses: + +- **Most charts**: Licensed under the [BSD-3-Clause License](LICENSE) +- **vshnpostgresql chart**: Licensed under the [Apache License 2.0](charts/vshnpostgresql/LICENSE) + - This chart is based on the CloudNativePG "cluster" chart from https://github.com/cloudnative-pg/charts + - See [charts/vshnpostgresql/NOTICE](charts/vshnpostgresql/NOTICE) for attribution details + +Please refer to the LICENSE file in each chart's directory for specific licensing information. + ## Add / Update Charts New charts and versions will be built and published automatically as GitHub Releases. All charts use the Semantic Versioning release strategy. diff --git a/charts/vshnpostgresql/LICENSE b/charts/vshnpostgresql/LICENSE new file mode 100644 index 0000000..dab15ac --- /dev/null +++ b/charts/vshnpostgresql/LICENSE @@ -0,0 +1,176 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Support. While redistributing the Work or + Derivative Works thereof, You may choose to offer, and charge a fee + for, acceptance of support, warranty, indemnity, or other liability + obligations and/or rights consistent with this License. However, in + accepting such obligations, You may act only on Your own behalf and + on Your sole responsibility, not on behalf of any other Contributor, + and only if You agree to indemnify, defend, and hold each Contributor + harmless for any liability incurred by, or claims asserted against, + such Contributor by reason of your accepting any such warranty or + additional liability. + + END OF TERMS AND CONDITIONS diff --git a/charts/vshnpostgresql/NOTICE b/charts/vshnpostgresql/NOTICE new file mode 100644 index 0000000..a0090a9 --- /dev/null +++ b/charts/vshnpostgresql/NOTICE @@ -0,0 +1,20 @@ +vshnpostgresql Helm Chart +Copyright 2025 VSHN AG + +This chart is based on the CloudNativePG "cluster" Helm chart from: +https://github.com/cloudnative-pg/charts + +Original work Copyright contributors to CloudNativePG, established as +CloudNativePG a Series of LF Projects, LLC. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/charts/vshnpostgresql/README.md b/charts/vshnpostgresql/README.md index 9af61a4..05b4bcc 100644 --- a/charts/vshnpostgresql/README.md +++ b/charts/vshnpostgresql/README.md @@ -6,6 +6,13 @@ > ### This chart is under active development. > ### Advised caution when using in production! +## License + +This chart is licensed under the [Apache License 2.0](LICENSE). + +This chart is based on the CloudNativePG "cluster" chart from https://github.com/cloudnative-pg/charts. +See [NOTICE](NOTICE) for attribution details. + A note on the chart's purpose ----------------------------- From 0fa1756f734bda365f7b1304feb45a9ce03256f0 Mon Sep 17 00:00:00 2001 From: Mike Ditton Date: Mon, 10 Nov 2025 11:21:42 +0100 Subject: [PATCH 3/6] Add Barman Cloud Plugin configuration This adds the barman cloud plugin as a backup option for cnpg. --- charts/vshnpostgresql/templates/_backup.tpl | 2 +- charts/vshnpostgresql/templates/_helpers.tpl | 11 ++++ .../templates/backup-s3-creds.yaml | 2 +- .../templates/barman-cloud-objectstore.yaml | 55 +++++++++++++++++++ .../templates/barman-plugin-s3-creds.yaml | 10 ++++ .../vshnpostgresql/templates/ca-bundle.yaml | 8 ++- charts/vshnpostgresql/templates/cluster.yaml | 7 +++ .../templates/scheduled-backups.yaml | 16 +++++- charts/vshnpostgresql/values.yaml | 28 ++++++++-- 9 files changed, 128 insertions(+), 11 deletions(-) create mode 100644 charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml create mode 100644 charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml diff --git a/charts/vshnpostgresql/templates/_backup.tpl b/charts/vshnpostgresql/templates/_backup.tpl index 60270ea..ac9bdab 100644 --- a/charts/vshnpostgresql/templates/_backup.tpl +++ b/charts/vshnpostgresql/templates/_backup.tpl @@ -1,5 +1,5 @@ {{- define "cluster.backup" -}} -{{- if .Values.backups.enabled }} +{{- if and .Values.backups.enabled (ne .Values.backups.method "plugin") }} backup: target: "prefer-standby" retentionPolicy: {{ .Values.backups.retentionPolicy }} diff --git a/charts/vshnpostgresql/templates/_helpers.tpl b/charts/vshnpostgresql/templates/_helpers.tpl index 2bae419..6d040c7 100644 --- a/charts/vshnpostgresql/templates/_helpers.tpl +++ b/charts/vshnpostgresql/templates/_helpers.tpl @@ -144,3 +144,14 @@ Postgres GID {{- 26 -}} {{- end -}} {{- end -}} + +{{/* +Backups ObjectStore Name +*/}} +{{- define "cluster.backups.objectStoreName" -}} + {{- if .Values.backups.plugin.objectStoreName -}} + {{- .Values.backups.plugin.objectStoreName -}} + {{- else -}} + {{- printf "%s-objectstore" (include "cluster.fullname" .) -}} + {{- end -}} +{{- end -}} diff --git a/charts/vshnpostgresql/templates/backup-s3-creds.yaml b/charts/vshnpostgresql/templates/backup-s3-creds.yaml index 5585732..bd7cbfe 100644 --- a/charts/vshnpostgresql/templates/backup-s3-creds.yaml +++ b/charts/vshnpostgresql/templates/backup-s3-creds.yaml @@ -1,4 +1,4 @@ -{{- if and .Values.backups.enabled (eq .Values.backups.provider "s3") (not .Values.backups.s3.inheritFromIAMRole) .Values.backups.secret.create }} +{{- if and .Values.backups.enabled (ne .Values.backups.method "plugin") (eq .Values.backups.provider "s3") (not .Values.backups.s3.inheritFromIAMRole) .Values.backups.secret.create }} apiVersion: v1 kind: Secret metadata: diff --git a/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml b/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml new file mode 100644 index 0000000..64bdca8 --- /dev/null +++ b/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml @@ -0,0 +1,55 @@ +{{ if and .Values.backups.enabled (eq .Values.backups.method "plugin") .Values.backups.plugin.createObjectStore }} +apiVersion: barmancloud.cnpg.io/v1 +kind: ObjectStore +metadata: + name: {{ include "cluster.backups.objectStoreName" . }} + namespace: {{ include "cluster.namespace" . }} + labels: {{ include "cluster.labels" . | nindent 4 }} +spec: + configuration: + {{- if .Values.backups.endpointURL }} + endpointURL: {{ .Values.backups.endpointURL | quote }} + {{- end }} + {{- if or (.Values.backups.endpointCA.create) (.Values.backups.endpointCA.name) }} + endpointCA: + name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" (include "cluster.fullname" .)) }} + key: {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" }} + {{- end }} + {{- if .Values.backups.destinationPath }} + destinationPath: {{ .Values.backups.destinationPath }} + {{- else }} + destinationPath: "s3://{{ required "You need to specify S3 bucket if destinationPath is not specified." .Values.backups.s3.bucket }}{{ .Values.backups.s3.path }}" + {{- end }} + {{- $secretName := .Values.backups.secret.name | default (printf "%s-barman-plugin-s3-creds" (include "cluster.fullname" .)) }} + s3Credentials: + {{- if .Values.backups.s3.inheritFromIAMRole }} + inheritFromIAMRole: true + {{- else }} + accessKeyId: + name: {{ $secretName }} + key: ACCESS_KEY_ID + secretAccessKey: + name: {{ $secretName }} + key: ACCESS_SECRET_KEY + {{- end }} + wal: + {{- if .Values.backups.wal.compression }} + compression: {{ .Values.backups.wal.compression }} + {{- end }} + {{- if .Values.backups.wal.encryption }} + encryption: {{ .Values.backups.wal.encryption }} + {{- end }} + {{- if .Values.backups.wal.maxParallel }} + maxParallel: {{ .Values.backups.wal.maxParallel }} + {{- end }} + data: + {{- if .Values.backups.data.compression }} + compression: {{ .Values.backups.data.compression }} + {{- end }} + {{- if .Values.backups.data.encryption }} + encryption: {{ .Values.backups.data.encryption }} + {{- end }} + {{- if .Values.backups.data.jobs }} + jobs: {{ .Values.backups.data.jobs }} + {{- end }} +{{ end }} diff --git a/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml b/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml new file mode 100644 index 0000000..7018b56 --- /dev/null +++ b/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml @@ -0,0 +1,10 @@ +{{- if and .Values.backups.enabled (eq .Values.backups.method "plugin") .Values.backups.plugin.createObjectStore (eq .Values.backups.provider "s3") (not .Values.backups.s3.inheritFromIAMRole) .Values.backups.secret.create }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ default (printf "%s-barman-plugin-s3-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + namespace: {{ include "cluster.namespace" . }} +data: + ACCESS_KEY_ID: {{ required ".Values.backups.s3.accessKey is required, but not specified." .Values.backups.s3.accessKey | b64enc | quote }} + ACCESS_SECRET_KEY: {{ required ".Values.backups.s3.secretKey is required, but not specified." .Values.backups.s3.secretKey | b64enc | quote }} +{{- end }} diff --git a/charts/vshnpostgresql/templates/ca-bundle.yaml b/charts/vshnpostgresql/templates/ca-bundle.yaml index 8f46f5a..d0bef28 100644 --- a/charts/vshnpostgresql/templates/ca-bundle.yaml +++ b/charts/vshnpostgresql/templates/ca-bundle.yaml @@ -1,10 +1,14 @@ -{{- if .Values.backups.endpointCA.create }} +{{- if and .Values.backups.enabled .Values.backups.endpointCA.create }} apiVersion: v1 kind: Secret metadata: + {{- if eq .Values.backups.method "plugin" }} + name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" (include "cluster.fullname" .)) | quote }} + {{- else }} name: {{ .Values.backups.endpointCA.name | default (printf "%s-ca-bundle" (include "cluster.fullname" .)) | quote }} + {{- end }} namespace: {{ include "cluster.namespace" . }} data: {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" | quote }}: {{ .Values.backups.endpointCA.value }} - + {{- end }} diff --git a/charts/vshnpostgresql/templates/cluster.yaml b/charts/vshnpostgresql/templates/cluster.yaml index bb9ea77..aa8bb40 100644 --- a/charts/vshnpostgresql/templates/cluster.yaml +++ b/charts/vshnpostgresql/templates/cluster.yaml @@ -141,5 +141,12 @@ spec: {{- toYaml . | nindent 6 }} {{ end }} {{- end }} + {{- if and .Values.backups.enabled (eq .Values.backups.method "plugin") }} + plugins: + - name: {{ .Values.backups.plugin.name }} + isWALArchiver: {{ .Values.backups.plugin.isWALArchiver }} + parameters: + barmanObjectName: {{ include "cluster.backups.objectStoreName" . }} + {{- end }} {{ include "cluster.bootstrap" . | nindent 2 }} {{ include "cluster.backup" . | nindent 2 }} diff --git a/charts/vshnpostgresql/templates/scheduled-backups.yaml b/charts/vshnpostgresql/templates/scheduled-backups.yaml index 47a0717..d942242 100644 --- a/charts/vshnpostgresql/templates/scheduled-backups.yaml +++ b/charts/vshnpostgresql/templates/scheduled-backups.yaml @@ -9,11 +9,25 @@ metadata: namespace: {{ include "cluster.namespace" $ }} labels: {{ include "cluster.labels" $context | nindent 4 }} spec: + {{- if .immediate }} + immediate: {{ .immediate }} + {{- else }} immediate: true + {{- end }} schedule: {{ .schedule | quote }} - method: {{ .method }} + {{- if eq $context.Values.backups.method "plugin" }} + method: plugin + cluster: + name: {{ include "cluster.fullname" $context }} + pluginConfiguration: + name: {{ $context.Values.backups.plugin.name }} + parameters: + barmanObjectName: {{ include "cluster.backups.objectStoreName" $context }} + {{- else }} + method: {{ $context.Values.backups.method }} backupOwnerReference: {{ .backupOwnerReference }} cluster: name: {{ include "cluster.fullname" $context }} + {{- end }} {{ end -}} {{ end }} diff --git a/charts/vshnpostgresql/values.yaml b/charts/vshnpostgresql/values.yaml index 3d5f11d..31f6bbf 100644 --- a/charts/vshnpostgresql/values.yaml +++ b/charts/vshnpostgresql/values.yaml @@ -399,6 +399,11 @@ backups: # -- You need to configure backups manually, so backups are disabled by default. enabled: false + # -- Backup method to use. Available methods: + # * `barmanObjectStore` - Uses CNPG's built-in barman object store (legacy method) + # * `plugin` - Uses CNPG's plugin system with barman-cloud plugin (recommended) + method: barmanObjectStore + # -- Overrides the provider specific default endpoint. Defaults to: # S3: https://s3..amazonaws.com" endpointURL: "" # Leave empty if using the default S3 endpoint @@ -460,19 +465,30 @@ backups: # -- Number of data files to be archived or restored in parallel. jobs: 2 + # -- Retention policy for backups + retentionPolicy: "30d" + + # -- Plugin-specific configuration (only used when method is 'plugin') + plugin: + # -- Plugin name + name: barman-cloud.cloudnative-pg.io + # -- Whether the plugin should be used as a WAL archiver + isWALArchiver: true + # -- Name of the ObjectStore resource to use (will be created if createObjectStore is true) + objectStoreName: "" + # -- Create an ObjectStore resource + createObjectStore: true + scheduledBackups: - # -- Scheduled backup name name: daily-backup # -- Schedule in cron format schedule: "0 0 0 * * *" - # -- Backup owner reference + # -- Backup owner reference (only used with barmanObjectStore method) backupOwnerReference: self - # -- Backup method, can be `barmanObjectStore` (default) or `volumeSnapshot` - method: barmanObjectStore - - # -- Retention policy for backups - retentionPolicy: "30d" + # -- Whether to take a backup immediately upon creation (only used with plugin method) + immediate: true imageCatalog: # -- Whether to provision an image catalog. If imageCatalog.images is empty this option will be ignored. From f2dac71f8bc52676941bba24ff8beaa81eace460 Mon Sep 17 00:00:00 2001 From: Mike Ditton Date: Mon, 10 Nov 2025 17:25:37 +0100 Subject: [PATCH 4/6] Docs: Align documentation with vshnmariadb This aligns the documentation of vshnpostgresql with vshnmariadb --- README.md | 12 +- charts/vshnpostgresql/Chart.yaml | 20 +- charts/vshnpostgresql/README.gotmpl.md | 83 ++++ charts/vshnpostgresql/README.md | 409 ++++-------------- charts/vshnpostgresql/README.md.gotmpl | 158 ------- charts/vshnpostgresql/docs/Getting Started.md | 106 ----- charts/vshnpostgresql/docs/Recovery.md | 27 -- .../docs/runbooks/CNPGClusterHACritical.md | 49 --- .../docs/runbooks/CNPGClusterHAWarning.md | 51 --- .../CNPGClusterHighConnectionsCritical.md | 24 - .../CNPGClusterHighConnectionsWarning.md | 24 - .../runbooks/CNPGClusterHighReplicationLag.md | 31 -- .../CNPGClusterInstancesOnSameNode.md | 28 -- .../CNPGClusterLowDiskSpaceCritical.md | 31 -- .../CNPGClusterLowDiskSpaceWarning.md | 31 -- .../docs/runbooks/CNPGClusterOffline.md | 43 -- .../runbooks/CNPGClusterZoneSpreadWarning.md | 37 -- charts/vshnpostgresql/examples/basic.yaml | 8 - .../examples/custom-queries.yaml | 24 - .../examples/image-catalog-ref.yaml | 12 - .../examples/image-catalog.yaml | 14 - charts/vshnpostgresql/examples/pgbouncer.yaml | 34 -- charts/vshnpostgresql/examples/postgis.yaml | 9 - .../examples/recovery-backup.yaml | 23 - .../examples/recovery-object_store.yaml | 31 -- .../examples/recovery-pg_basebackup.yaml | 15 - .../examples/standalone-s3.yaml | 20 - .../vshnpostgresql/examples/timescaledb.yaml | 9 - 28 files changed, 188 insertions(+), 1175 deletions(-) create mode 100644 charts/vshnpostgresql/README.gotmpl.md delete mode 100644 charts/vshnpostgresql/README.md.gotmpl delete mode 100644 charts/vshnpostgresql/docs/Getting Started.md delete mode 100644 charts/vshnpostgresql/docs/Recovery.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md delete mode 100644 charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md delete mode 100644 charts/vshnpostgresql/examples/basic.yaml delete mode 100644 charts/vshnpostgresql/examples/custom-queries.yaml delete mode 100644 charts/vshnpostgresql/examples/image-catalog-ref.yaml delete mode 100644 charts/vshnpostgresql/examples/image-catalog.yaml delete mode 100644 charts/vshnpostgresql/examples/pgbouncer.yaml delete mode 100644 charts/vshnpostgresql/examples/postgis.yaml delete mode 100644 charts/vshnpostgresql/examples/recovery-backup.yaml delete mode 100644 charts/vshnpostgresql/examples/recovery-object_store.yaml delete mode 100644 charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml delete mode 100644 charts/vshnpostgresql/examples/standalone-s3.yaml delete mode 100644 charts/vshnpostgresql/examples/timescaledb.yaml diff --git a/README.md b/README.md index 7c665f3..8189f0e 100644 --- a/README.md +++ b/README.md @@ -16,17 +16,7 @@ helm repo add appcat https://charts.appcat.ch | Downloads & Changelog | Chart | | --- | --- | | [![chart downloads](https://img.shields.io/github/downloads/vshn/appcat-charts/vshnmariadb-0.0.10/total)](https://github.com/vshn/appcat-charts/releases/tag/vshnmariadb-0.0.10) | [vshnmariadb](charts/vshnmariadb/README.md) | - -## Licensing - -This repository contains charts under different licenses: - -- **Most charts**: Licensed under the [BSD-3-Clause License](LICENSE) -- **vshnpostgresql chart**: Licensed under the [Apache License 2.0](charts/vshnpostgresql/LICENSE) - - This chart is based on the CloudNativePG "cluster" chart from https://github.com/cloudnative-pg/charts - - See [charts/vshnpostgresql/NOTICE](charts/vshnpostgresql/NOTICE) for attribution details - -Please refer to the LICENSE file in each chart's directory for specific licensing information. +| [![chart downloads](https://img.shields.io/github/downloads/vshn/appcat-charts/vshnpostgresql-0.0.1/total)](https://github.com/vshn/appcat-charts/releases/tag/vshnpostgresql-0.0.1) | [vshnpostgresql](charts/vshnpostgresql/README.md) | ## Add / Update Charts diff --git a/charts/vshnpostgresql/Chart.yaml b/charts/vshnpostgresql/Chart.yaml index 6e0bfd4..3d226a8 100644 --- a/charts/vshnpostgresql/Chart.yaml +++ b/charts/vshnpostgresql/Chart.yaml @@ -1,4 +1,8 @@ # +# Modified by VSHN AG, Copyright 2025 +# Based on CloudNativePG cluster chart +# https://github.com/cloudnative-pg/charts +# # Copyright © contributors to CloudNativePG, established as # CloudNativePG a Series of LF Projects, LLC. # @@ -17,18 +21,10 @@ # SPDX-License-Identifier: Apache-2.0 # apiVersion: v2 -name: cluster +name: vshnpostgresql description: Deploys and manages a CloudNativePG cluster and its associated resources. -icon: https://raw.githubusercontent.com/cloudnative-pg/artwork/main/cloudnativepg-logo.svg type: application -version: 0.3.1 -sources: - - https://github.com/cloudnative-pg/charts -keywords: - - postgresql - - postgres - - database -home: https://cloudnative-pg.io +version: 0.0.1 maintainers: - - name: itay-grudev - email: itay+cloudnativepg-charts+github.com@grudev.com + - name: Schedar Team + email: info@vshn.ch diff --git a/charts/vshnpostgresql/README.gotmpl.md b/charts/vshnpostgresql/README.gotmpl.md new file mode 100644 index 0000000..6d20539 --- /dev/null +++ b/charts/vshnpostgresql/README.gotmpl.md @@ -0,0 +1,83 @@ + + +## Introduction + +This helm chart is used to deploy PostgreSQL instances using the [CloudNativePG operator](https://cloudnative-pg.io). + +## Configuration + +The following table lists the configurable parameters chart. For default values and examples, consult `values.yaml`. + +### Generic parameters +| Parameter | Description | Default +|--- | --- | --- +| `type` | Type of database. Supported types: `postgresql`, `postgis`, `timescaledb` | `postgresql` +| `version.postgresql` | PostgreSQL major version to use | `16` +| `cluster.instances` | Number of instances to deploy | 3 +| `cluster.imageName` | Container image name supporting both tags and digests | +| `cluster.storage.size` | PVC size of the instance | 8Gi +| `cluster.storage.storageClass` | StorageClass to use for the PVC | +| `cluster.resources` | Resources describes the compute resource requirements. We strongly advise using the same settings for limits and requests for Guaranteed QoS. See: [resource-units] | +| `cluster.affinity` | Defines the affinity for the pods | `{"topologyKey": "topology.kubernetes.io/zone"}` + +### Backup + +| Parameter | Description | Default +| --- | --- | --- +| `backups.enabled` | Enabled is a flag to enable backups | false +| `backups.method` | Backup method: `barmanObjectStore` or `plugin` | `barmanObjectStore` +| `backups.provider` | Backup provider: `s3`, `azure` or `google` | `s3` +| `backups.retentionPolicy` | Retention policy for backups | `30d` +| `backups.s3.bucket` | Name of the s3 bucket for backups | +| `backups.s3.region` | AWS region for the s3 bucket | +| `backups.s3.accessKey` | Access key for the s3 bucket | +| `backups.s3.secretKey` | Secret key for the s3 bucket | +| `backups.scheduledBackups[].name` | Name of the scheduled backup | `daily-backup` +| `backups.scheduledBackups[].schedule` | Cron schedule for the backup | `0 0 0 * * *` + +### Monitoring + +| Parameter | Description | Default +| --- | --- | --- +| `cluster.monitoring.enabled` | Enable Prometheus monitoring | false +| `cluster.monitoring.podMonitor.enabled` | Enable PodMonitor creation | true +| `cluster.monitoring.prometheusRule.enabled` | Enable PrometheusRule for automated alerts | true + +### PostgreSQL configuration + +| Parameter | Description | Default +| --- | --- | --- +| `cluster.postgresql.parameters` | PostgreSQL configuration options (postgresql.conf) | `{}` +| `cluster.postgresql.pg_hba` | PostgreSQL Host Based Authentication rules | `[]` +| `cluster.postgresql.shared_preload_libraries` | Lists of shared preload libraries to add to defaults | `[]` + +### Connection Pooling (PgBouncer) + +| Parameter | Description | Default +| --- | --- | --- +| `poolers[].name` | Name of the pooler resource | +| `poolers[].type` | Type of service: `rw` or `ro` | `rw` +| `poolers[].poolMode` | PgBouncer pooling mode | `session` +| `poolers[].instances` | Number of PgBouncer instances | 1 +| `poolers[].parameters` | Additional PgBouncer configuration parameters | `{}` + +### Recovery + +| Parameter | Description | Default +| --- | --- | --- +| `mode` | Cluster mode: `standalone` or `recovery` | `standalone` +| `recovery.method` | Recovery method: `backup`, `object_store`, `pg_basebackup`, or `import` | `backup` +| `recovery.backupName` | Name of the backup to recover from (required for `backup` method) | +| `recovery.clusterName` | Original cluster name when used in backups | +| `recovery.provider` | Recovery provider: `s3`, `azure` or `google` | `s3` +| `recovery.pitrTarget.time` | Point-in-time recovery target in RFC3339 format | + + +[resource-units]: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes +[cloudnative-pg]: https://cloudnative-pg.io/documentation/current/ diff --git a/charts/vshnpostgresql/README.md b/charts/vshnpostgresql/README.md index 05b4bcc..4d88b25 100644 --- a/charts/vshnpostgresql/README.md +++ b/charts/vshnpostgresql/README.md @@ -1,318 +1,101 @@ -# cluster +# vshnpostgresql -![Version: 0.3.1](https://img.shields.io/badge/Version-0.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) +![Version: 0.0.1](https://img.shields.io/badge/Version-0.0.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) -> **Warning** -> ### This chart is under active development. -> ### Advised caution when using in production! +Deploys and manages a CloudNativePG cluster and its associated resources. -## License +## Installation -This chart is licensed under the [Apache License 2.0](LICENSE). - -This chart is based on the CloudNativePG "cluster" chart from https://github.com/cloudnative-pg/charts. -See [NOTICE](NOTICE) for attribution details. - -A note on the chart's purpose ------------------------------ - -This is an opinionated chart that is designed to provide a subset of simple, stable and safe configurations using the -CloudNativePG operator. It is designed to provide a simple way to perform recovery operations to decrease your RTO. - -It is not designed to be a one size fits all solution. If you need a more complicated setup we strongly recommend that -you either: - -* use the operator directly -* create your own chart -* use Kustomize to modify the chart's resources - -**_Note_** that the latter option carries it's own risks as the chart configuration may change, especially before it -reaches a stable release. - -That being said, we welcome PRs that improve the chart, but please keep in mind that we don't plan to support every -single configuration that the operator provides and we may reject PRs that add too much complexity and maintenance -difficulty to the chart. - -Getting Started ---------------- - -### Installing the Operator -Skip this step if the CNPG operator is already installed in your cluster. - -```console -helm repo add cnpg https://cloudnative-pg.github.io/charts -helm upgrade --install cnpg \ ---namespace cnpg-system \ ---create-namespace \ -cnpg/cloudnative-pg +```bash +helm repo add appcat https://charts.appcat.ch +helm install vshnpostgresql vshn/vshnpostgresql ``` - -### Setting up a CNPG Cluster - -```console -helm repo add cnpg https://cloudnative-pg.github.io/charts -helm upgrade --install cnpg \ ---namespace cnpg-database \ ---create-namespace \ ---values values.yaml \ -cnpg/cluster -``` - -A more detailed guide can be found in the [Getting Started docs](<./docs/Getting Started.md>). - -Cluster Configuration ---------------------- - -### Database types - -Currently the chart supports two database types. These are configured via the `type` parameter. These are: -* `postgresql` - A standard PostgreSQL database. -* `postgis` - A PostgreSQL database with the PostGIS extension installed. - -Depending on the type the chart will use a different Docker image and fill in some initial setup, like extension installation. - -### Modes of operation - -The chart has three modes of operation. These are configured via the `mode` parameter: -* `standalone` - Creates new or updates an existing CNPG cluster. This is the default mode. -* `replica` - Creates a replica cluster from an existing CNPG cluster. **_Note_ that this mode is not yet supported.** -* `recovery` - Recovers a CNPG cluster from a backup, object store or via pg_basebackup. - -### Backup configuration - -CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object -store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are -stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following -providers are supported: - -* S3 or S3-compatible stores, like MinIO -* Microsoft Azure Blob Storage -* Google Cloud Storage - -Additionally you can specify the following parameters: -* `backups.retentionPolicy` - The retention policy for backups. Defaults to `30d`. -* `backups.scheduledBackups` - An array of scheduled backups containing a name and a crontab schedule. Example: -```yaml -backups: - scheduledBackups: - - name: daily-backup - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self -``` - -Each backup adapter takes it's own set of parameters, listed in the [Configuration options](#Configuration-options) section -below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, -`backup.azure`, or `backup.google`. - -Recovery --------- - -There is a separate document outlining the recovery procedure here: **[Recovery](docs/Recovery.md)** - -Examples --------- - -There are several configuration examples in the [examples](examples) directory. Refer to them for a basic setup and -refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/current/) for more advanced configurations. - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| backups.azure.connectionString | string | `""` | | -| backups.azure.containerName | string | `""` | | -| backups.azure.inheritFromAzureAD | bool | `false` | | -| backups.azure.path | string | `"/"` | | -| backups.azure.serviceName | string | `"blob"` | | -| backups.azure.storageAccount | string | `""` | | -| backups.azure.storageKey | string | `""` | | -| backups.azure.storageSasToken | string | `""` | | -| backups.data.compression | string | `"gzip"` | Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | -| backups.data.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. | -| backups.data.jobs | int | `2` | Number of data files to be archived or restored in parallel. | -| backups.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | -| backups.enabled | bool | `false` | You need to configure backups manually, so backups are disabled by default. | -| backups.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | -| backups.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | -| backups.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" | -| backups.google.applicationCredentials | string | `""` | | -| backups.google.bucket | string | `""` | | -| backups.google.gkeEnvironment | bool | `false` | | -| backups.google.path | string | `"/"` | | -| backups.provider | string | `"s3"` | One of `s3`, `azure` or `google` | -| backups.retentionPolicy | string | `"30d"` | Retention policy for backups | -| backups.s3.accessKey | string | `""` | | -| backups.s3.bucket | string | `""` | | -| backups.s3.inheritFromIAMRole | bool | `false` | Use the role based authentication without providing explicitly the keys | -| backups.s3.path | string | `"/"` | | -| backups.s3.region | string | `""` | | -| backups.s3.secretKey | string | `""` | | -| backups.scheduledBackups[0].backupOwnerReference | string | `"self"` | Backup owner reference | -| backups.scheduledBackups[0].method | string | `"barmanObjectStore"` | Backup method, can be `barmanObjectStore` (default) or `volumeSnapshot` | -| backups.scheduledBackups[0].name | string | `"daily-backup"` | Scheduled backup name | -| backups.scheduledBackups[0].schedule | string | `"0 0 0 * * *"` | Schedule in cron format | -| backups.secret.create | bool | `true` | Whether to create a secret for the backup credentials | -| backups.secret.name | string | `""` | Name of the backup credentials secret | -| backups.wal.compression | string | `"gzip"` | WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. | -| backups.wal.encryption | string | `"AES256"` | Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. | -| backups.wal.maxParallel | int | `1` | Number of WAL files to be archived or restored in parallel. | -| cluster.additionalLabels | object | `{}` | | -| cluster.affinity | object | `{"topologyKey":"topology.kubernetes.io/zone"}` | Affinity/Anti-affinity rules for Pods. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-AffinityConfiguration | -| cluster.annotations | object | `{}` | | -| cluster.certificates | object | `{}` | The configuration for the CA and related certificates. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-CertificatesConfiguration | -| cluster.enablePDB | bool | `true` | Allow to disable PDB, mainly useful for upgrade of single-instance clusters or development purposes See: https://cloudnative-pg.io/documentation/current/kubernetes_upgrade/#pod-disruption-budgets | -| cluster.enableSuperuserAccess | bool | `true` | When this option is enabled, the operator will use the SuperuserSecret to update the postgres user password. If the secret is not present, the operator will automatically create one. When this option is disabled, the operator will ignore the SuperuserSecret content, delete it when automatically created, and then blank the password of the postgres user by setting it to NULL. | -| cluster.env | list | `[]` | Env follows the Env format to pass environment variables to the pods created in the cluster | -| cluster.envFrom | list | `[]` | EnvFrom follows the EnvFrom format to pass environment variables sources to the pods to be used by Env | -| cluster.imageCatalogRef | object | `{}` | Reference to `ImageCatalog` of `ClusterImageCatalog`, if specified takes precedence over `cluster.imageName` | -| cluster.imageName | string | `""` | Name of the container image, supporting both tags (:) and digests for deterministic and repeatable deployments: :@sha256: | -| cluster.imagePullPolicy | string | `"IfNotPresent"` | Image pull policy. One of Always, Never or IfNotPresent. If not defined, it defaults to IfNotPresent. Cannot be updated. More info: https://kubernetes.io/docs/concepts/containers/images#updating-images | -| cluster.imagePullSecrets | list | `[]` | The list of pull secrets to be used to pull the images. See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-LocalObjectReference | -| cluster.initdb | object | `{}` | BootstrapInitDB is the configuration of the bootstrap process when initdb is used. See: https://cloudnative-pg.io/documentation/current/bootstrap/ See: https://cloudnative-pg.io/documentation/current/cloudnative-pg.v1/#postgresql-cnpg-io-v1-bootstrapinitdb | -| cluster.instances | int | `3` | Number of instances | -| cluster.logLevel | string | `"info"` | The instances' log level, one of the following values: error, warning, info (default), debug, trace | -| cluster.monitoring.customQueries | list | `[]` | Custom Prometheus metrics Will be stored in the ConfigMap | -| cluster.monitoring.customQueriesSecret | list | `[]` | The list of secrets containing the custom queries | -| cluster.monitoring.disableDefaultQueries | bool | `false` | Whether the default queries should be injected. Set it to true if you don't want to inject default queries into the cluster. | -| cluster.monitoring.enabled | bool | `false` | Whether to enable monitoring | -| cluster.monitoring.podMonitor.enabled | bool | `true` | Whether to enable the PodMonitor | -| cluster.monitoring.podMonitor.metricRelabelings | list | `[]` | The list of metric relabelings for the PodMonitor. Applied to samples before ingestion. | -| cluster.monitoring.podMonitor.relabelings | list | `[]` | The list of relabelings for the PodMonitor. Applied to samples before scraping. | -| cluster.monitoring.prometheusRule.enabled | bool | `true` | Whether to enable the PrometheusRule automated alerts | -| cluster.monitoring.prometheusRule.excludeRules | list | `[]` | Exclude specified rules | -| cluster.postgresGID | int | `-1` | The GID of the postgres user inside the image, defaults to 26 | -| cluster.postgresUID | int | `-1` | The UID of the postgres user inside the image, defaults to 26 | -| cluster.postgresql.ldap | object | `{}` | PostgreSQL LDAP configuration (see https://cloudnative-pg.io/documentation/current/postgresql_conf/#ldap-configuration) | -| cluster.postgresql.parameters | object | `{}` | PostgreSQL configuration options (postgresql.conf) | -| cluster.postgresql.pg_hba | list | `[]` | PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) | -| cluster.postgresql.pg_ident | list | `[]` | PostgreSQL User Name Maps rules (lines to be appended to the pg_ident.conf file) | -| cluster.postgresql.shared_preload_libraries | list | `[]` | Lists of shared preload libraries to add to the default ones | -| cluster.postgresql.synchronous | object | `{}` | Quorum-based Synchronous Replication | -| cluster.primaryUpdateMethod | string | `"switchover"` | Method to follow to upgrade the primary server during a rolling update procedure, after all replicas have been successfully updated. It can be switchover (default) or restart. | -| cluster.primaryUpdateStrategy | string | `"unsupervised"` | Strategy to follow to upgrade the primary server during a rolling update procedure, after all replicas have been successfully updated: it can be automated (unsupervised - default) or manual (supervised) | -| cluster.priorityClassName | string | `""` | | -| cluster.resources | object | `{}` | Resources requirements of every generated Pod. Please refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for more information. We strongly advise you use the same setting for limits and requests so that your cluster pods are given a Guaranteed QoS. See: https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/ | -| cluster.roles | list | `[]` | This feature enables declarative management of existing roles, as well as the creation of new roles if they are not already present in the database. See: https://cloudnative-pg.io/documentation/current/declarative_role_management/ | -| cluster.serviceAccountTemplate | object | `{}` | Configure the metadata of the generated service account | -| cluster.services | object | `{}` | Customization of service definitions. Please refer to https://cloudnative-pg.io/documentation/current/service_management/ | -| cluster.storage.size | string | `"8Gi"` | | -| cluster.storage.storageClass | string | `""` | | -| cluster.superuserSecret | string | `""` | | -| cluster.walStorage.enabled | bool | `false` | | -| cluster.walStorage.size | string | `"1Gi"` | | -| cluster.walStorage.storageClass | string | `""` | | -| fullnameOverride | string | `""` | Override the full name of the chart | -| imageCatalog.create | bool | `true` | Whether to provision an image catalog. If imageCatalog.images is empty this option will be ignored. | -| imageCatalog.images | list | `[]` | List of images to be provisioned in an image catalog. | -| mode | string | `"standalone"` | Cluster mode of operation. Available modes: * `standalone` - default mode. Creates new or updates an existing CNPG cluster. * `replica` - Creates a replica cluster from an existing CNPG cluster. # TODO * `recovery` - Same as standalone but creates a cluster from a backup, object store or via pg_basebackup. | -| nameOverride | string | `""` | Override the name of the chart | -| namespaceOverride | string | `""` | Override the namespace of the chart | -| poolers | list | `[]` | List of PgBouncer poolers | -| recovery.azure.connectionString | string | `""` | | -| recovery.azure.containerName | string | `""` | | -| recovery.azure.inheritFromAzureAD | bool | `false` | | -| recovery.azure.path | string | `"/"` | | -| recovery.azure.serviceName | string | `"blob"` | | -| recovery.azure.storageAccount | string | `""` | | -| recovery.azure.storageKey | string | `""` | | -| recovery.azure.storageSasToken | string | `""` | | -| recovery.backupName | string | `""` | Backup Recovery Method | -| recovery.clusterName | string | `""` | The original cluster name when used in backups. Also known as serverName. | -| recovery.database | string | `"app"` | Name of the database used by the application. Default: `app`. | -| recovery.destinationPath | string | `""` | Overrides the provider specific default path. Defaults to: S3: s3:// Azure: https://..core.windows.net/ Google: gs:// | -| recovery.endpointCA | object | `{"create":false,"key":"","name":"","value":""}` | Specifies a CA bundle to validate a privately signed certificate. | -| recovery.endpointCA.create | bool | `false` | Creates a secret with the given value if true, otherwise uses an existing secret. | -| recovery.endpointURL | string | `""` | Overrides the provider specific default endpoint. Defaults to: S3: https://s3..amazonaws.com" Leave empty if using the default S3 endpoint | -| recovery.google.applicationCredentials | string | `""` | | -| recovery.google.bucket | string | `""` | | -| recovery.google.gkeEnvironment | bool | `false` | | -| recovery.google.path | string | `"/"` | | -| recovery.import.databases | list | `[]` | Databases to import | -| recovery.import.pgDumpExtraOptions | list | `[]` | List of custom options to pass to the `pg_dump` command. IMPORTANT: Use these options with caution and at your own risk, as the operator does not validate their content. Be aware that certain options may conflict with the operator's intended functionality or design. | -| recovery.import.pgRestoreExtraOptions | list | `[]` | List of custom options to pass to the `pg_restore` command. IMPORTANT: Use these options with caution and at your own risk, as the operator does not validate their content. Be aware that certain options may conflict with the operator's intended functionality or design. | -| recovery.import.postImportApplicationSQL | list | `[]` | List of SQL queries to be executed as a superuser in the application database right after is imported. To be used with extreme care. Only available in microservice type. | -| recovery.import.roles | list | `[]` | Roles to import | -| recovery.import.schemaOnly | bool | `false` | When set to true, only the pre-data and post-data sections of pg_restore are invoked, avoiding data import. | -| recovery.import.source.database | string | `""` | | -| recovery.import.source.host | string | `""` | | -| recovery.import.source.passwordSecret.create | bool | `false` | Whether to create a secret for the password | -| recovery.import.source.passwordSecret.key | string | `"password"` | The key in the secret containing the password | -| recovery.import.source.passwordSecret.name | string | `""` | Name of the secret containing the password | -| recovery.import.source.passwordSecret.value | string | `""` | The password value to use when creating the secret | -| recovery.import.source.port | int | `5432` | | -| recovery.import.source.sslCertSecret.key | string | `""` | | -| recovery.import.source.sslCertSecret.name | string | `""` | | -| recovery.import.source.sslKeySecret.key | string | `""` | | -| recovery.import.source.sslKeySecret.name | string | `""` | | -| recovery.import.source.sslMode | string | `"verify-full"` | | -| recovery.import.source.sslRootCertSecret.key | string | `""` | | -| recovery.import.source.sslRootCertSecret.name | string | `""` | | -| recovery.import.source.username | string | `""` | | -| recovery.import.type | string | `"microservice"` | One of `microservice` or `monolith.` See: https://cloudnative-pg.io/documentation/current/database_import/#how-it-works | -| recovery.method | string | `"backup"` | Available recovery methods: * `backup` - Recovers a CNPG cluster from a CNPG backup (PITR supported) Needs to be on the same cluster in the same namespace. * `object_store` - Recovers a CNPG cluster from a barman object store (PITR supported). * `pg_basebackup` - Recovers a CNPG cluster viaa streaming replication protocol. Useful if you want to migrate databases to CloudNativePG, even from outside Kubernetes. * `import` - Import one or more databases from an existing Postgres cluster. | -| recovery.owner | string | `""` | Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. | -| recovery.pgBaseBackup.database | string | `"app"` | Name of the database used by the application. Default: `app`. | -| recovery.pgBaseBackup.owner | string | `""` | Name of the owner of the database in the instance to be used by applications. Defaults to the value of the `database` key. | -| recovery.pgBaseBackup.secret | string | `""` | Name of the secret containing the initial credentials for the owner of the user database. If empty a new secret will be created from scratch | -| recovery.pgBaseBackup.source.database | string | `"app"` | | -| recovery.pgBaseBackup.source.host | string | `""` | | -| recovery.pgBaseBackup.source.passwordSecret.create | bool | `false` | Whether to create a secret for the password | -| recovery.pgBaseBackup.source.passwordSecret.key | string | `"password"` | The key in the secret containing the password | -| recovery.pgBaseBackup.source.passwordSecret.name | string | `""` | Name of the secret containing the password | -| recovery.pgBaseBackup.source.passwordSecret.value | string | `""` | The password value to use when creating the secret | -| recovery.pgBaseBackup.source.port | int | `5432` | | -| recovery.pgBaseBackup.source.sslCertSecret.key | string | `""` | | -| recovery.pgBaseBackup.source.sslCertSecret.name | string | `""` | | -| recovery.pgBaseBackup.source.sslKeySecret.key | string | `""` | | -| recovery.pgBaseBackup.source.sslKeySecret.name | string | `""` | | -| recovery.pgBaseBackup.source.sslMode | string | `"verify-full"` | | -| recovery.pgBaseBackup.source.sslRootCertSecret.key | string | `""` | | -| recovery.pgBaseBackup.source.sslRootCertSecret.name | string | `""` | | -| recovery.pgBaseBackup.source.username | string | `""` | | -| recovery.pitrTarget.time | string | `""` | Time in RFC3339 format | -| recovery.provider | string | `"s3"` | One of `s3`, `azure` or `google` | -| recovery.s3.accessKey | string | `""` | | -| recovery.s3.bucket | string | `""` | | -| recovery.s3.inheritFromIAMRole | bool | `false` | Use the role based authentication without providing explicitly the keys | -| recovery.s3.path | string | `"/"` | | -| recovery.s3.region | string | `""` | | -| recovery.s3.secretKey | string | `""` | | -| recovery.secret.create | bool | `true` | Whether to create a secret for the backup credentials | -| recovery.secret.name | string | `""` | Name of the backup credentials secret | -| type | string | `"postgresql"` | Type of the CNPG database. Available types: * `postgresql` * `postgis` * `timescaledb` | -| version.postgis | string | `"3.4"` | If using PostGIS, specify the version | -| version.postgresql | string | `"16"` | PostgreSQL major version to use | -| version.timescaledb | string | `"2.15"` | If using TimescaleDB, specify the version | -| poolers[].name | string | `` | Name of the pooler resource | -| poolers[].instances | number | `1` | The number of replicas we want | -| poolers[].type | [PoolerType][PoolerType] | `rw` | Type of service to forward traffic to. Default: `rw`. | -| poolers[].poolMode | [PgBouncerPoolMode][PgBouncerPoolMode] | `session` | The pool mode. Default: `session`. | -| poolers[].authQuerySecret | [LocalObjectReference][LocalObjectReference] | `{}` | The credentials of the user that need to be used for the authentication query. | -| poolers[].authQuery | string | `{}` | The credentials of the user that need to be used for the authentication query. | -| poolers[].parameters | map[string]string | `{}` | Additional parameters to be passed to PgBouncer - please check the CNPG documentation for a list of options you can configure | -| poolers[].template | [PodTemplateSpec][PodTemplateSpec] | `{}` | The template of the Pod to be created | -| poolers[].template | [ServiceTemplateSpec][ServiceTemplateSpec] | `{}` | Template for the Service to be created | -| poolers[].pg_hba | []string | `{}` | PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) | -| poolers[].monitoring.enabled | bool | `false` | Whether to enable monitoring for the Pooler. | -| poolers[].monitoring.podMonitor.enabled | bool | `true` | Create a podMonitor for the Pooler. | - -## Maintainers - -| Name | Email | Url | -| ---- | ------ | --- | -| itay-grudev | | | - -Features that require feedback ------------------------------- - -Please raise a ticket tested any of the following features and they have worked. -Alternatively a ticket and a PR if you have found that something needs a change to work properly. - -- [ ] Google Cloud Storage Backups -- [ ] Google Cloud Storage Recovery - -TODO ----- -* IAM Role for S3 Service Account -* Automatic provisioning of a Alert Manager configuration - + + +## Introduction + +This helm chart is used to deploy PostgreSQL instances using the [CloudNativePG operator](https://cloudnative-pg.io). + +## Configuration + +The following table lists the configurable parameters chart. For default values and examples, consult `values.yaml`. + +### Generic parameters +| Parameter | Description | Default +|--- | --- | --- +| `type` | Type of database. Supported types: `postgresql`, `postgis`, `timescaledb` | `postgresql` +| `version.postgresql` | PostgreSQL major version to use | `16` +| `cluster.instances` | Number of instances to deploy | 3 +| `cluster.imageName` | Container image name supporting both tags and digests | +| `cluster.storage.size` | PVC size of the instance | 8Gi +| `cluster.storage.storageClass` | StorageClass to use for the PVC | +| `cluster.resources` | Resources describes the compute resource requirements. We strongly advise using the same settings for limits and requests for Guaranteed QoS. See: [resource-units] | +| `cluster.affinity` | Defines the affinity for the pods | `{"topologyKey": "topology.kubernetes.io/zone"}` + +### Backup + +| Parameter | Description | Default +| --- | --- | --- +| `backups.enabled` | Enabled is a flag to enable backups | false +| `backups.method` | Backup method: `barmanObjectStore` or `plugin` | `barmanObjectStore` +| `backups.provider` | Backup provider: `s3`, `azure` or `google` | `s3` +| `backups.retentionPolicy` | Retention policy for backups | `30d` +| `backups.s3.bucket` | Name of the s3 bucket for backups | +| `backups.s3.region` | AWS region for the s3 bucket | +| `backups.s3.accessKey` | Access key for the s3 bucket | +| `backups.s3.secretKey` | Secret key for the s3 bucket | +| `backups.scheduledBackups[].name` | Name of the scheduled backup | `daily-backup` +| `backups.scheduledBackups[].schedule` | Cron schedule for the backup | `0 0 0 * * *` + +### Monitoring + +| Parameter | Description | Default +| --- | --- | --- +| `cluster.monitoring.enabled` | Enable Prometheus monitoring | false +| `cluster.monitoring.podMonitor.enabled` | Enable PodMonitor creation | true +| `cluster.monitoring.prometheusRule.enabled` | Enable PrometheusRule for automated alerts | true + +### PostgreSQL configuration + +| Parameter | Description | Default +| --- | --- | --- +| `cluster.postgresql.parameters` | PostgreSQL configuration options (postgresql.conf) | `{}` +| `cluster.postgresql.pg_hba` | PostgreSQL Host Based Authentication rules | `[]` +| `cluster.postgresql.shared_preload_libraries` | Lists of shared preload libraries to add to defaults | `[]` + +### Connection Pooling (PgBouncer) + +| Parameter | Description | Default +| --- | --- | --- +| `poolers[].name` | Name of the pooler resource | +| `poolers[].type` | Type of service: `rw` or `ro` | `rw` +| `poolers[].poolMode` | PgBouncer pooling mode | `session` +| `poolers[].instances` | Number of PgBouncer instances | 1 +| `poolers[].parameters` | Additional PgBouncer configuration parameters | `{}` + +### Recovery + +| Parameter | Description | Default +| --- | --- | --- +| `mode` | Cluster mode: `standalone` or `recovery` | `standalone` +| `recovery.method` | Recovery method: `backup`, `object_store`, `pg_basebackup`, or `import` | `backup` +| `recovery.backupName` | Name of the backup to recover from (required for `backup` method) | +| `recovery.clusterName` | Original cluster name when used in backups | +| `recovery.provider` | Recovery provider: `s3`, `azure` or `google` | `s3` +| `recovery.pitrTarget.time` | Point-in-time recovery target in RFC3339 format | + + +[resource-units]: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes +[cloudnative-pg]: https://cloudnative-pg.io/documentation/current/ + + +[resource-units]: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/#resource-units-in-kubernetes +[prometheus-operator]: https://github.com/coreos/prometheus-operator diff --git a/charts/vshnpostgresql/README.md.gotmpl b/charts/vshnpostgresql/README.md.gotmpl deleted file mode 100644 index 66e5256..0000000 --- a/charts/vshnpostgresql/README.md.gotmpl +++ /dev/null @@ -1,158 +0,0 @@ -{{ template "chart.header" . }} - - -{{ template "chart.deprecationWarning" . }} - - -{{ template "chart.badgesSection" . }} - - -> **Warning** -> ### This chart is under active development. -> ### Advised caution when using in production! - - -A note on the chart's purpose ------------------------------ - -This is an opinionated chart that is designed to provide a subset of simple, stable and safe configurations using the -CloudNativePG operator. It is designed to provide a simple way to perform recovery operations to decrease your RTO. - -It is not designed to be a one size fits all solution. If you need a more complicated setup we strongly recommend that -you either: - -* use the operator directly -* create your own chart -* use Kustomize to modify the chart's resources - -**_Note_** that the latter option carries it's own risks as the chart configuration may change, especially before it -reaches a stable release. - -That being said, we welcome PRs that improve the chart, but please keep in mind that we don't plan to support every -single configuration that the operator provides and we may reject PRs that add too much complexity and maintenance -difficulty to the chart. - - -Getting Started ---------------- - -### Installing the Operator -Skip this step if the CNPG operator is already installed in your cluster. - -```console -helm repo add cnpg https://cloudnative-pg.github.io/charts -helm upgrade --install cnpg \ ---namespace cnpg-system \ ---create-namespace \ -cnpg/cloudnative-pg -``` - -### Setting up a CNPG Cluster - -```console -helm repo add cnpg https://cloudnative-pg.github.io/charts -helm upgrade --install cnpg \ ---namespace cnpg-database \ ---create-namespace \ ---values values.yaml \ -cnpg/cluster -``` - -A more detailed guide can be found in the [Getting Started docs](<./docs/Getting Started.md>). - - -Cluster Configuration ---------------------- - -### Database types - -Currently the chart supports two database types. These are configured via the `type` parameter. These are: -* `postgresql` - A standard PostgreSQL database. -* `postgis` - A PostgreSQL database with the PostGIS extension installed. - -Depending on the type the chart will use a different Docker image and fill in some initial setup, like extension installation. - -### Modes of operation - -The chart has three modes of operation. These are configured via the `mode` parameter: -* `standalone` - Creates new or updates an existing CNPG cluster. This is the default mode. -* `replica` - Creates a replica cluster from an existing CNPG cluster. **_Note_ that this mode is not yet supported.** -* `recovery` - Recovers a CNPG cluster from a backup, object store or via pg_basebackup. - -### Backup configuration - -CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object -store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are -stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following -providers are supported: - -* S3 or S3-compatible stores, like MinIO -* Microsoft Azure Blob Storage -* Google Cloud Storage - -Additionally you can specify the following parameters: -* `backups.retentionPolicy` - The retention policy for backups. Defaults to `30d`. -* `backups.scheduledBackups` - An array of scheduled backups containing a name and a crontab schedule. Example: -```yaml -backups: - scheduledBackups: - - name: daily-backup - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self -``` - -Each backup adapter takes it's own set of parameters, listed in the [Configuration options](#Configuration-options) section -below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, -`backup.azure`, or `backup.google`. - - -Recovery --------- - -There is a separate document outlining the recovery procedure here: **[Recovery](docs/Recovery.md)** - - -Examples --------- - -There are several configuration examples in the [examples](examples) directory. Refer to them for a basic setup and -refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/current/) for more advanced configurations. - - -{{ template "chart.requirementsSection" . }} - - -{{ template "chart.valuesSection" . }} -| poolers[].name | string | `` | Name of the pooler resource | -| poolers[].instances | number | `1` | The number of replicas we want | -| poolers[].type | [PoolerType][PoolerType] | `rw` | Type of service to forward traffic to. Default: `rw`. | -| poolers[].poolMode | [PgBouncerPoolMode][PgBouncerPoolMode] | `session` | The pool mode. Default: `session`. | -| poolers[].authQuerySecret | [LocalObjectReference][LocalObjectReference] | `{}` | The credentials of the user that need to be used for the authentication query. | -| poolers[].authQuery | string | `{}` | The credentials of the user that need to be used for the authentication query. | -| poolers[].parameters | map[string]string | `{}` | Additional parameters to be passed to PgBouncer - please check the CNPG documentation for a list of options you can configure | -| poolers[].template | [PodTemplateSpec][PodTemplateSpec] | `{}` | The template of the Pod to be created | -| poolers[].template | [ServiceTemplateSpec][ServiceTemplateSpec] | `{}` | Template for the Service to be created | -| poolers[].pg_hba | []string | `{}` | PostgreSQL Host Based Authentication rules (lines to be appended to the pg_hba.conf file) | -| poolers[].monitoring.enabled | bool | `false` | Whether to enable monitoring for the Pooler. | -| poolers[].monitoring.podMonitor.enabled | bool | `true` | Create a podMonitor for the Pooler. | - -{{ template "chart.maintainersSection" . }} - - -Features that require feedback ------------------------------- - -Please raise a ticket tested any of the following features and they have worked. -Alternatively a ticket and a PR if you have found that something needs a change to work properly. - -- [ ] Google Cloud Storage Backups -- [ ] Google Cloud Storage Recovery - - -TODO ----- -* IAM Role for S3 Service Account -* Automatic provisioning of a Alert Manager configuration - - -{{ template "helm-docs.versionFooter" . }} diff --git a/charts/vshnpostgresql/docs/Getting Started.md b/charts/vshnpostgresql/docs/Getting Started.md deleted file mode 100644 index 2e3b660..0000000 --- a/charts/vshnpostgresql/docs/Getting Started.md +++ /dev/null @@ -1,106 +0,0 @@ -# Getting Started - -The CNPG cluster chart follows a convention over configuration approach. This means that the chart will create a reasonable -CNPG setup with sensible defaults. However, you can override these defaults to create a more customized setup. Note that -you still need to configure backups and monitoring separately. The chart will not install a Prometheus stack for you. - -_**Note,**_ that this is an opinionated chart. It does not support all configuration options that CNPG supports. If you -need a highly customized setup, you should manage your cluster via a Kubernetes CNPG cluster manifest instead of this chart. -Refer to the [CNPG documentation](https://cloudnative-pg.io/documentation/current/) in that case. - -## Installing the operator - -To begin, make sure you install the CNPG operator in you cluster. It can be installed via a Helm chart as shown below or -ir can be installed via a Kubernetes manifest. For more information see the [CNPG documentation](https://cloudnative-pg.io/documentation/current/installation_upgrade/). - -```console -helm repo add cnpg https://cloudnative-pg.github.io/charts -helm upgrade --install cnpg \ - --namespace cnpg-system \ - --create-namespace \ - cnpg/cloudnative-pg -``` - -## Creating a cluster configuration - -Once you have the operator installed, the next step is to prepare the cluster configuration. Whether this will be managed -via a GitOps solution or directly via Helm is up to you. The following sections outlines the important steps in both cases. - -### Choosing the database type - -Currently the chart supports two database types. These are configured via the `type` parameter. These are: -* `postgresql` - A standard PostgreSQL database. -* `postgis` - A PostgreSQL database with the PostGIS extension installed. - -Depending on the type the chart will use a different Docker image and fill in some initial setup, like extension installation. - -### Choosing the mode of operation - -The chart has three modes of operation. These are configured via the `mode` parameter. If this is your first cluster, you -are likely looking for the `standalone` option. -* `standalone` - Creates new or updates an existing CNPG cluster. This is the default mode. -* `replica` - Creates a replica cluster from an existing CNPG cluster. **_Note_ that this mode is not yet supported.** -* `recovery` - Recovers a CNPG cluster from a backup, object store or via pg_basebackup. - -### Backup configuration - -Most importantly you should configure your backup storage. - -CNPG implements disaster recovery via [Barman](https://pgbarman.org/). The following section configures the barman object -store where backups will be stored. Barman performs backups of the cluster filesystem base backup and WALs. Both are -stored in the specified location. The backup provider is configured via the `backups.provider` parameter. The following -providers are supported: - -* S3 or S3-compatible stores, like MinIO -* Microsoft Azure Blob Storage -* Google Cloud Storage - -Additionally you can specify the following parameters: -* `backups.retentionPolicy` - The retention policy for backups. Defaults to `30d`. -* `backups.scheduledBackups` - An array of scheduled backups containing a name and a crontab schedule. Example: - ```yaml - backups: - scheduledBackups: - - name: daily-backup - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self - ``` - -Each backup adapter takes it's own set of parameters, listed in the [Configuration options](../README.md#Configuration-options) section -below. Refer to the table for the full list of parameters and place the configuration under the appropriate key: `backup.s3`, -`backup.azure`, or `backup.google`. - -### Cluster configuration - -There are several important cluster options. Here are the most important ones: - -`cluster.instances` - The number of instances in the cluster. Defaults to `1`, but you should set this to `3` for production. -`cluster.imageName` - This allows you to override the Docker image used for the cluster. The chart will choose a default - for you based on the setting you chose for `type`. If you need to run a configuration that is not supported, you can - create your own Docker image. You can use the [postgres-containers](https://github.com/cloudnative-pg/postgres-containers) - repository for a starting point. - You will likely need to set your own repository access credentials via: `cluster.imagePullPolicy` and `cluster.imagePullSecrets`. -`cluster.storage.size` - The size of the persistent volume claim for the cluster. Defaults to `8Gi`. Every instance will - have it's own persistent volume claim. -`cluster.storage.storageClass` - The storage class to use for the persistent volume claim. -`cluster.resources` - The resource limits and requests for the cluster. You are strongly advised to use the same values - for both limits and requests to ensure a [Guaranteed QoS](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#guaranteed). -`cluster.affinity.topologyKey` - The chart sets it to `topology.kubernetes.io/zone` by default which is useful if you are - running a production cluster in a multi AZ cluster (highly recommended). If you are running a single AZ cluster, you may - want to change that to `kubernetes.io/hostname` to ensure that cluster instances are not provisioned on the same node. -`cluster.postgresql` - Allows you to override PostgreSQL configuration parameters example: - ```yaml - cluster: - postgresql: - max_connections: "200" - shared_buffers: "2GB" - ``` -`cluster.initSQL` - Allows you to run custom SQL queries during the cluster initialization. This is useful for creating -extensions, schemas and databases. Note that these are as a superuser. - -For a full list - refer to the Helm chart [configuration options](../README.md#Configuration-options). - -## Examples - -There are several configuration examples in the [examples](../examples) directory. Refer to them for a basic setup and -refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentation/current/) for more advanced configurations. diff --git a/charts/vshnpostgresql/docs/Recovery.md b/charts/vshnpostgresql/docs/Recovery.md deleted file mode 100644 index 1a7a915..0000000 --- a/charts/vshnpostgresql/docs/Recovery.md +++ /dev/null @@ -1,27 +0,0 @@ -Recovery -======== - -This chart can be used to initiate a recovery operation of a CNPG cluster no matter if it was created with the chart or not. - -CNPG does not support recovery in-place. Instead you need to create a new cluster that will be bootstrapped from the existing one or from a backup. - -You can find more information about the recovery process in the [CNPG documentation](https://cloudnative-pg.io/documentation/current/backup_recovery). - -There are 3 types of recovery possible with CNPG: -* Recovery from a backup object in the same Kubernetes namespace. -* Recovery from a Barman Object Store, that could be located anywhere. -* Streaming replication from an operating cluster using `pg_basebackup`. - -When performing a recovery you are strongly advised to use the same configuration and PostgreSQL version as the original cluster. - -To begin, create a `values.yaml` that contains the following: - -1. Set `mode: recovery` to indicate that you want to perform bootstrap the new cluster from an existing one. -2. Set the `recovery.method` to the type of recovery you want to perform. -3. Set either the `recovery.backupName` or the Barman Object Store configuration - i.e. `recovery.provider` and appropriate S3, Azure or GCS configuration. In case of `pg_basebackup` complete the `recovery.pgBaseBackup` section. -4. Optionally set the `recovery.pitrTarget.time` in RFC3339 format to perform a point-in-time recovery (not applicable for `pgBaseBackup`). -5. Retain the identical PostgreSQL version and configuration as the original cluster. -6. Make sure you don't use the same backup section name as the original cluster. We advise you change the `path` within the storage location if you want to reuse the same storage location/bucket. - One pattern is adding a version number at the end of the path, e.g. `/v1` or `/v2` after each recovery procedure. - -Example recovery configurations can be found in the [examples](../examples) directory. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md deleted file mode 100644 index 8be576c..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHACritical.md +++ /dev/null @@ -1,49 +0,0 @@ -CNPGClusterHACritical -===================== - -Meaning -------- - -The `CNPGClusterHACritical` alert is triggered when the CloudNativePG cluster has no ready standby replicas. - -This can happen during either a normal failover or automated minor version upgrades in a cluster with 2 or less -instances. The replaced instance may need some time to catch-up with the cluster primary instance. - -This alarm will be always triggered if your cluster is configured to run with only 1 instance. In this case you -may want to silence it. - -Impact ------- - -Having no available replicas puts your cluster at a severe risk if the primary instance fails. The primary instance is -still online and able to serve queries, although connections to the `-ro` endpoint will fail. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Get the status of the CloudNativePG cluster instances: - -```bash -kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide -``` - -Check the logs of the affected CloudNativePG instances: - -```bash -kubectl logs --namespace pod/ -``` - -Check the CloudNativePG operator logs: - -```bash -kubectl logs --namespace cnpg-system -l "app.kubernetes.io/name=cloudnative-pg" -``` - -Mitigation ----------- - -Refer to the [CloudNativePG Failure Modes](https://cloudnative-pg.io/documentation/current/failure_modes/) -and [CloudNativePG Troubleshooting](https://cloudnative-pg.io/documentation/current/troubleshooting/) documentation for -more information on how to troubleshoot and mitigate this issue. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md deleted file mode 100644 index 80acfad..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHAWarning.md +++ /dev/null @@ -1,51 +0,0 @@ -CNPGClusterHAWarning -==================== - -Meaning -------- - -The `CNPGClusterHAWarning` alert is triggered when the CloudNativePG cluster ready standby replicas are less than `2`. - -This alarm will be always triggered if your cluster is configured to run with less than `3` instances. In this case you -may want to silence it. - -Impact ------- - -Having less than two available replicas puts your cluster at risk if another instance fails. The cluster is still able -to operate normally, although the `-ro` and `-r` endpoints operate at reduced capacity. - -This can happen during a normal failover or automated minor version upgrades. The replaced instance may need some time -to catch-up with the cluster primary instance which will trigger the alert if the operation takes more than 5 minutes. - -At `0` available ready replicas, a `CNPGClusterHACritical` alert will be triggered. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Get the status of the CloudNativePG cluster instances: - -```bash -kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide -``` - -Check the logs of the affected CloudNativePG instances: - -```bash -kubectl logs --namespace pod/ -``` - -Check the CloudNativePG operator logs: - -```bash -kubectl logs --namespace cnpg-system -l "app.kubernetes.io/name=cloudnative-pg" -``` - -Mitigation ----------- - -Refer to the [CloudNativePG Failure Modes](https://cloudnative-pg.io/documentation/current/failure_modes/) -and [CloudNativePG Troubleshooting](https://cloudnative-pg.io/documentation/current/troubleshooting/) documentation for -more information on how to troubleshoot and mitigate this issue. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md deleted file mode 100644 index 2003421..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsCritical.md +++ /dev/null @@ -1,24 +0,0 @@ -CNPGClusterHighConnectionsCritical -================================== - -Meaning -------- - -This alert is triggered when the number of connections to the CloudNativePG cluster instance exceeds 95% of its capacity. - -Impact ------- - -At 100% capacity, the CloudNativePG cluster instance will not be able to accept new connections. This will result in a service -disruption. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Mitigation ----------- - -* Increase the maximum number of connections by increasing the `max_connections` PostgreSQL parameter. -* Use connection pooling by enabling PgBouncer to reduce the number of connections to the database. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md deleted file mode 100644 index 636579f..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighConnectionsWarning.md +++ /dev/null @@ -1,24 +0,0 @@ -CNPGClusterHighConnectionsWarning -================================= - -Meaning -------- - -This alert is triggered when the number of connections to the CloudNativePG cluster instance exceeds 85% of its capacity. - -Impact ------- - -At 100% capacity, the CloudNativePG cluster instance will not be able to accept new connections. This will result in a service -disruption. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Mitigation ----------- - -* Increase the maximum number of connections by increasing the `max_connections` PostgreSQL parameter. -* Use connection pooling by enabling PgBouncer to reduce the number of connections to the database. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md deleted file mode 100644 index 78963ce..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterHighReplicationLag.md +++ /dev/null @@ -1,31 +0,0 @@ -CNPGClusterHighReplicationLag -============================= - -Meaning -------- - -This alert is triggered when the replication lag of the CloudNativePG cluster exceed `1s`. - -Impact ------- - -High replication lag can cause the cluster replicas become out of sync. Queries to the `-r` and `-ro` endpoints may return stale data. -In the event of a failover, there may be data loss for the time period of the lag. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -High replication lag can be caused by a number of factors, including: -* Network issues -* High load on the primary or replicas -* Long running queries -* Suboptimal PostgreSQL configuration, in particular small numbers of `max_wal_senders`. - -```yaml -kubectl exec --namespace --stdin --tty services/-rw -- psql -c "SELECT * from pg_stat_replication;" -``` - -Mitigation ----------- diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md deleted file mode 100644 index df309ff..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterInstancesOnSameNode.md +++ /dev/null @@ -1,28 +0,0 @@ -CNPGClusterInstancesOnSameNode -============================ - -Meaning -------- - -The `CNPGClusterInstancesOnSameNode` alert is raised when two or more database pods are scheduled on the same node. - -Impact ------- - -A failure or scheduled downtime of a single node will lead to a potential service disruption and/or data loss. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -```bash -kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide -``` - -Mitigation ----------- - -1. Verify you have more than a single node with no taints, preventing pods to be scheduled there. -2. Verify your [affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) configuration. -3. For more information, please refer to the ["Scheduling"](https://cloudnative-pg.io/documentation/current/scheduling/) section in the documentation diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md deleted file mode 100644 index 5b73552..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceCritical.md +++ /dev/null @@ -1,31 +0,0 @@ -CNPGClusterLowDiskSpaceCritical -=============================== - -Meaning -------- - -This alert is triggered when the disk space on the CloudNativePG cluster exceeds 90%. It can be triggered by either: - -* the PVC hosting the `PGDATA` (`storage` section) -* the PVC hosting WAL files (`walStorage` section), where applicable -* any PVC hosting a tablespace (`tablespaces` section) - -Impact ------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Excessive disk space usage can lead fragmentation negatively impacting performance. Reaching 100% disk usage will result -in downtime and data loss. - -Diagnosis ---------- - -Mitigation ----------- - -If you experience issues with the WAL (Write-Ahead Logging) volume and have -set up continuous archiving, ensure that WAL archiving is functioning -correctly. This is crucial to avoid a buildup of WAL files in the `pg_wal` -folder. Monitor the `cnpg_collector_pg_wal_archive_status` metric, specifically -ensuring that the number of `ready` files does not increase linearly. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md deleted file mode 100644 index 36e56ac..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterLowDiskSpaceWarning.md +++ /dev/null @@ -1,31 +0,0 @@ -CNPGClusterLowDiskSpaceWarning -============================== - -Meaning -------- - -This alert is triggered when the disk space on the CloudNativePG cluster exceeds 90%. It can be triggered by either: - -* the PVC hosting the `PGDATA` (`storage` section) -* the PVC hosting WAL files (`walStorage` section), where applicable -* any PVC hosting a tablespace (`tablespaces` section) - -Impact ------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Excessive disk space usage can lead fragmentation negatively impacting performance. Reaching 100% disk usage will result -in downtime and data loss. - -Diagnosis ---------- - -Mitigation ----------- - -If you experience issues with the WAL (Write-Ahead Logging) volume and have -set up continuous archiving, ensure that WAL archiving is functioning -correctly. This is crucial to avoid a buildup of WAL files in the `pg_wal` -folder. Monitor the `cnpg_collector_pg_wal_archive_status` metric, specifically -ensuring that the number of `ready` files does not increase linearly. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md deleted file mode 100644 index 0e69db1..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterOffline.md +++ /dev/null @@ -1,43 +0,0 @@ -CNPGClusterOffline -================== - -Meaning -------- - -The `CNPGClusterOffline` alert is triggered when there are no ready CloudNativePG instances. - -Impact ------- - -Having an offline cluster means your applications will not be able to access the database, leading to potential service -disruption. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Get the status of the CloudNativePG cluster instances: - -```bash -kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide -``` - -Check the logs of the affected CloudNativePG instances: - -```bash -kubectl logs --namespace pod/ -``` - -Check the CloudNativePG operator logs: - -```bash -kubectl logs --namespace cnpg-system -l "app.kubernetes.io/name=cloudnative-pg" -``` - -Mitigation ----------- - -Refer to the [CloudNativePG Failure Modes](https://cloudnative-pg.io/documentation/current/failure_modes/) -and [CloudNativePG Troubleshooting](https://cloudnative-pg.io/documentation/current/troubleshooting/) documentation for -more information on how to troubleshoot and mitigate this issue. diff --git a/charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md b/charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md deleted file mode 100644 index c5bdb05..0000000 --- a/charts/vshnpostgresql/docs/runbooks/CNPGClusterZoneSpreadWarning.md +++ /dev/null @@ -1,37 +0,0 @@ -CNPGClusterZoneSpreadWarning -============================ - -Meaning -------- - -The `CNPGClusterZoneSpreadWarning` alert is raised when pods are not evenly distributed across availability zones. To be -more accurate, the alert is raised when the number of `pods > zones < 3`. - -Impact ------- - -The uneven distribution of pods across availability zones can lead to a single point of failure if a zone goes down. - -Diagnosis ---------- - -Use the [CloudNativePG Grafana Dashboard](https://grafana.com/grafana/dashboards/20417-cloudnativepg/). - -Get the status of the CloudNativePG cluster instances: - -```bash -kubectl get pods -A -l "cnpg.io/podRole=instance" -o wide -``` - -Get the nodes and their respective zones: - -```bash -kubectl get nodes --label-columns topology.kubernetes.io/zone -``` - -Mitigation ----------- - -1. Verify you have more than a single node with no taints, preventing pods to be scheduled in each availability zone. -2. Verify your [affinity](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) configuration. -3. Delete the pods and their respective PVC that are not in the desired availability zone and allow the operator to repair the cluster. diff --git a/charts/vshnpostgresql/examples/basic.yaml b/charts/vshnpostgresql/examples/basic.yaml deleted file mode 100644 index b4c15bb..0000000 --- a/charts/vshnpostgresql/examples/basic.yaml +++ /dev/null @@ -1,8 +0,0 @@ -type: postgresql -mode: standalone -version: - postgresql: "16" -cluster: - instances: 1 -backups: - enabled: false diff --git a/charts/vshnpostgresql/examples/custom-queries.yaml b/charts/vshnpostgresql/examples/custom-queries.yaml deleted file mode 100644 index 7995202..0000000 --- a/charts/vshnpostgresql/examples/custom-queries.yaml +++ /dev/null @@ -1,24 +0,0 @@ -type: postgresql -mode: standalone - -cluster: - instances: 1 - monitoring: - enabled: true - customQueries: - - name: "pg_cache_hit" - query: | - SELECT - current_database() as datname, - sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) as ratio - FROM pg_statio_user_tables; - metrics: - - datname: - usage: "LABEL" - description: "Name of the database database" - - ratio: - usage: GAUGE - description: "Cache hit ratio" - -backups: - enabled: false diff --git a/charts/vshnpostgresql/examples/image-catalog-ref.yaml b/charts/vshnpostgresql/examples/image-catalog-ref.yaml deleted file mode 100644 index e4833a3..0000000 --- a/charts/vshnpostgresql/examples/image-catalog-ref.yaml +++ /dev/null @@ -1,12 +0,0 @@ -type: postgresql -mode: standalone -version: - major: "16" - timescaledb: "2.15" -cluster: - instances: 1 - imageCatalogRef: - kind: ImageCatalog - name: my-image-catalog -backups: - enabled: false diff --git a/charts/vshnpostgresql/examples/image-catalog.yaml b/charts/vshnpostgresql/examples/image-catalog.yaml deleted file mode 100644 index c610229..0000000 --- a/charts/vshnpostgresql/examples/image-catalog.yaml +++ /dev/null @@ -1,14 +0,0 @@ -type: postgresql -mode: standalone -version: - major: "16" - timescaledb: "2.15" -cluster: - instances: 1 -backups: - enabled: false -imageCatalog: - create: true - images: - - major: 16 - image: my-custom-postgres-image:mytag diff --git a/charts/vshnpostgresql/examples/pgbouncer.yaml b/charts/vshnpostgresql/examples/pgbouncer.yaml deleted file mode 100644 index 94d4987..0000000 --- a/charts/vshnpostgresql/examples/pgbouncer.yaml +++ /dev/null @@ -1,34 +0,0 @@ -type: postgresql -mode: standalone - -cluster: - instances: 1 - monitoring: - enabled: true - podMonitor: - enabled: true - -backups: - enabled: false - -poolers: - - name: rw - type: rw - instances: 1 - monitoring: - enabled: true - podMonitor: - enabled: true - relabelings: - - targetLabel: type - replacement: rw - - name: ro - type: ro - instances: 1 - monitoring: - enabled: true - podMonitor: - enabled: true - relabelings: - - targetLabel: type - replacement: ro diff --git a/charts/vshnpostgresql/examples/postgis.yaml b/charts/vshnpostgresql/examples/postgis.yaml deleted file mode 100644 index 168ac9f..0000000 --- a/charts/vshnpostgresql/examples/postgis.yaml +++ /dev/null @@ -1,9 +0,0 @@ -type: postgis -mode: standalone -version: - postgresql: "16" - postgis: "3.4" -cluster: - instances: 1 -backups: - enabled: false diff --git a/charts/vshnpostgresql/examples/recovery-backup.yaml b/charts/vshnpostgresql/examples/recovery-backup.yaml deleted file mode 100644 index c478e7a..0000000 --- a/charts/vshnpostgresql/examples/recovery-backup.yaml +++ /dev/null @@ -1,23 +0,0 @@ -type: postgresql -mode: recovery - -recovery: - method: backup - backupName: "database-clustermarket-database-daily-backup-1683244800" - -cluster: - instances: 1 - -backups: - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1-restore" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" - scheduledBackups: - - name: daily-backup # Daily at midnight - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self - retentionPolicy: "30d" \ No newline at end of file diff --git a/charts/vshnpostgresql/examples/recovery-object_store.yaml b/charts/vshnpostgresql/examples/recovery-object_store.yaml deleted file mode 100644 index 060f532..0000000 --- a/charts/vshnpostgresql/examples/recovery-object_store.yaml +++ /dev/null @@ -1,31 +0,0 @@ -type: postgresql -mode: recovery - -recovery: - method: object_store - clusterName: "cluster-name-to-recover-from" - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1-restore" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" - -cluster: - instances: 1 - -backups: - endpointURL: "https://cm-db-chart-test.ams3.digitaloceanspaces.com" - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1-restore" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" - scheduledBackups: - - name: daily-backup # Daily at midnight - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self - retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml b/charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml deleted file mode 100644 index 05358bf..0000000 --- a/charts/vshnpostgresql/examples/recovery-pg_basebackup.yaml +++ /dev/null @@ -1,15 +0,0 @@ -type: postgresql -mode: "recovery" - -recovery: - method: "pg_basebackup" - pgBaseBackup: - sourceHost: "source-db.foo.com" - sourceUsername: "streaming_replica" - existingPasswordSecret: "source-db-replica-password" - -cluster: - instances: 1 - -backups: - enabled: false \ No newline at end of file diff --git a/charts/vshnpostgresql/examples/standalone-s3.yaml b/charts/vshnpostgresql/examples/standalone-s3.yaml deleted file mode 100644 index 44a4bb1..0000000 --- a/charts/vshnpostgresql/examples/standalone-s3.yaml +++ /dev/null @@ -1,20 +0,0 @@ -type: postgresql -mode: standalone - -cluster: - instances: 1 - -backups: - enabled: true - provider: s3 - s3: - region: "eu-west-1" - bucket: "db-backups" - path: "/v1" - accessKey: "AWS_S3_ACCESS_KEY" - secretKey: "AWS_S3_SECRET_KEY" - scheduledBackups: - - name: daily-backup # Daily at midnight - schedule: "0 0 0 * * *" # Daily at midnight - backupOwnerReference: self - retentionPolicy: "30d" diff --git a/charts/vshnpostgresql/examples/timescaledb.yaml b/charts/vshnpostgresql/examples/timescaledb.yaml deleted file mode 100644 index 328b6c1..0000000 --- a/charts/vshnpostgresql/examples/timescaledb.yaml +++ /dev/null @@ -1,9 +0,0 @@ -type: timescaledb -mode: standalone -version: - postgresql: "15.7" - timescaledb: "2.15" -cluster: - instances: 1 -backups: - enabled: false From 5b27ca58b24aafea082033bd2b98af2190d80316 Mon Sep 17 00:00:00 2001 From: Mike Ditton Date: Tue, 11 Nov 2025 15:16:37 +0100 Subject: [PATCH 5/6] Base names on relesae name instead of cluster fullname This uses the release name instead of the cluster fullname as a prefix for the barman object store related resources. --- charts/vshnpostgresql/templates/_helpers.tpl | 2 +- charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml | 4 ++-- charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml | 2 +- charts/vshnpostgresql/templates/ca-bundle.yaml | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/charts/vshnpostgresql/templates/_helpers.tpl b/charts/vshnpostgresql/templates/_helpers.tpl index 6d040c7..0e1e357 100644 --- a/charts/vshnpostgresql/templates/_helpers.tpl +++ b/charts/vshnpostgresql/templates/_helpers.tpl @@ -152,6 +152,6 @@ Backups ObjectStore Name {{- if .Values.backups.plugin.objectStoreName -}} {{- .Values.backups.plugin.objectStoreName -}} {{- else -}} - {{- printf "%s-objectstore" (include "cluster.fullname" .) -}} + {{- printf "%s-objectstore" .Release.Name -}} {{- end -}} {{- end -}} diff --git a/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml b/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml index 64bdca8..347aebe 100644 --- a/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml +++ b/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml @@ -12,7 +12,7 @@ spec: {{- end }} {{- if or (.Values.backups.endpointCA.create) (.Values.backups.endpointCA.name) }} endpointCA: - name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" (include "cluster.fullname" .)) }} + name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" .Release.Name) }} key: {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" }} {{- end }} {{- if .Values.backups.destinationPath }} @@ -20,7 +20,7 @@ spec: {{- else }} destinationPath: "s3://{{ required "You need to specify S3 bucket if destinationPath is not specified." .Values.backups.s3.bucket }}{{ .Values.backups.s3.path }}" {{- end }} - {{- $secretName := .Values.backups.secret.name | default (printf "%s-barman-plugin-s3-creds" (include "cluster.fullname" .)) }} + {{- $secretName := .Values.backups.secret.name | default (printf "%s-barman-plugin-s3-creds" .Release.Name) }} s3Credentials: {{- if .Values.backups.s3.inheritFromIAMRole }} inheritFromIAMRole: true diff --git a/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml b/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml index 7018b56..3a495cf 100644 --- a/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml +++ b/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml @@ -2,7 +2,7 @@ apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-barman-plugin-s3-creds" (include "cluster.fullname" .)) .Values.backups.secret.name }} + name: {{ default (printf "%s-barman-plugin-s3-creds" .Release.Name) .Values.backups.secret.name }} namespace: {{ include "cluster.namespace" . }} data: ACCESS_KEY_ID: {{ required ".Values.backups.s3.accessKey is required, but not specified." .Values.backups.s3.accessKey | b64enc | quote }} diff --git a/charts/vshnpostgresql/templates/ca-bundle.yaml b/charts/vshnpostgresql/templates/ca-bundle.yaml index d0bef28..75f90ce 100644 --- a/charts/vshnpostgresql/templates/ca-bundle.yaml +++ b/charts/vshnpostgresql/templates/ca-bundle.yaml @@ -3,9 +3,9 @@ apiVersion: v1 kind: Secret metadata: {{- if eq .Values.backups.method "plugin" }} - name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" (include "cluster.fullname" .)) | quote }} + name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" .Release.Name) | quote }} {{- else }} - name: {{ .Values.backups.endpointCA.name | default (printf "%s-ca-bundle" (include "cluster.fullname" .)) | quote }} + name: {{ .Values.backups.endpointCA.name | default (printf "%s-ca-bundle" .Release.Name) | quote }} {{- end }} namespace: {{ include "cluster.namespace" . }} data: From 3acfca709a7de3f9b0e64427f2b8b8fa2f829377 Mon Sep 17 00:00:00 2001 From: Mike Ditton Date: Fri, 14 Nov 2025 14:08:57 +0100 Subject: [PATCH 6/6] Simplify object store configuration This simplifies the object store and its related resources to only expose what we actually need --- charts/vshnpostgresql/templates/_helpers.tpl | 10 ---- .../templates/barman-cloud-objectstore.yaml | 28 ++--------- .../templates/barman-plugin-s3-creds.yaml | 8 ++-- .../vshnpostgresql/templates/ca-bundle.yaml | 14 ------ charts/vshnpostgresql/templates/cluster.yaml | 6 +-- .../templates/scheduled-backups.yaml | 4 +- charts/vshnpostgresql/values.yaml | 47 +------------------ 7 files changed, 15 insertions(+), 102 deletions(-) delete mode 100644 charts/vshnpostgresql/templates/ca-bundle.yaml diff --git a/charts/vshnpostgresql/templates/_helpers.tpl b/charts/vshnpostgresql/templates/_helpers.tpl index 0e1e357..563901f 100644 --- a/charts/vshnpostgresql/templates/_helpers.tpl +++ b/charts/vshnpostgresql/templates/_helpers.tpl @@ -145,13 +145,3 @@ Postgres GID {{- end -}} {{- end -}} -{{/* -Backups ObjectStore Name -*/}} -{{- define "cluster.backups.objectStoreName" -}} - {{- if .Values.backups.plugin.objectStoreName -}} - {{- .Values.backups.plugin.objectStoreName -}} - {{- else -}} - {{- printf "%s-objectstore" .Release.Name -}} - {{- end -}} -{{- end -}} diff --git a/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml b/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml index 347aebe..f80f0d6 100644 --- a/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml +++ b/charts/vshnpostgresql/templates/barman-cloud-objectstore.yaml @@ -2,7 +2,7 @@ apiVersion: barmancloud.cnpg.io/v1 kind: ObjectStore metadata: - name: {{ include "cluster.backups.objectStoreName" . }} + name: {{ printf "%s-objectstore" .Release.Name }} namespace: {{ include "cluster.namespace" . }} labels: {{ include "cluster.labels" . | nindent 4 }} spec: @@ -10,28 +10,14 @@ spec: {{- if .Values.backups.endpointURL }} endpointURL: {{ .Values.backups.endpointURL | quote }} {{- end }} - {{- if or (.Values.backups.endpointCA.create) (.Values.backups.endpointCA.name) }} - endpointCA: - name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" .Release.Name) }} - key: {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" }} - {{- end }} - {{- if .Values.backups.destinationPath }} - destinationPath: {{ .Values.backups.destinationPath }} - {{- else }} - destinationPath: "s3://{{ required "You need to specify S3 bucket if destinationPath is not specified." .Values.backups.s3.bucket }}{{ .Values.backups.s3.path }}" - {{- end }} - {{- $secretName := .Values.backups.secret.name | default (printf "%s-barman-plugin-s3-creds" .Release.Name) }} + destinationPath: "s3://{{ required "You need to specify S3 bucket." .Values.backups.s3.bucket }}" s3Credentials: - {{- if .Values.backups.s3.inheritFromIAMRole }} - inheritFromIAMRole: true - {{- else }} accessKeyId: - name: {{ $secretName }} + name: {{ printf "%s-barman-plugin-s3-creds" .Release.Name }} key: ACCESS_KEY_ID secretAccessKey: - name: {{ $secretName }} + name: {{ printf "%s-barman-plugin-s3-creds" .Release.Name }} key: ACCESS_SECRET_KEY - {{- end }} wal: {{- if .Values.backups.wal.compression }} compression: {{ .Values.backups.wal.compression }} @@ -39,9 +25,6 @@ spec: {{- if .Values.backups.wal.encryption }} encryption: {{ .Values.backups.wal.encryption }} {{- end }} - {{- if .Values.backups.wal.maxParallel }} - maxParallel: {{ .Values.backups.wal.maxParallel }} - {{- end }} data: {{- if .Values.backups.data.compression }} compression: {{ .Values.backups.data.compression }} @@ -49,7 +32,4 @@ spec: {{- if .Values.backups.data.encryption }} encryption: {{ .Values.backups.data.encryption }} {{- end }} - {{- if .Values.backups.data.jobs }} - jobs: {{ .Values.backups.data.jobs }} - {{- end }} {{ end }} diff --git a/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml b/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml index 3a495cf..99d663a 100644 --- a/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml +++ b/charts/vshnpostgresql/templates/barman-plugin-s3-creds.yaml @@ -1,10 +1,10 @@ -{{- if and .Values.backups.enabled (eq .Values.backups.method "plugin") .Values.backups.plugin.createObjectStore (eq .Values.backups.provider "s3") (not .Values.backups.s3.inheritFromIAMRole) .Values.backups.secret.create }} +{{- if and .Values.backups.enabled (eq .Values.backups.method "plugin") .Values.backups.plugin.createObjectStore }} apiVersion: v1 kind: Secret metadata: - name: {{ default (printf "%s-barman-plugin-s3-creds" .Release.Name) .Values.backups.secret.name }} + name: {{ printf "%s-barman-plugin-s3-creds" .Release.Name }} namespace: {{ include "cluster.namespace" . }} data: - ACCESS_KEY_ID: {{ required ".Values.backups.s3.accessKey is required, but not specified." .Values.backups.s3.accessKey | b64enc | quote }} - ACCESS_SECRET_KEY: {{ required ".Values.backups.s3.secretKey is required, but not specified." .Values.backups.s3.secretKey | b64enc | quote }} + ACCESS_KEY_ID: {{ required ".Values.backups.s3.accessKey is required." .Values.backups.s3.accessKey | b64enc | quote }} + ACCESS_SECRET_KEY: {{ required ".Values.backups.s3.secretKey is required." .Values.backups.s3.secretKey | b64enc | quote }} {{- end }} diff --git a/charts/vshnpostgresql/templates/ca-bundle.yaml b/charts/vshnpostgresql/templates/ca-bundle.yaml deleted file mode 100644 index 75f90ce..0000000 --- a/charts/vshnpostgresql/templates/ca-bundle.yaml +++ /dev/null @@ -1,14 +0,0 @@ -{{- if and .Values.backups.enabled .Values.backups.endpointCA.create }} -apiVersion: v1 -kind: Secret -metadata: - {{- if eq .Values.backups.method "plugin" }} - name: {{ .Values.backups.endpointCA.name | default (printf "%s-barman-plugin-ca-bundle" .Release.Name) | quote }} - {{- else }} - name: {{ .Values.backups.endpointCA.name | default (printf "%s-ca-bundle" .Release.Name) | quote }} - {{- end }} - namespace: {{ include "cluster.namespace" . }} -data: - {{ .Values.backups.endpointCA.key | default "ca-bundle.crt" | quote }}: {{ .Values.backups.endpointCA.value }} - -{{- end }} diff --git a/charts/vshnpostgresql/templates/cluster.yaml b/charts/vshnpostgresql/templates/cluster.yaml index aa8bb40..7ea0a33 100644 --- a/charts/vshnpostgresql/templates/cluster.yaml +++ b/charts/vshnpostgresql/templates/cluster.yaml @@ -143,10 +143,10 @@ spec: {{- end }} {{- if and .Values.backups.enabled (eq .Values.backups.method "plugin") }} plugins: - - name: {{ .Values.backups.plugin.name }} - isWALArchiver: {{ .Values.backups.plugin.isWALArchiver }} + - name: barman-cloud.cloudnative-pg.io + isWALArchiver: true parameters: - barmanObjectName: {{ include "cluster.backups.objectStoreName" . }} + barmanObjectName: {{ printf "%s-objectstore" .Release.Name }} {{- end }} {{ include "cluster.bootstrap" . | nindent 2 }} {{ include "cluster.backup" . | nindent 2 }} diff --git a/charts/vshnpostgresql/templates/scheduled-backups.yaml b/charts/vshnpostgresql/templates/scheduled-backups.yaml index d942242..e2af3f6 100644 --- a/charts/vshnpostgresql/templates/scheduled-backups.yaml +++ b/charts/vshnpostgresql/templates/scheduled-backups.yaml @@ -20,9 +20,9 @@ spec: cluster: name: {{ include "cluster.fullname" $context }} pluginConfiguration: - name: {{ $context.Values.backups.plugin.name }} + name: barman-cloud.cloudnative-pg.io parameters: - barmanObjectName: {{ include "cluster.backups.objectStoreName" $context }} + barmanObjectName: {{ printf "%s-objectstore" $context.Release.Name }} {{- else }} method: {{ $context.Values.backups.method }} backupOwnerReference: {{ .backupOwnerReference }} diff --git a/charts/vshnpostgresql/values.yaml b/charts/vshnpostgresql/values.yaml index 31f6bbf..11f3b60 100644 --- a/charts/vshnpostgresql/values.yaml +++ b/charts/vshnpostgresql/values.yaml @@ -407,75 +407,32 @@ backups: # -- Overrides the provider specific default endpoint. Defaults to: # S3: https://s3..amazonaws.com" endpointURL: "" # Leave empty if using the default S3 endpoint - # -- Specifies a CA bundle to validate a privately signed certificate. - endpointCA: - # -- Creates a secret with the given value if true, otherwise uses an existing secret. - create: false - name: "" - key: "" - value: "" - # -- Overrides the provider specific default path. Defaults to: - # S3: s3:// - # Azure: https://..core.windows.net/ - # Google: gs:// - destinationPath: "" - # -- One of `s3`, `azure` or `google` + # -- One of `s3`, `azure` or `google` (only used for non-plugin backup method) provider: s3 + s3: region: "" bucket: "" - path: "/" accessKey: "" secretKey: "" - # -- Use the role based authentication without providing explicitly the keys - inheritFromIAMRole: false - azure: - path: "/" - connectionString: "" - storageAccount: "" - storageKey: "" - storageSasToken: "" - containerName: "" - serviceName: blob - inheritFromAzureAD: false - google: - path: "/" - bucket: "" - gkeEnvironment: false - applicationCredentials: "" - secret: - # -- Whether to create a secret for the backup credentials - create: true - # -- Name of the backup credentials secret - name: "" wal: # -- WAL compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. compression: gzip # -- Whether to instruct the storage provider to encrypt WAL files. One of `` (use the storage container default), `AES256` or `aws:kms`. encryption: AES256 - # -- Number of WAL files to be archived or restored in parallel. - maxParallel: 1 data: # -- Data compression method. One of `` (for no compression), `gzip`, `bzip2` or `snappy`. compression: gzip # -- Whether to instruct the storage provider to encrypt data files. One of `` (use the storage container default), `AES256` or `aws:kms`. encryption: AES256 - # -- Number of data files to be archived or restored in parallel. - jobs: 2 # -- Retention policy for backups retentionPolicy: "30d" # -- Plugin-specific configuration (only used when method is 'plugin') plugin: - # -- Plugin name - name: barman-cloud.cloudnative-pg.io - # -- Whether the plugin should be used as a WAL archiver - isWALArchiver: true - # -- Name of the ObjectStore resource to use (will be created if createObjectStore is true) - objectStoreName: "" # -- Create an ObjectStore resource createObjectStore: true