feat(charts):完成第一版helm charts

This commit is contained in:
Yu Sun
2022-10-03 19:40:37 +08:00
parent 8b878b603a
commit fbe6bda621
14 changed files with 925 additions and 0 deletions

1
charts/.helmignore Normal file
View File

@@ -0,0 +1 @@
*.png

21
charts/Chart.yaml Normal file
View File

@@ -0,0 +1,21 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
apiVersion: v1
name: timescaledb-multinode
description: 'TimescaleDB Multinode Deployment.'
version: 0.8.0
# appVersion specifies the version of the software, which can vary wildly,
# e.g. TimescaleDB 1.4.1 on PostgreSQL 11 or TimescaleDB 1.5.0 on PostgreSQL 12.
# https://github.com/helm/helm/blob/master/docs/charts.md#the-appversion-field
# To avoid confusion, we will not expose appVersion
# appVersion: 0.0.1
home: https://github.com/timescale/helm-charts
sources:
- https://github.com/timescale/helm-charts
- https://github.com/timescale/timescaledb-docker-ha
- https://github.com/zalando/patroni
# The chart is deprecated. We are looking for maintainers to remove this field.
# More in https://github.com/timescale/helm-charts/blob/main/charts/timescaledb-multinode/README.md#call-for-maintainers
deprecated: false

134
charts/admin-guide.md Normal file
View File

@@ -0,0 +1,134 @@
<!---
This file and its contents are licensed under the Apache License 2.0.
Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
-->
# TimescaleDB Single Administrator Guide
##### Table of Contents
- [Configuration](#configuration)
- [Backups](#backups)
- [Cleanup](#cleanup)
- [Troubleshooting](#troubleshooting)
## Configuration
The following table lists the configurable parameters of the TimescaleDB Helm chart and their default values.
| Parameter | Description | Default |
|-----------------------------------|---------------------------------------------|-----------------------------------------------------|
| `nameOverride` | Override the name of the chart | `timescaledb` |
| `fullnameOverride` | Override the fullname of the chart | `nil` |
| `replicaCount` | Amount of pods to spawn | `3` |
| `image.repository` | The image to pull | `timescale/timescaledb-ha` |
| `image.tag` | The version of the image to pull | `pg12.5-ts2.0.0-p0`
| `image.pullPolicy` | The pull policy | `IfNotPresent` |
| `credentials.accessNode.superuser`| Password of the superuser for the Access Node | `tea` |
| `credentials.dataNode.superuser` | Password of the superuser for the Data Nodes | `coffee` |
| `env` | Extra custom environment variables, expressed as [EnvVar](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#envvarsource-v1-core) | `PGDATA` and some language settings |
| `resources` | Any resources you wish to assign to the pod | `{}` |
| `nodeSelector` | Node label to use for scheduling | `{}` |
| `tolerations` | List of node taints to tolerate | `[]` |
| `affinityTemplate` | A template string to use to generate the affinity settings | Anti-affinity preferred on hostname |
| `affinity` | Affinity settings. Overrides `affinityTemplate` if set. | `{}` |
| `postgresql.databases` | List of databases to automatically create a multinode setup for | `["postgres", "example"]` |
| `postgresql.parameters` | [PostgreSQL parameters](https://www.postgresql.org/docs/current/config-setting.html#CONFIG-SETTING-CONFIGURATION-FILE)) | Some required and preferred settings |
| `schedulerName` | Alternate scheduler name | `nil` |
| `persistentVolume.accessModes` | Persistent Volume access modes | `[ReadWriteOnce]` |
| `persistentVolume.annotations` | Annotations for Persistent Volume Claim` | `{}` |
| `persistentVolume.mountPath` | Persistent Volume mount root path | `/var/lib/postgresql` |
| `persistentVolume.size` | Persistent Volume size | `5Gi` |
| `persistentVolume.storageClass` | Persistent Volume Storage Class | `volume.alpha.kubernetes.io/storage-class: default` |
| `persistentVolume.subPath` | Subdirectory of Persistent Volume to mount | `""` |
| `rbac.create` | Create required role and rolebindings | `true` |
| `serviceAccount.create` | If true, create a new service account | `true` |
| `serviceAccount.name` | Service account to be used. If not set and `serviceAccount.create` is `true`, a name is generated using the fullname template | `nil` |
### Examples
- Override value using commandline parameters
```console
helm upgrade --install my-release . --set image.tag=pg12.5-ts2.0.0-p0 --set image.pullPolicy=Always
```
- Override values using `myvalues.yaml`
```yaml
# Filename: myvalues.yaml
image:
tag: pg12.5-ts2.0.0-p0
pullPolicy: Always
postgresql:
databases:
- postgres
- proddb
parameters:
checkpoint_completion_target: 32MB
work_mem: 16MB
shared_buffers: 512MB
```
```console
helm upgrade --install my-release . -f myvalues.yaml
```
## Cleanup
Removing a deployment can be done by deleting a Helm deployment, however, removing the deployment does not remove:
- the Persistent Volume Claims (pvc) belonging to the cluster
To fully purge a deployment in Kubernetes, you should do the following:
```console
# Delete the Helm deployment
helm delete my-release
# Delete pvc and the headless Patroni service
kubectl delete $(kubectl get pvc -l release=my-release -o name)
```
## Troubleshooting
### List Resources
All the resources that are deployed can be listed by providing the filter `-l release=my-release`.
```console
kubectl get all -l release=my-release
```
The output should be similar to the below output:
```console
NAME READY STATUS RESTARTS AGE
pod/my-release-timescaledb-access-0 1/1 Running 0 11m
pod/my-release-timescaledb-data-0 1/1 Running 0 11m
pod/my-release-timescaledb-data-1 1/1 Running 0 11m
pod/my-release-timescaledb-data-2 1/1 Running 0 11m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/my-release-timescaledb LoadBalancer 10.152.183.60 <pending> 5432:31819/TCP 11m
service/my-release-timescaledb-data ClusterIP None <none> 5432/TCP 11m
NAME READY AGE
statefulset.apps/my-release-timescaledb-access 1/1 11m
statefulset.apps/my-release-timescaledb-data 3/3 11m
```
> **INFO** When listing resources within minutes of deploying a new Helm chart, you may see a list of jobs and its pods;
these jobs are there to create the database, and to attach the data nodes to the access node. There will be quite a few,
but these should disappear within minutes after successful deployment.
### Investigate TimescaleDB logs
The logs for the Access Node of TimescaleDB can be accessed as follows:
```console
kubectl logs $(kubectl get pod -l release=my-release,timescaleNodeType=access) timescaledb
```
### Verify multinode topology
```console
$ kubectl exec -ti $(kubectl get pod -l timescaleNodeType=access -o name) -c timescaledb -- psql -d example -c 'select node_name from timescaledb_information.data_nodes'
```
```text
node_name
-------------------------------
my-release-timescaledb-data-0
my-release-timescaledb-data-1
my-release-timescaledb-data-2
(3 rows)
```

View File

@@ -0,0 +1,28 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
TimescaleDB can be accessed via port 5432 on the following DNS name from within your cluster:
{{ template "timescaledb.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local
To get your password for superuser run:
# superuser password
PGPASSWORD_SUPERUSER=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "timescaledb.fullname" . }} -o jsonpath="{.data.password-superuser}" | base64 --decode)
# admin password
PGPASSWORD_ADMIN=$(kubectl get secret --namespace {{ .Release.Namespace }} {{ template "timescaledb.fullname" . }} -o jsonpath="{.data.password-admin}" | base64 --decode)
To connect to your database:
1. Run a postgres pod and connect using the psql cli:
# login as superuser
kubectl run -i --tty --rm psql --image=postgres \
--env "PGPASSWORD=$PGPASSWORD_SUPERUSER" \
--command -- psql -U postgres \
-h {{ template "timescaledb.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local postgres
# login as admin
kubectl run -i -tty --rm psql --image=postgres \
--env "PGPASSWORD=$PGPASSWORD_ADMIN" \
--command -- psql -U admin \
-h {{ template "timescaledb.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local postgres

View File

@@ -0,0 +1,60 @@
{{/*
This file and its contents are licensed under the Apache License 2.0.
Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
*/}}
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "timescaledb.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 "timescaledb.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 -}}
{{- define "timescaledb.dataname" -}}
{{ template "timescaledb.fullname" . }}-data
{{- end -}}
{{- define "timescaledb.accessname" -}}
{{ template "timescaledb.fullname" . }}-access
{{- end -}}
{{- define "postgres.uid" -}}
{{- default .Values.uid "1000" -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "timescaledb.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create the name of the service account to use.
*/}}
{{- define "timescaledb.serviceAccountName" -}}
{{- if .Values.serviceAccount.create -}}
{{ default (include "timescaledb.fullname" .) .Values.serviceAccount.name }}
{{- else -}}
{{ default "default" .Values.serviceAccount.name }}
{{- end -}}
{{- end -}}

View File

@@ -0,0 +1,77 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
{{- range $pod, $e := until ( .Values.dataNodes | int) }}
{{- range $index, $dbname := $.Values.postgresql.databases }}
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ printf "attachdn-%s-db%s-data%s" $.Release.Name ($index | toString) ($pod | toString) | trunc 63 }}
labels:
app: {{ template "timescaledb.fullname" $ }}
chart: {{ template "timescaledb.chart" $ }}
release: {{ $.Release.Name }}
heritage: {{ $.Release.Service }}
annotations:
"helm.sh/hook-delete-policy": hook-succeeded
spec:
ttlSecondsAfterFinished: 600
template:
metadata:
labels:
app: {{ template "timescaledb.fullname" $ }}
chart: {{ template "timescaledb.chart" $ }}
release: {{ $.Release.Name }}
heritage: {{ $.Release.Service }}
dataNode: {{ template "timescaledb.dataname" $ }}-{{ $pod }}
spec:
containers:
- name: attachdn-{{ $index }}
image: postgres:14.5-alpine # A relatively small official image that can run psql
command:
- sh
- -c
# We wait for the data node to allow connections
# We wait for the access node to allow connections to DBNAME
- >
while ! pg_isready -U postgres -h "${DATA_NODE_DNS}"; do sleep 1; done;
while ! psql -d "${ACCESS_SVC_CONNSTR}" --set dbname="${DBNAME}" --set ON_ERROR_STOP=1 --command '\c :"dbname"'; do sleep 1; done;
echo "${SQLCOMMAND}" | psql -d "${ACCESS_SVC_CONNSTR}" --file=- --echo-queries --set ON_ERROR_STOP=1 \
--set dbname="${DBNAME}" \
--set data_node_name="${DATA_NODE_NAME}" \
--set data_node_dns="${DATA_NODE_DNS}"
env:
{{- /*
Some parameter juggling is required to ensure we don't have SQL injection;
which is not necessarily a major security leak at this stage, but we want
to be able to support database names like 'test db' or, 'CamelCase'.
The template quote function ensures bash will be able to interpret the variable.
The --set dbname= and subsequent :'dbname' psql_variable ensures no SQL injection can occur.
https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-INTERPOLATION
*/}}
- name: DBNAME
value: {{ $dbname | quote }}
- name: ACCESS_SVC_CONNSTR
value: host={{ template "timescaledb.fullname" $ }} user=postgres connect_timeout=3 sslmode=disable
- name: DATA_NODE_DNS
value: {{ template "timescaledb.dataname" $ }}-{{ $pod }}.{{ template "timescaledb.dataname" $ }}
- name: DATA_NODE_NAME
value: {{ template "timescaledb.dataname" $ }}-{{ $pod }}
- name: SQLCOMMAND
value: |
\c :"dbname"
SELECT *
FROM add_data_node(:'data_node_name'::name, host => :'data_node_dns', if_not_exists => true)
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: {{ template "timescaledb.accessname" $ }}
key: password-superuser
restartPolicy: OnFailure
backoffLimit: 2
...
{{ end }}
{{ end }}

View File

@@ -0,0 +1,72 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
{{- range $index, $dbname := .Values.postgresql.databases }}
---
apiVersion: batch/v1
kind: Job
metadata:
name: {{ printf "createdb-%s-db%s" $.Release.Name ($index | toString) | trunc 63 }}
labels:
app: {{ template "timescaledb.fullname" $ }}
chart: {{ template "timescaledb.chart" $ }}
release: {{ $.Release.Name }}
heritage: {{ $.Release.Service }}
annotations:
"helm.sh/hook-delete-policy": hook-succeeded
spec:
ttlSecondsAfterFinished: 600
template:
metadata:
labels:
app: {{ template "timescaledb.fullname" $ }}
chart: {{ template "timescaledb.chart" $ }}
release: {{ $.Release.Name }}
heritage: {{ $.Release.Service }}
spec:
containers:
- name: createdb-{{ $index }}
image: postgres:14.5-alpine # A relatively small official image that can run psql
command:
- sh
- -c
- >
while ! pg_isready -U postgres -h {{ template "timescaledb.fullname" $ }}; do sleep 1; done;
echo "${SQLCOMMAND}" | psql --file=- --echo-queries -d "${ACCESS_SVC_CONNSTR}" \
--set ON_ERROR_STOP=1 \
--set dbname="${DBNAME}"
env:
{{- /*
Some parameter juggling is required to ensure we don't have SQL injection;
which is not necessarily a major security leak at this stage, but we want
to be able to support database names like 'test db' or, 'CamelCase'.
The template quote function ensures bash will be able to interpret the variable.
The --set dbname= and subsequent :'dbname' psql_variable ensures no SQL injection can occur.
https://www.postgresql.org/docs/current/app-psql.html#APP-PSQL-INTERPOLATION
*/}}
- name: DBNAME
value: {{ $dbname | quote }}
- name: ACCESS_SVC_CONNSTR
value: host={{ template "timescaledb.fullname" $ }} user=postgres connect_timeout=3 sslmode=disable
- name: SQLCOMMAND
value: |
SELECT format('CREATE DATABASE %I', :'dbname')
WHERE NOT EXISTS (
SELECT
FROM pg_database
WHERE datname=:'dbname'
)
\gexec
\c :"dbname"
CREATE EXTENSION IF NOT EXISTS timescaledb;
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: {{ template "timescaledb.accessname" $ }}
key: password-superuser
restartPolicy: OnFailure
backoffLimit: 2
...
{{ end }}

View File

@@ -0,0 +1,31 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
---
apiVersion: v1
kind: Secret
metadata:
name: {{ template "timescaledb.accessname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
type: Opaque
data:
password-superuser: {{ .Values.credentials.accessNode.superuser | b64enc }}
...
---
apiVersion: v1
kind: Secret
metadata:
name: {{ template "timescaledb.dataname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
type: Opaque
data:
password-superuser: {{ .Values.credentials.dataNode.superuser | b64enc }}
...

View File

@@ -0,0 +1,14 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
{{- if .Values.serviceAccount.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ template "timescaledb.serviceAccountName" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
{{- end }}

View File

@@ -0,0 +1,166 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ template "timescaledb.accessname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
serviceName: {{ template "timescaledb.accessname" . }}
replicas: 1
podManagementPolicy: Parallel
selector:
matchLabels:
app: {{ template "timescaledb.fullname" . }}
release: {{ .Release.Name }}
timescaleNodeType: access
template:
metadata:
name: {{ template "timescaledb.accessname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
release: {{ .Release.Name }}
timescaleNodeType: access
spec:
serviceAccountName: {{ template "timescaledb.serviceAccountName" . }}
securityContext:
# The postgres user inside the TimescaleDB image has uid=1000.
# This configuration ensures the permissions of the mounts are suitable
fsGroup: {{ template "postgres.uid" }}
runAsGroup: {{ template "postgres.uid" }}
runAsNonRoot: true
runAsUser: {{ template "postgres.uid" }}
initContainers:
- name: initdb
securityContext:
allowPrivilegeEscalation: false
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: POSTGRESQL_CUSTOM_PARAMETERS
value: |
{{- range $key, $value := .Values.postgresql.parameters }}
{{ printf "%s = '%s'" $key ($value | toString) }}
{{- end }}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "timescaledb.accessname" . }}
key: password-superuser
- name: POSTGRES_PASSWORD_DATA_NODE
valueFrom:
secretKeyRef:
name: {{ template "timescaledb.dataname" . }}
key: password-superuser
{{- if .Values.env }}
{{ .Values.env | default list | toYaml | indent 8 }}
{{- end }}
command:
- sh
- '-c'
# By calling the original entrypoint with the first argument being postgres
# we ensure we do everything that is required to init a PostgreSQL instance.
# By supplying --single however, we ensure the postmaster is running in the
# foreground, allowing us to do some more initialization
- |
set -e
install -o postgres -g postgres -m 0700 -d "${PGDATA}"
/docker-entrypoint.sh postgres --single < /dev/null
grep -qxF "include 'postgresql_helm_customizations.conf'" "${PGDATA}/postgresql.conf" \
|| echo "include 'postgresql_helm_customizations.conf'" >> "${PGDATA}/postgresql.conf"
echo "Writing custom PostgreSQL Parameters to ${PGDATA}/postgresql_helm_customizations.conf"
echo "cluster_name = '$(hostname)'" > "${PGDATA}/postgresql_helm_customizations.conf"
echo "${POSTGRESQL_CUSTOM_PARAMETERS}" | sort >> "${PGDATA}/postgresql_helm_customizations.conf"
echo "*:*:*:postgres:${POSTGRES_PASSWORD_DATA_NODE}" > "${PGDATA}/../.pgpass"
chown postgres:postgres "${PGDATA}/../.pgpass" "${PGDATA}/postgresql_helm_customizations.conf"
chmod 0600 "${PGDATA}/../.pgpass"
echo "Adding host all all all md5 in pg_hba.conf"
grep -qxF "host all all all md5" "${PGDATA}/pg_hba.conf" \
|| echo "host all all all md5" >> ${PGDATA}/pg_hba.conf
volumeMounts:
- name: storage-volume
mountPath: "{{ .Values.persistentVolume.mountPath }}"
subPath: "{{ .Values.persistentVolume.subPath }}"
containers:
- name: timescaledb
securityContext:
allowPrivilegeEscalation: false
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
# We start postgres with a fully cleared environment
command:
- sh
- '-c'
- exec env -i PGDATA="${PGDATA}" PATH="${PATH}" /docker-entrypoint.sh postgres
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
{{- if .Values.env }}
{{ .Values.env | default list | toYaml | indent 8 }}
{{- end }}
ports:
- containerPort: 5432
volumeMounts:
- name: storage-volume
mountPath: "{{ .Values.persistentVolume.mountPath }}"
subPath: "{{ .Values.persistentVolume.subPath }}"
resources:
{{ toYaml .Values.resources | indent 10 }}
# {{- with .Values.nodeSelector }}
# nodeSelector:
nodeSelector:
kubernetes.io/hostname: an
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
{{- if .Values.schedulerName }}
schedulerName: {{ .Values.schedulerName }}
{{- end }}
{{- if .Values.affinity }}
affinity:
{{ .Values.affinity | toYaml | indent 8 }}
{{- else if .Values.affinityTemplate }}
affinity:
{{ tpl .Values.affinityTemplate . | indent 8 }}
{{- end }}
{{- if not .Values.persistentVolume.enabled }}
- name: storage-volume
emptyDir: {}
{{- end }}
{{- if .Values.persistentVolume.enabled }}
volumeClaimTemplates:
- metadata:
name: storage-volume
annotations:
{{- if .Values.persistentVolume.annotations }}
{{ toYaml .Values.persistentVolume.annotations | indent 8 }}
{{- end }}
labels:
app: {{ template "timescaledb.fullname" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
accessModes:
{{ toYaml .Values.persistentVolume.accessModes | indent 8 }}
resources:
requests:
storage: "{{ .Values.persistentVolume.size }}"
{{- if .Values.persistentVolume.storageClass }}
{{- if (eq "-" .Values.persistentVolume.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistentVolume.storageClass }}"
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,159 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: {{ template "timescaledb.dataname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
serviceName: {{ template "timescaledb.dataname" . }}
replicas: {{ .Values.dataNodes }}
podManagementPolicy: Parallel
selector:
matchLabels:
app: {{ template "timescaledb.fullname" . }}
release: {{ .Release.Name }}
timescaleNodeType: data
template:
metadata:
name: {{ template "timescaledb.dataname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
release: {{ .Release.Name }}
timescaleNodeType: data
spec:
serviceAccountName: {{ template "timescaledb.serviceAccountName" . }}
securityContext:
# The postgres user inside the TimescaleDB image has uid=1000.
# This configuration ensures the permissions of the mounts are suitable
fsGroup: {{ template "postgres.uid" }}
runAsGroup: {{ template "postgres.uid" }}
runAsNonRoot: true
runAsUser: {{ template "postgres.uid" }}
initContainers:
- name: initdb
securityContext:
allowPrivilegeEscalation: false
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
env:
- name: POSTGRESQL_CUSTOM_PARAMETERS
value: |
{{- range $key, $value := .Values.postgresql.parameters }}
{{ printf "%s = '%s'" $key ($value | toString) }}
{{- end }}
- name: POSTGRES_PASSWORD
valueFrom:
secretKeyRef:
name: {{ template "timescaledb.dataname" . }}
key: password-superuser
{{- if .Values.env }}
{{ .Values.env | default list | toYaml | indent 8 }}
{{- end }}
command:
- sh
- '-c'
# By calling the original entrypoint with the first argument being postgres
# we ensure we do everything that is required to init a PostgreSQL instance.
# By supplying --single however, we ensure the postmaster is running in the
# foreground, allowing us to do some more initialization
- |
set -e
install -o postgres -g postgres -m 0700 -d "${PGDATA}" "${PGDATA}/../conf.d"
/docker-entrypoint.sh postgres --single < /dev/null
grep -qxF "include 'postgresql_helm_customizations.conf'" "${PGDATA}/postgresql.conf" \
|| echo "include 'postgresql_helm_customizations.conf'" >> "${PGDATA}/postgresql.conf"
echo "Writing custom PostgreSQL Parameters to ${PGDATA}/postgresql_helm_customizations.conf"
echo "cluster_name = '$(hostname)'" > "${PGDATA}/postgresql_helm_customizations.conf"
echo "${POSTGRESQL_CUSTOM_PARAMETERS}" | sort >> "${PGDATA}/postgresql_helm_customizations.conf"
echo "Adding host all all all md5 in pg_hba.conf"
grep -qxF "host all all all md5" "${PGDATA}/pg_hba.conf" \
|| echo "host all all all md5" >> ${PGDATA}/pg_hba.conf
# The TimescaleDB extension should not be available by default, as this interferes with the bootstrapping
# done by the access nodes. Therefore we drop the extensions from template1
echo "DROP EXTENSION timescaledb" | /docker-entrypoint.sh postgres --single -D "${PGDATA}" template1
volumeMounts:
- name: storage-volume
mountPath: "{{ .Values.persistentVolume.mountPath }}"
subPath: "{{ .Values.persistentVolume.subPath }}"
containers:
- name: timescaledb
securityContext:
allowPrivilegeEscalation: false
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
# We start postgres with a fully cleared environment
command:
- sh
- '-c'
- exec env -i PGDATA="${PGDATA}" PATH="${PATH}" /docker-entrypoint.sh postgres
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
{{- if .Values.env }}
{{ .Values.env | default list | toYaml | indent 8 }}
{{- end }}
ports:
- containerPort: 5432
volumeMounts:
- name: storage-volume
mountPath: "{{ .Values.persistentVolume.mountPath }}"
subPath: "{{ .Values.persistentVolume.subPath }}"
resources:
{{ toYaml .Values.resources | indent 10 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
{{- if .Values.schedulerName }}
schedulerName: {{ .Values.schedulerName }}
{{- end }}
{{- if .Values.affinity }}
affinity:
{{ .Values.affinity | toYaml | indent 8 }}
{{- else if .Values.affinityTemplate }}
affinity:
{{ tpl .Values.affinityTemplate . | indent 8 }}
{{- end }}
{{- if not .Values.persistentVolume.enabled }}
- name: storage-volume
emptyDir: {}
{{- end }}
{{- if .Values.persistentVolume.enabled }}
volumeClaimTemplates:
- metadata:
name: storage-volume
annotations:
{{- if .Values.persistentVolume.annotations }}
{{ toYaml .Values.persistentVolume.annotations | indent 8 }}
{{- end }}
labels:
app: {{ template "timescaledb.fullname" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
accessModes:
{{ toYaml .Values.persistentVolume.accessModes | indent 8 }}
resources:
requests:
storage: "{{ .Values.persistentVolume.size }}"
{{- if .Values.persistentVolume.storageClass }}
{{- if (eq "-" .Values.persistentVolume.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistentVolume.storageClass }}"
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,25 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
---
apiVersion: v1
kind: Service
metadata:
name: {{ template "timescaledb.fullname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
annotations:
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "4000"
spec:
type: LoadBalancer
ports:
- name: postgresql
port: 5432
protocol: TCP
selector:
app: {{ template "timescaledb.fullname" . }}
timescaleNodeType: access
...

View File

@@ -0,0 +1,23 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
---
apiVersion: v1
kind: Service
metadata:
name: {{ template "timescaledb.dataname" . }}
labels:
app: {{ template "timescaledb.fullname" . }}
chart: {{ template "timescaledb.chart" . }}
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
clusterIP: None
ports:
- name: postgresql
port: 5432
protocol: TCP
selector:
app: {{ template "timescaledb.fullname" . }}
timescaleNodeType: data
...

114
charts/values.yaml Normal file
View File

@@ -0,0 +1,114 @@
# This file and its contents are licensed under the Apache License 2.0.
# Please see the included NOTICE for copyright information and LICENSE for a copy of the license.
dataNodes: 3
# To prevent very long names, we override the name, otherwise it would default to
# timescaledb-multinode (the name of the chart)
nameOverride: timescaledb
image:
# Image was built from
# https://github.com/timescale/timescaledb-docker-ha
repository: timescale/timescaledb-ha
tag: pg14.5-ts2.8.0-patroni-static-primary-latest
pullPolicy: IfNotPresent
# Credentials used by PostgreSQL
credentials:
accessNode:
superuser: big_dick
dataNode:
superuser: big_dick
# Extra custom environment variables.
# These should be an EnvVar, as this allows you to inject secrets into the environment
# https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.16/#envvar-v1-core
env:
- name: LC_ALL
value: C.UTF-8
- name: LANG
value: C.UTF-8
- name: PGDATA
# This should be a subdirectory of the persistentVolume (if any), as PostgreSQL will need to
# fully manage permissions. Also, using /var/lib/postgresql/data is discouraged, as this is
# a Docker Volume in many Docker images, which means the data is not actually persisted.
value: /var/lib/postgresql/pgdata
persistentVolume:
enabled: true
size: 100G
## database data Persistent Volume Storage Class
## If defined, storageClassName: <storageClass>
## If set to "-", storageClassName: "", which disables dynamic provisioning
## If undefined (the default) or set to null, no storageClassName spec is
## set, choosing the default provisioner. (gp2 on AWS, standard on
## GKE, AWS & OpenStack)
##
# storageClass: "-"
subPath: ""
mountPath: "/var/lib/postgresql"
annotations: {}
accessModes:
- ReadWriteOnce
resources: {}
postgresql:
databases:
- postgres
- example
parameters:
max_connections: 100
max_prepared_transactions: 150
# This is rather small, but as this Helm Chart may be used to spin up
# 1 access node and 4 data nodes on a single minikube/microk8s this is set
# to a conservative value
shared_buffers: 300MB
work_mem: 16MB
log_connections: 'on'
log_line_prefix: "%t [%p]: [%c-%l] %u@%d,app=%a [%e] "
log_min_duration_statement: '1s'
log_statement: ddl
log_checkpoints: 'on'
log_lock_waits: 'on'
# These values are set as the default data volume size
# is small as well.
min_wal_size: 256MB
max_wal_size: 512MB
temp_file_limit: 1GB
# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#nodeselector
nodeSelector: {}
# https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
tolerations: []
# https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
affinityTemplate: |
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
topologyKey: "kubernetes.io/hostname"
labelSelector:
matchLabels:
app: {{ template "timescaledb.name" . }}
release: {{ .Release.Name | quote }}
affinity: {}
## Use an alternate scheduler, e.g. "stork".
## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
##
# schedulerName:
rbac:
# Specifies whether RBAC resources should be created
create: true
serviceAccount:
# Specifies whether a ServiceAccount should be created
create: true
# The name of the ServiceAccount to use.
# If not set and create is true, a name is generated using the fullname template
name: