diff --git a/charts/cluster/README.md b/charts/cluster/README.md index bf30859ce..439b926af 100644 --- a/charts/cluster/README.md +++ b/charts/cluster/README.md @@ -153,6 +153,7 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | 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.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.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 | @@ -164,8 +165,8 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | cluster.monitoring.podMonitor.enabled | bool | `true` | Whether to enable the PodMonitor | | cluster.monitoring.prometheusRule.enabled | bool | `true` | Whether to enable the PrometheusRule automated alerts | | cluster.monitoring.prometheusRule.excludeRules | list | `[]` | Exclude specified rules | -| cluster.postgresGID | int | `26` | The GID of the postgres user inside the image, defaults to 26 | -| cluster.postgresUID | int | `26` | The UID of the postgres user inside the image, defaults to 26 | +| 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.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.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. | @@ -180,6 +181,8 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | 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 | | pooler.enabled | bool | `false` | Whether to enable PgBouncer | @@ -236,7 +239,10 @@ refer to the [CloudNativePG Documentation](https://cloudnative-pg.io/documentat | 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` | +| 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 | ## Maintainers diff --git a/charts/cluster/examples/basic.yaml b/charts/cluster/examples/basic.yaml index 5b608c267..730612c2f 100644 --- a/charts/cluster/examples/basic.yaml +++ b/charts/cluster/examples/basic.yaml @@ -1,4 +1,6 @@ mode: standalone +version: + postgresql: "16" cluster: instances: 1 backups: diff --git a/charts/cluster/examples/image-catalog-ref.yaml b/charts/cluster/examples/image-catalog-ref.yaml new file mode 100644 index 000000000..e4833a3b6 --- /dev/null +++ b/charts/cluster/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/cluster/examples/image-catalog.yaml b/charts/cluster/examples/image-catalog.yaml new file mode 100644 index 000000000..c610229b0 --- /dev/null +++ b/charts/cluster/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/cluster/examples/postgis.yaml b/charts/cluster/examples/postgis.yaml index 6c686dc62..168ac9fbf 100644 --- a/charts/cluster/examples/postgis.yaml +++ b/charts/cluster/examples/postgis.yaml @@ -1,6 +1,9 @@ type: postgis mode: standalone +version: + postgresql: "16" + postgis: "3.4" cluster: instances: 1 backups: - enabled: false \ No newline at end of file + enabled: false diff --git a/charts/cluster/examples/timescaledb.yaml b/charts/cluster/examples/timescaledb.yaml new file mode 100644 index 000000000..328b6c1eb --- /dev/null +++ b/charts/cluster/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/cluster/templates/NOTES.txt b/charts/cluster/templates/NOTES.txt index ba44e95df..6a28fa592 100644 --- a/charts/cluster/templates/NOTES.txt +++ b/charts/cluster/templates/NOTES.txt @@ -37,7 +37,7 @@ Configuration {{- $redundancyColor = "ok" -}} {{- end }} -{{ $scheduledBackups := (first .Values.backups.scheduledBackups).name }} +{{- $scheduledBackups := (first .Values.backups.scheduledBackups).name -}} {{- range (rest .Values.backups.scheduledBackups) -}} {{ $scheduledBackups = printf "%s, %s" $scheduledBackups .name }} {{- end -}} @@ -54,12 +54,19 @@ Configuration {{- 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" (include "cluster.imageName" .)) }} │ +│ Image │ {{ include "cluster.color-info" (printf "%-56s" $image) }} │ {{- if eq .Values.mode "recovery" }} │ Source │ {{ printf "%-56s" $source }} │ {{- end }} diff --git a/charts/cluster/templates/_helpers.tpl b/charts/cluster/templates/_helpers.tpl index db3c253e5..0bfa47fa5 100644 --- a/charts/cluster/templates/_helpers.tpl +++ b/charts/cluster/templates/_helpers.tpl @@ -51,6 +51,20 @@ app.kubernetes.io/instance: {{ .Release.Name }} app.kubernetes.io/part-of: cloudnative-pg {{- end }} +{{/* +Whether we need to use TimescaleDB defualts +*/}} +{{- 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 @@ -59,12 +73,63 @@ If a custom imageName is available, use it, otherwise use the defaults based on {{- if .Values.cluster.imageName -}} {{- .Values.cluster.imageName -}} {{- else if eq .Values.type "postgresql" -}} - {{- "ghcr.io/cloudnative-pg/postgresql:15.2" -}} + {{- printf "ghcr.io/cloudnative-pg/postgresql:%s" .Values.version.postgresql -}} {{- else if eq .Values.type "postgis" -}} - {{- "ghcr.io/cloudnative-pg/postgis:14" -}} - {{- else if eq .Values.type "timescaledb" -}} - {{ fail "You need to provide your own cluster.imageName as an official timescaledb image doesn't exist yet." }} + {{- 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, otherwice 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/cluster/templates/cluster.yaml b/charts/cluster/templates/cluster.yaml index ba2b87643..232c2b18e 100644 --- a/charts/cluster/templates/cluster.yaml +++ b/charts/cluster/templates/cluster.yaml @@ -13,14 +13,14 @@ metadata: {{- end }} spec: instances: {{ .Values.cluster.instances }} - imageName: {{ include "cluster.imageName" . }} + {{- include "cluster.image" . | nindent 2 }} imagePullPolicy: {{ .Values.cluster.imagePullPolicy }} - {{- with .Values.cluster.imagePullSecrets}} + {{- with .Values.cluster.imagePullSecrets }} imagePullSecrets: {{- . | toYaml | nindent 4 }} {{- end }} - postgresUID: {{ .Values.cluster.postgresUID }} - postgresGID: {{ .Values.cluster.postgresGID }} + postgresUID: {{ include "cluster.postgresUID" . }} + postgresGID: {{ include "cluster.postgresGID" . }} storage: size: {{ .Values.cluster.storage.size }} storageClass: {{ .Values.cluster.storage.storageClass }} diff --git a/charts/cluster/templates/image-catalog-timescaledb-ha.yaml b/charts/cluster/templates/image-catalog-timescaledb-ha.yaml new file mode 100644 index 000000000..d611171e1 --- /dev/null +++ b/charts/cluster/templates/image-catalog-timescaledb-ha.yaml @@ -0,0 +1,18 @@ +{{- if eq (include "cluster.useTimescaleDBDefaults" .) "true" -}} +apiVersion: postgresql.cnpg.io/v1 +kind: ImageCatalog +metadata: + name: {{ include "cluster.fullname" . }}-timescaledb-ha +spec: + images: + - major: 12 + image: timescale/timescaledb-ha:pg15-ts{{ .Values.version.timescaledb }} + - major: 13 + image: timescale/timescaledb-ha:pg15-ts{{ .Values.version.timescaledb }} + - major: 14 + image: timescale/timescaledb-ha:pg15-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/cluster/templates/image-catalog.yaml b/charts/cluster/templates/image-catalog.yaml new file mode 100644 index 000000000..6dc707222 --- /dev/null +++ b/charts/cluster/templates/image-catalog.yaml @@ -0,0 +1,12 @@ +{{ if and .Values.imageCatalog.create (not (empty .Values.imageCatalog.images )) }} +apiVersion: postgresql.cnpg.io/v1 +kind: ImageCatalog +metadata: + name: {{ include "cluster.fullname" . }} +spec: + images: + {{- range $image := .Values.imageCatalog.images }} + - image: {{ $image.image }} + major: {{ $image.major }} + {{- end }} +{{- end }} diff --git a/charts/cluster/values.schema.json b/charts/cluster/values.schema.json index 38ca30a04..9d773a473 100644 --- a/charts/cluster/values.schema.json +++ b/charts/cluster/values.schema.json @@ -187,6 +187,9 @@ "enableSuperuserAccess": { "type": "boolean" }, + "imageCatalogRef": { + "type": "object" + }, "imageName": { "type": "string" }, @@ -300,6 +303,17 @@ "fullnameOverride": { "type": "string" }, + "imageCatalog": { + "type": "object", + "properties": { + "create": { + "type": "boolean" + }, + "images": { + "type": "array" + } + } + }, "mode": { "type": "string" }, @@ -564,6 +578,20 @@ }, "type": { "type": "string" + }, + "version": { + "type": "object", + "properties": { + "postgis": { + "type": "string" + }, + "postgresql": { + "type": "string" + }, + "timescaledb": { + "type": "string" + } + } } } } diff --git a/charts/cluster/values.yaml b/charts/cluster/values.yaml index d8bb3b22d..e9e31d784 100644 --- a/charts/cluster/values.yaml +++ b/charts/cluster/values.yaml @@ -7,8 +7,17 @@ fullnameOverride: "" # -- 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. @@ -123,6 +132,11 @@ cluster: # :@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 @@ -141,10 +155,10 @@ cluster: storageClass: "" # -- The UID of the postgres user inside the image, defaults to 26 - postgresUID: 26 + postgresUID: -1 # -- The GID of the postgres user inside the image, defaults to 26 - postgresGID: 26 + postgresGID: -1 # -- Resources requirements of every generated Pod. # Please refer to https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ for more information. @@ -328,6 +342,13 @@ backups: # -- 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 pooler: # -- Whether to enable PgBouncer