diff --git a/charts/clickhouse/.helmignore b/charts/clickhouse/.helmignore
new file mode 100644
index 000000000..bc120b4b8
--- /dev/null
+++ b/charts/clickhouse/.helmignore
@@ -0,0 +1,2 @@
+artifacthub-repo.yaml
+tests/
diff --git a/charts/clickhouse/CHANGELOG.md b/charts/clickhouse/CHANGELOG.md
new file mode 100644
index 000000000..bee3e08ee
--- /dev/null
+++ b/charts/clickhouse/CHANGELOG.md
@@ -0,0 +1,21 @@
+# Changelog
+
+## [0.1.0]
+
+### Added
+
+- Initial release of the standalone ClickHouse Helm chart
+- StatefulSet deployment using official `clickhouse/clickhouse-server` image
+- Configurable `config.xml` and `users.xml` via ConfigMaps
+- Persistent storage via PVC with configurable size and storage class
+- HTTP (8123) and TCP/native (9000) service ports
+- Headless service for StatefulSet DNS
+- Optional Prometheus metrics sidecar with ServiceMonitor support
+- Optional Ingress and Gateway API HTTPRoute resources
+- Optional ServiceAccount creation
+- Liveness, readiness, and startup probes via ClickHouse `/ping` endpoint
+- Support for init SQL scripts via ConfigMap
+- `extraObjects`, `extraEnvVars`, `extraVolumes`, `extraVolumeMounts` escape hatches
+- Auto-generated credentials secret with connection URI
+- Pod and container security context defaults
+- `persistentVolumeClaimRetentionPolicy` support
diff --git a/charts/clickhouse/Chart.lock b/charts/clickhouse/Chart.lock
new file mode 100644
index 000000000..a48d5ffa9
--- /dev/null
+++ b/charts/clickhouse/Chart.lock
@@ -0,0 +1,6 @@
+dependencies:
+- name: common
+ repository: oci://registry-1.docker.io/cloudpirates
+ version: 2.2.0
+digest: sha256:a2168dfa04b6fbeb8ab278d891670dd5d27c51366c36853e156f07479720cefe
+generated: "2026-03-30T07:55:43.090874+02:00"
diff --git a/charts/clickhouse/Chart.yaml b/charts/clickhouse/Chart.yaml
new file mode 100644
index 000000000..3912227b7
--- /dev/null
+++ b/charts/clickhouse/Chart.yaml
@@ -0,0 +1,49 @@
+apiVersion: v2
+name: clickhouse
+description: The Open-Source, High Performance Columnar OLAP Database Management System
+type: application
+version: 0.1.0
+appVersion: "25.3.14.14"
+keywords:
+ - clickhouse
+ - database
+ - olap
+ - analytics
+ - columnar
+home: https://clickhouse.com
+sources:
+ - https://github.com/CloudPirates-io/helm-charts/tree/main/charts/clickhouse
+ - https://github.com/ClickHouse/ClickHouse
+maintainers:
+ - name: CloudPirates GmbH & Co. KG
+ email: hello@cloudpirates.io
+ url: https://www.cloudpirates.io
+dependencies:
+ - name: common
+ version: "2.2.x"
+ repository: oci://registry-1.docker.io/cloudpirates
+icon: https://a.storyblok.com/f/143071/512x512/7be3e97a51/clickhouse-logo.svg
+annotations:
+ license: Apache-2.0
+ artifacthub.io/category: database
+ artifacthub.io/containsSecurityUpdates: "false"
+ artifacthub.io/signKey: |
+ fingerprint: 6917f1a88c122cbb1de5aa55457752135bdcf95a
+ url: https://raw.githubusercontent.com/CloudPirates-io/helm-charts/refs/heads/main/cosign.pub
+ artifacthub.io/links: |
+ - name: ClickHouse
+ url: https://clickhouse.com
+ - name: Helm Chart
+ url: https://github.com/CloudPirates-io/helm-charts/tree/main/charts/clickhouse
+ - name: Application
+ url: https://github.com/ClickHouse/ClickHouse
+ - name: Docker Image
+ url: https://hub.docker.com/r/clickhouse/clickhouse-server
+ - name: Maintainer CloudPirates
+ url: https://www.cloudpirates.io
+ artifacthub.io/changes: |-
+ - kind: added
+ description: "Initial release of the ClickHouse chart"
+ links:
+ - name: "Changelog"
+ url: "https://github.com/CloudPirates-io/helm-charts/blob/main/charts/clickhouse/CHANGELOG.md"
diff --git a/charts/clickhouse/artifacthub-repo.yml b/charts/clickhouse/artifacthub-repo.yml
new file mode 100644
index 000000000..66e588618
--- /dev/null
+++ b/charts/clickhouse/artifacthub-repo.yml
@@ -0,0 +1 @@
+repositoryID: XXXXXXXX
diff --git a/charts/clickhouse/templates/_helpers.tpl b/charts/clickhouse/templates/_helpers.tpl
new file mode 100644
index 000000000..d12dbe2dc
--- /dev/null
+++ b/charts/clickhouse/templates/_helpers.tpl
@@ -0,0 +1,125 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "clickhouse.name" -}}
+{{- include "cloudpirates.name" . -}}
+{{- 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 "clickhouse.fullname" -}}
+{{- include "cloudpirates.fullname" . -}}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "clickhouse.chart" -}}
+{{- include "cloudpirates.chart" . -}}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "clickhouse.labels" -}}
+{{- include "cloudpirates.labels" . -}}
+{{- end }}
+
+{{/*
+Common annotations
+*/}}
+{{- define "clickhouse.annotations" -}}
+{{- with .Values.commonAnnotations }}
+{{- toYaml . }}
+{{- end }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "clickhouse.selectorLabels" -}}
+{{- include "cloudpirates.selectorLabels" . -}}
+{{- end }}
+
+{{/*
+Return the proper ClickHouse image name
+*/}}
+{{- define "clickhouse.image" -}}
+{{- include "cloudpirates.image" (dict "image" .Values.image "global" .Values.global) -}}
+{{- end }}
+
+{{/*
+Return ClickHouse credentials secret name
+*/}}
+{{- define "clickhouse.secretName" -}}
+{{- if .Values.auth.existingSecret -}}
+ {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.existingSecret "context" .) -}}
+{{- else -}}
+ {{- include "clickhouse.fullname" . -}}
+{{- end -}}
+{{- end }}
+
+{{/*
+Return ClickHouse admin password key
+*/}}
+{{- define "clickhouse.passwordKey" -}}
+{{- if .Values.auth.existingSecret -}}
+ {{- include "cloudpirates.tplvalues.render" (dict "value" .Values.auth.secretKeys.passwordKey "context" .) | default "clickhouse-password" -}}
+{{- else -}}
+clickhouse-password
+{{- end -}}
+{{- end }}
+
+{{/*
+Return ClickHouse configuration ConfigMap name
+*/}}
+{{- define "clickhouse.configmapName" -}}
+{{- if .Values.config.existingConfigmap -}}
+ {{- .Values.config.existingConfigmap -}}
+{{- else -}}
+ {{- printf "%s-config" (include "clickhouse.fullname" .) -}}
+{{- end -}}
+{{- end }}
+
+{{/*
+Return ClickHouse users configuration ConfigMap name
+*/}}
+{{- define "clickhouse.usersConfigmapName" -}}
+{{- if .Values.config.existingUsersConfigmap -}}
+ {{- .Values.config.existingUsersConfigmap -}}
+{{- else -}}
+ {{- printf "%s-users" (include "clickhouse.fullname" .) -}}
+{{- end -}}
+{{- end }}
+
+{{/*
+Return ClickHouse init scripts ConfigMap name
+*/}}
+{{- define "clickhouse.initdb.scriptsCM" -}}
+{{- if .Values.initdb.scriptsConfigMap -}}
+ {{- printf "%s" (tpl .Values.initdb.scriptsConfigMap $) -}}
+{{- else -}}
+ {{- printf "%s-init-scripts" (include "clickhouse.fullname" .) -}}
+{{- end -}}
+{{- end -}}
+
+{{/*
+Return the proper Docker Image Registry Secret Names
+*/}}
+{{- define "clickhouse.imagePullSecrets" -}}
+{{ include "cloudpirates.images.renderPullSecrets" (dict "images" (list .Values.image) "context" .) }}
+{{- end -}}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "clickhouse.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "clickhouse.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/charts/clickhouse/templates/configmap.yaml b/charts/clickhouse/templates/configmap.yaml
new file mode 100644
index 000000000..7880d422f
--- /dev/null
+++ b/charts/clickhouse/templates/configmap.yaml
@@ -0,0 +1,71 @@
+{{- if not .Values.config.existingConfigmap }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ include "clickhouse.configmapName" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- if .Values.commonAnnotations }}
+ annotations:
+ {{- include "clickhouse.annotations" . | nindent 4 }}
+ {{- end }}
+data:
+ kubernetes.xml: |
+
+
+ {{ .Values.config.listenHost }}
+ {{ .Values.service.httpPort }}
+ {{ .Values.service.tcpPort }}
+ {{ .Values.config.maxConnections }}
+ {{ .Values.config.maxConcurrentQueries }}
+ {{ .Values.config.timezone }}
+
+ {{ .Values.config.logLevel }}
+ 1
+
+ {{- if .Values.config.extraConfig }}
+ {{ .Values.config.extraConfig | nindent 6 }}
+ {{- end }}
+
+{{- end }}
+---
+{{- if not .Values.config.existingUsersConfigmap }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ include "clickhouse.usersConfigmapName" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- if .Values.commonAnnotations }}
+ annotations:
+ {{- include "clickhouse.annotations" . | nindent 4 }}
+ {{- end }}
+data:
+ kubernetes.xml: |
+
+
+
+ <{{ .Values.auth.username }}>
+
+
+ ::/0
+
+ default
+ default
+ 1
+ {{ .Values.auth.username }}>
+
+ {{- if gt (.Values.config.maxMemoryUsage | int) 0 }}
+
+
+ {{ .Values.config.maxMemoryUsage }}
+
+
+ {{- end }}
+ {{- if .Values.config.extraUsersConfig }}
+ {{ .Values.config.extraUsersConfig | nindent 6 }}
+ {{- end }}
+
+{{- end }}
diff --git a/charts/clickhouse/templates/extraobjects.yaml b/charts/clickhouse/templates/extraobjects.yaml
new file mode 100644
index 000000000..d12e6cc6e
--- /dev/null
+++ b/charts/clickhouse/templates/extraobjects.yaml
@@ -0,0 +1,4 @@
+{{- range .Values.extraObjects }}
+---
+{{- include "cloudpirates.tplvalues.render" (dict "value" . "context" $) }}
+{{- end }}
diff --git a/charts/clickhouse/templates/httproute.yaml b/charts/clickhouse/templates/httproute.yaml
new file mode 100644
index 000000000..39761801e
--- /dev/null
+++ b/charts/clickhouse/templates/httproute.yaml
@@ -0,0 +1,69 @@
+{{- if .Values.gatewayAPI.httpRoute.enabled -}}
+{{- $fullName := include "clickhouse.fullname" . -}}
+{{- $svcPort := .Values.service.httpPort -}}
+{{- $httpRoute := .Values.gatewayAPI.httpRoute -}}
+{{- $hostnames := $httpRoute.hostnames -}}
+{{- if not $hostnames }}
+{{- $hostnames = list -}}
+{{- range .Values.ingress.hosts -}}
+{{- $hostnames = append $hostnames .host -}}
+{{- end -}}
+{{- end -}}
+apiVersion: gateway.networking.k8s.io/v1
+kind: HTTPRoute
+metadata:
+ name: {{ $fullName }}
+ namespace: {{ .Release.Namespace | quote }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- $annotations := merge $httpRoute.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ parentRefs:
+ {{- range $httpRoute.parentRefs }}
+ - name: {{ .name }}
+ {{- if .namespace }}
+ namespace: {{ .namespace }}
+ {{- end }}
+ {{- if .sectionName }}
+ sectionName: {{ .sectionName }}
+ {{- end }}
+ {{- end }}
+ {{- if $hostnames }}
+ hostnames:
+ {{- range $hostnames }}
+ - {{ . | quote }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- if $httpRoute.rules }}
+ {{- range $httpRoute.rules }}
+ - {{- if .matches }}
+ matches:
+ {{- range .matches }}
+ - path:
+ type: {{ .path.type }}
+ value: {{ .path.value }}
+ {{- end }}
+ {{- end }}
+ backendRefs:
+ - name: {{ $fullName }}
+ port: {{ $svcPort }}
+ {{- end }}
+ {{- else }}
+ {{- range .Values.ingress.hosts }}
+ {{- range .paths }}
+ - matches:
+ - path:
+ type: {{ if eq .pathType "Exact" }}Exact{{ else }}PathPrefix{{ end }}
+ value: {{ .path }}
+ backendRefs:
+ - name: {{ $fullName }}
+ port: {{ $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/charts/clickhouse/templates/ingress.yaml b/charts/clickhouse/templates/ingress.yaml
new file mode 100644
index 000000000..c45ad6e35
--- /dev/null
+++ b/charts/clickhouse/templates/ingress.yaml
@@ -0,0 +1,52 @@
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "clickhouse.fullname" . -}}
+{{- $svcPort := .Values.service.httpPort -}}
+apiVersion: networking.k8s.io/v1
+kind: Ingress
+metadata:
+ name: {{ $fullName }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- $annotations := merge .Values.ingress.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
+ ingressClassName: {{ .Values.ingress.className }}
+ {{- end }}
+ {{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . | quote }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
+ pathType: {{ .pathType }}
+ {{- end }}
+ backend:
+ {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $svcPort }}
+ {{- else }}
+ serviceName: {{ $fullName }}
+ servicePort: {{ $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/charts/clickhouse/templates/init-scripts-configmap.yaml b/charts/clickhouse/templates/init-scripts-configmap.yaml
new file mode 100644
index 000000000..265df1857
--- /dev/null
+++ b/charts/clickhouse/templates/init-scripts-configmap.yaml
@@ -0,0 +1,18 @@
+{{- if and .Values.initdb.scripts (not .Values.initdb.scriptsConfigMap) }}
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: {{ include "clickhouse.initdb.scriptsCM" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- if .Values.commonAnnotations }}
+ annotations:
+ {{- include "clickhouse.annotations" . | nindent 4 }}
+ {{- end }}
+data:
+ {{- range $key, $value := .Values.initdb.scripts }}
+ {{ $key }}: |
+ {{- $value | nindent 4 }}
+ {{- end }}
+{{- end }}
diff --git a/charts/clickhouse/templates/secret.yaml b/charts/clickhouse/templates/secret.yaml
new file mode 100644
index 000000000..e57ebd46b
--- /dev/null
+++ b/charts/clickhouse/templates/secret.yaml
@@ -0,0 +1,33 @@
+{{- if not .Values.auth.existingSecret }}
+apiVersion: v1
+kind: Secret
+metadata:
+ name: {{ include "clickhouse.fullname" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- if .Values.commonAnnotations }}
+ annotations:
+ {{- include "clickhouse.annotations" . | nindent 4 }}
+ {{- end }}
+type: Opaque
+data:
+ {{- $existingSecret := (lookup "v1" "Secret" .Release.Namespace (include "clickhouse.fullname" .)) }}
+ {{- $existingPassword := "" }}
+ {{- if and $existingSecret $existingSecret.data }}
+ {{- $existingPassword = index $existingSecret.data "clickhouse-password" }}
+ {{- end }}
+ {{- $password := $existingPassword | default (.Values.auth.password | default (randAlphaNum 32) | b64enc) }}
+ {{- $host := printf "%s.%s.svc" (include "clickhouse.fullname" .) .Release.Namespace }}
+ {{- $tcpPort := .Values.service.tcpPort | toString }}
+ {{- $httpPort := .Values.service.httpPort | toString }}
+ {{- $username := .Values.auth.username }}
+ {{- $database := .Values.auth.database }}
+ clickhouse-password: {{ $password | quote }}
+ host: {{ $host | b64enc | quote }}
+ tcp-port: {{ $tcpPort | b64enc | quote }}
+ http-port: {{ $httpPort | b64enc | quote }}
+ username: {{ $username | b64enc | quote }}
+ database: {{ $database | b64enc | quote }}
+ uri: {{ printf "clickhouse://%s:%s@%s:%s/%s" $username ($password | b64dec) $host $tcpPort $database | b64enc | quote }}
+{{- end }}
diff --git a/charts/clickhouse/templates/service-metrics.yaml b/charts/clickhouse/templates/service-metrics.yaml
new file mode 100644
index 000000000..4c09929fe
--- /dev/null
+++ b/charts/clickhouse/templates/service-metrics.yaml
@@ -0,0 +1,27 @@
+{{- if .Values.metrics.enabled }}
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "clickhouse.fullname" . }}-metrics
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ app.kubernetes.io/component: metrics
+ {{- with .Values.metrics.service.labels }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- $annotations := merge .Values.metrics.service.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ type: ClusterIP
+ ports:
+ - name: metrics
+ port: {{ .Values.metrics.service.port }}
+ protocol: TCP
+ targetPort: metrics
+ selector:
+ {{- include "clickhouse.selectorLabels" . | nindent 4 }}
+{{- end }}
diff --git a/charts/clickhouse/templates/service.yaml b/charts/clickhouse/templates/service.yaml
new file mode 100644
index 000000000..1e52e8a33
--- /dev/null
+++ b/charts/clickhouse/templates/service.yaml
@@ -0,0 +1,61 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "clickhouse.fullname" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ type: {{ .Values.service.type }}
+ {{- if and (eq .Values.service.type "LoadBalancer") (not (empty .Values.service.loadBalancerIP)) }}
+ loadBalancerIP: {{ .Values.service.loadBalancerIP }}
+ {{- end }}
+ {{- if and (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) (not (empty .Values.service.externalTrafficPolicy)) }}
+ externalTrafficPolicy: {{ .Values.service.externalTrafficPolicy | quote }}
+ {{- end }}
+ ports:
+ - port: {{ .Values.service.httpPort }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ - port: {{ .Values.service.tcpPort }}
+ targetPort: tcp
+ {{- if and (or (eq .Values.service.type "LoadBalancer") (eq .Values.service.type "NodePort")) .Values.service.nodePort }}
+ nodePort: {{ .Values.service.nodePort }}
+ {{- end }}
+ protocol: TCP
+ name: tcp
+ selector:
+ {{- include "clickhouse.selectorLabels" . | nindent 4 }}
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "clickhouse.fullname" . }}-headless
+ namespace: {{ .Release.Namespace | quote }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- $annotations := merge .Values.service.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ type: ClusterIP
+ clusterIP: None
+ ports:
+ - port: {{ .Values.service.httpPort }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ - port: {{ .Values.service.tcpPort }}
+ targetPort: tcp
+ protocol: TCP
+ name: tcp
+ selector:
+ {{- include "clickhouse.selectorLabels" . | nindent 4 }}
diff --git a/charts/clickhouse/templates/serviceaccount.yaml b/charts/clickhouse/templates/serviceaccount.yaml
new file mode 100644
index 000000000..886225523
--- /dev/null
+++ b/charts/clickhouse/templates/serviceaccount.yaml
@@ -0,0 +1,14 @@
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "clickhouse.serviceAccountName" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- $annotations := merge .Values.serviceAccount.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- end }}
diff --git a/charts/clickhouse/templates/servicemonitor.yaml b/charts/clickhouse/templates/servicemonitor.yaml
new file mode 100644
index 000000000..6bc7dd02d
--- /dev/null
+++ b/charts/clickhouse/templates/servicemonitor.yaml
@@ -0,0 +1,52 @@
+{{- if and .Values.metrics.enabled .Values.metrics.serviceMonitor.enabled }}
+apiVersion: monitoring.coreos.com/v1
+kind: ServiceMonitor
+metadata:
+ name: {{ include "clickhouse.fullname" . }}-metrics
+ {{- if .Values.metrics.serviceMonitor.namespace }}
+ namespace: {{ .Values.metrics.serviceMonitor.namespace }}
+ {{- else }}
+ namespace: {{ .Release.Namespace }}
+ {{- end }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ app.kubernetes.io/component: metrics
+ {{- with .Values.metrics.serviceMonitor.selector }}
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+ {{- $annotations := merge .Values.metrics.serviceMonitor.annotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ jobLabel: {{ include "clickhouse.fullname" . }}
+ selector:
+ matchLabels:
+ {{- include "clickhouse.selectorLabels" . | nindent 6 }}
+ app.kubernetes.io/component: metrics
+ endpoints:
+ - port: metrics
+ {{- with .Values.metrics.serviceMonitor.interval }}
+ interval: {{ . }}
+ {{- end }}
+ {{- with .Values.metrics.serviceMonitor.scrapeTimeout }}
+ scrapeTimeout: {{ . }}
+ {{- end }}
+ path: /metrics
+ {{- with .Values.metrics.serviceMonitor.honorLabels }}
+ honorLabels: {{ . }}
+ {{- end }}
+ {{- with .Values.metrics.serviceMonitor.relabelings }}
+ relabelings:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.metrics.serviceMonitor.metricRelabelings }}
+ metricRelabelings:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.metrics.serviceMonitor.namespaceSelector }}
+ namespaceSelector:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- end }}
diff --git a/charts/clickhouse/templates/statefulset.yaml b/charts/clickhouse/templates/statefulset.yaml
new file mode 100644
index 000000000..9bc2d54ab
--- /dev/null
+++ b/charts/clickhouse/templates/statefulset.yaml
@@ -0,0 +1,260 @@
+{{- $hasInitScripts := or .Values.initdb.scripts .Values.initdb.scriptsConfigMap -}}
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+ name: {{ include "clickhouse.fullname" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 4 }}
+ {{- if .Values.commonAnnotations }}
+ annotations:
+ {{- include "clickhouse.annotations" . | nindent 4 }}
+ {{- end }}
+spec:
+ replicas: {{ .Values.replicaCount }}
+ serviceName: {{ include "clickhouse.fullname" . }}-headless
+ updateStrategy:
+ type: RollingUpdate
+ selector:
+ matchLabels:
+ {{- include "clickhouse.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ {{- $annotations := merge .Values.podAnnotations .Values.commonAnnotations }}
+ {{- with $annotations }}
+ annotations: {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "clickhouse.labels" . | nindent 8 }}
+ {{- with .Values.podLabels }}
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ spec:
+ serviceAccountName: {{ include "clickhouse.serviceAccountName" . }}
+ {{- if .Values.priorityClassName }}
+ priorityClassName: {{ .Values.priorityClassName }}
+ {{- end }}
+ automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
+{{- with (include "clickhouse.imagePullSecrets" .) }}
+{{- . | nindent 6 }}
+{{- end }}
+ securityContext: {{ include "cloudpirates.renderPodSecurityContext" . | nindent 8 }}
+ {{- if .Values.initContainers }}
+ initContainers:
+ {{- toYaml .Values.initContainers | nindent 8 }}
+ {{- end }}
+ terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }}
+ enableServiceLinks: {{ .Values.global.enableServiceLinks }}
+ containers:
+ - name: {{ .Chart.Name }}
+ securityContext: {{ include "cloudpirates.renderContainerSecurityContext" . | nindent 12 }}
+ image: {{ include "clickhouse.image" . }}
+ imagePullPolicy: {{ .Values.image.imagePullPolicy }}
+ {{- if .Values.command }}
+ command: {{- toYaml .Values.command | nindent 12 }}
+ {{- end }}
+ {{- if .Values.args }}
+ args: {{- toYaml .Values.args | nindent 12 }}
+ {{- end }}
+ env:
+ - name: CLICKHOUSE_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ include "clickhouse.secretName" . }}
+ key: {{ include "clickhouse.passwordKey" . }}
+ - name: CLICKHOUSE_DB
+ value: {{ .Values.auth.database | quote }}
+ - name: CLICKHOUSE_USER
+ value: {{ .Values.auth.username | quote }}
+ - name: CLICKHOUSE_DEFAULT_ACCESS_MANAGEMENT
+ value: "1"
+ {{- with .Values.extraEnvVars }}
+{{ toYaml . | indent 12 }}
+ {{- end }}
+ {{- if .Values.extraEnvVarsSecret }}
+ envFrom:
+ - secretRef:
+ name: {{ .Values.extraEnvVarsSecret }}
+ {{- end }}
+ ports:
+ - name: http
+ containerPort: {{ .Values.service.httpPort }}
+ protocol: TCP
+ - name: tcp
+ containerPort: {{ .Values.service.tcpPort }}
+ protocol: TCP
+ {{- if .Values.livenessProbe.enabled }}
+ livenessProbe:
+ httpGet:
+ path: /ping
+ port: http
+ initialDelaySeconds: {{ .Values.livenessProbe.initialDelaySeconds }}
+ periodSeconds: {{ .Values.livenessProbe.periodSeconds }}
+ timeoutSeconds: {{ .Values.livenessProbe.timeoutSeconds }}
+ successThreshold: {{ .Values.livenessProbe.successThreshold }}
+ failureThreshold: {{ .Values.livenessProbe.failureThreshold }}
+ {{- end }}
+ {{- if .Values.readinessProbe.enabled }}
+ readinessProbe:
+ httpGet:
+ path: /ping
+ port: http
+ initialDelaySeconds: {{ .Values.readinessProbe.initialDelaySeconds }}
+ periodSeconds: {{ .Values.readinessProbe.periodSeconds }}
+ timeoutSeconds: {{ .Values.readinessProbe.timeoutSeconds }}
+ successThreshold: {{ .Values.readinessProbe.successThreshold }}
+ failureThreshold: {{ .Values.readinessProbe.failureThreshold }}
+ {{- end }}
+ {{- if .Values.startupProbe.enabled }}
+ startupProbe:
+ httpGet:
+ path: /ping
+ port: http
+ initialDelaySeconds: {{ .Values.startupProbe.initialDelaySeconds }}
+ periodSeconds: {{ .Values.startupProbe.periodSeconds }}
+ timeoutSeconds: {{ .Values.startupProbe.timeoutSeconds }}
+ successThreshold: {{ .Values.startupProbe.successThreshold }}
+ failureThreshold: {{ .Values.startupProbe.failureThreshold }}
+ {{- end }}
+ resources:
+ {{- toYaml .Values.resources | nindent 12 }}
+ volumeMounts:
+ - name: {{ .Values.persistence.volumeName }}
+ mountPath: /var/lib/clickhouse
+ {{- if .Values.persistence.subPath }}
+ subPath: {{ .Values.persistence.subPath }}
+ {{- end }}
+ - name: config
+ mountPath: /etc/clickhouse-server/config.d/kubernetes.xml
+ subPath: kubernetes.xml
+ - name: users-config
+ mountPath: /etc/clickhouse-server/users.d/kubernetes.xml
+ subPath: kubernetes.xml
+ - name: tmp
+ mountPath: /tmp
+ {{- if $hasInitScripts }}
+ - name: init-scripts
+ mountPath: /docker-entrypoint-initdb.d
+ {{- end }}
+ {{- if .Values.extraVolumeMounts }}
+ {{- toYaml .Values.extraVolumeMounts | nindent 12 }}
+ {{- end }}
+ {{- if .Values.metrics.enabled }}
+ - name: metrics
+ image: "{{ .Values.metrics.image.registry }}/{{ .Values.metrics.image.repository }}:{{ .Values.metrics.image.tag }}"
+ imagePullPolicy: {{ .Values.metrics.image.pullPolicy }}
+ securityContext:
+ allowPrivilegeEscalation: false
+ capabilities:
+ drop:
+ - ALL
+ privileged: false
+ readOnlyRootFilesystem: true
+ runAsNonRoot: true
+ runAsUser: 65534
+ runAsGroup: 65534
+ env:
+ - name: CLICKHOUSE_USER
+ value: {{ .Values.auth.username | quote }}
+ - name: CLICKHOUSE_PASSWORD
+ valueFrom:
+ secretKeyRef:
+ name: {{ include "clickhouse.secretName" . }}
+ key: {{ include "clickhouse.passwordKey" . }}
+ - name: CLICKHOUSE_URL
+ value: "http://localhost:{{ .Values.service.httpPort }}/"
+ ports:
+ - name: metrics
+ containerPort: {{ .Values.metrics.service.port }}
+ protocol: TCP
+ startupProbe:
+ httpGet:
+ path: /metrics
+ port: metrics
+ readinessProbe:
+ httpGet:
+ path: /metrics
+ port: metrics
+ livenessProbe:
+ httpGet:
+ path: /metrics
+ port: metrics
+ {{- with .Values.metrics.resources }}
+ resources:
+ {{- toYaml . | nindent 12 }}
+ {{- end }}
+ {{- end }}
+ volumes:
+ {{- if not .Values.persistence.enabled }}
+ - name: {{ .Values.persistence.volumeName }}
+ emptyDir: {}
+ {{- end }}
+ {{- if .Values.persistence.existingClaim }}
+ - name: {{ .Values.persistence.volumeName }}
+ persistentVolumeClaim:
+ claimName: {{ .Values.persistence.existingClaim }}
+ {{- end }}
+ - name: config
+ configMap:
+ name: {{ include "clickhouse.configmapName" . }}
+ - name: users-config
+ configMap:
+ name: {{ include "clickhouse.usersConfigmapName" . }}
+ - name: tmp
+ emptyDir: {}
+ {{- if $hasInitScripts }}
+ - name: init-scripts
+ configMap:
+ name: {{ include "clickhouse.initdb.scriptsCM" . }}
+ defaultMode: 0755
+ {{- end }}
+ {{- if .Values.extraVolumes }}
+ {{- toYaml .Values.extraVolumes | nindent 8 }}
+ {{- end }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- if .Values.persistence.enabled }}
+ {{- if .Values.persistentVolumeClaimRetentionPolicy.enabled }}
+ persistentVolumeClaimRetentionPolicy:
+ whenDeleted: {{ .Values.persistentVolumeClaimRetentionPolicy.whenDeleted }}
+ whenScaled: {{ .Values.persistentVolumeClaimRetentionPolicy.whenScaled }}
+ {{- end }}
+ {{- if not .Values.persistence.existingClaim }}
+ volumeClaimTemplates:
+ - metadata:
+ name: {{ .Values.persistence.volumeName }}
+ {{- with $labels := merge (include "clickhouse.selectorLabels" . | fromYaml) .Values.persistence.labels .Values.podLabels }}
+ labels:
+ {{- toYaml $labels | nindent 8 }}
+ {{- end }}
+ {{- with .Values.persistence.annotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ spec:
+ accessModes:
+ {{- range .Values.persistence.accessModes }}
+ - {{ . | quote }}
+ {{- end }}
+ resources:
+ requests:
+ storage: {{ .Values.persistence.size | quote }}
+ {{- if .Values.persistence.storageClass }}
+ {{- if (eq "-" .Values.persistence.storageClass) }}
+ storageClassName: ""
+ {{- else }}
+ storageClassName: {{ .Values.persistence.storageClass | quote }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
diff --git a/charts/clickhouse/tests/common-parameters_test.yaml b/charts/clickhouse/tests/common-parameters_test.yaml
new file mode 100644
index 000000000..7fa66a830
--- /dev/null
+++ b/charts/clickhouse/tests/common-parameters_test.yaml
@@ -0,0 +1,131 @@
+suite: test clickhouse common parameters
+templates:
+ - statefulset.yaml
+tests:
+ - it: should use default values when nothing is overridden
+ asserts:
+ - equal:
+ path: metadata.name
+ value: RELEASE-NAME-clickhouse
+ - equal:
+ path: metadata.labels["app.kubernetes.io/name"]
+ value: clickhouse
+ - equal:
+ path: metadata.labels["app.kubernetes.io/instance"]
+ value: RELEASE-NAME
+ - equal:
+ path: spec.template.spec.containers[0].imagePullPolicy
+ value: Always
+
+ - it: should respect global.imageRegistry override
+ set:
+ global:
+ imageRegistry: "my-registry.com"
+ asserts:
+ - matchRegex:
+ path: spec.template.spec.containers[0].image
+ pattern: "^my-registry.com/clickhouse/clickhouse-server:.*"
+
+ - it: should respect global.imagePullSecrets
+ set:
+ global:
+ imagePullSecrets:
+ - name: my-secret-1
+ - name: my-secret-2
+ asserts:
+ - equal:
+ path: spec.template.spec.imagePullSecrets[0].name
+ value: my-secret-1
+ - equal:
+ path: spec.template.spec.imagePullSecrets[1].name
+ value: my-secret-2
+
+ - it: should respect nameOverride
+ set:
+ nameOverride: "custom-name"
+ asserts:
+ - equal:
+ path: metadata.name
+ value: RELEASE-NAME-custom-name
+ - equal:
+ path: metadata.labels["app.kubernetes.io/name"]
+ value: custom-name
+
+ - it: should respect fullnameOverride
+ set:
+ fullnameOverride: "completely-custom-name"
+ asserts:
+ - equal:
+ path: metadata.name
+ value: completely-custom-name
+
+ - it: should add commonLabels to all resources
+ set:
+ commonLabels:
+ environment: "test"
+ team: "platform"
+ asserts:
+ - equal:
+ path: metadata.labels.environment
+ value: test
+ - equal:
+ path: metadata.labels.team
+ value: platform
+
+ - it: should add commonAnnotations to all resources
+ set:
+ commonAnnotations:
+ deployment.kubernetes.io/revision: "1"
+ prometheus.io/scrape: "true"
+ asserts:
+ - equal:
+ path: metadata.annotations["deployment.kubernetes.io/revision"]
+ value: "1"
+ - equal:
+ path: metadata.annotations["prometheus.io/scrape"]
+ value: "true"
+
+ - it: should respect image.imagePullPolicy override
+ set:
+ image:
+ imagePullPolicy: "IfNotPresent"
+ asserts:
+ - equal:
+ path: spec.template.spec.containers[0].imagePullPolicy
+ value: IfNotPresent
+
+ - it: should set CLICKHOUSE_USER env var from values
+ set:
+ auth:
+ username: "myadmin"
+ asserts:
+ - contains:
+ path: spec.template.spec.containers[0].env
+ content:
+ name: CLICKHOUSE_USER
+ value: "myadmin"
+
+ - it: should set CLICKHOUSE_DB env var from values
+ set:
+ auth:
+ database: "mydb"
+ asserts:
+ - contains:
+ path: spec.template.spec.containers[0].env
+ content:
+ name: CLICKHOUSE_DB
+ value: "mydb"
+
+ - it: should set replicaCount
+ set:
+ replicaCount: 3
+ asserts:
+ - equal:
+ path: spec.replicas
+ value: 3
+
+ - it: should set the headless service name
+ asserts:
+ - equal:
+ path: spec.serviceName
+ value: RELEASE-NAME-clickhouse-headless
diff --git a/charts/clickhouse/tests/secret_test.yaml b/charts/clickhouse/tests/secret_test.yaml
new file mode 100644
index 000000000..a15f4ca8f
--- /dev/null
+++ b/charts/clickhouse/tests/secret_test.yaml
@@ -0,0 +1,43 @@
+suite: test clickhouse secret
+templates:
+ - secret.yaml
+tests:
+ - it: should create secret by default
+ asserts:
+ - isKind:
+ of: Secret
+ - equal:
+ path: metadata.name
+ value: RELEASE-NAME-clickhouse
+
+ - it: should not create secret when existingSecret is set
+ set:
+ auth:
+ existingSecret: "my-existing-secret"
+ asserts:
+ - hasDocuments:
+ count: 0
+
+ - it: should use provided password when set
+ set:
+ auth:
+ password: "mysecretpassword"
+ asserts:
+ - equal:
+ path: data["clickhouse-password"]
+ value: bXlzZWNyZXRwYXNzd29yZA==
+
+ - it: should include host and port keys
+ asserts:
+ - isNotEmpty:
+ path: data.host
+ - isNotEmpty:
+ path: data["tcp-port"]
+ - isNotEmpty:
+ path: data["http-port"]
+ - isNotEmpty:
+ path: data.username
+ - isNotEmpty:
+ path: data.database
+ - isNotEmpty:
+ path: data.uri
diff --git a/charts/clickhouse/tests/service_test.yaml b/charts/clickhouse/tests/service_test.yaml
new file mode 100644
index 000000000..54e11101d
--- /dev/null
+++ b/charts/clickhouse/tests/service_test.yaml
@@ -0,0 +1,77 @@
+suite: test clickhouse service
+templates:
+ - service.yaml
+tests:
+ - it: should create ClusterIP service by default
+ documentIndex: 0
+ asserts:
+ - equal:
+ path: spec.type
+ value: ClusterIP
+ - equal:
+ path: metadata.name
+ value: RELEASE-NAME-clickhouse
+
+ - it: should expose HTTP port 8123
+ documentIndex: 0
+ asserts:
+ - contains:
+ path: spec.ports
+ content:
+ port: 8123
+ targetPort: http
+ protocol: TCP
+ name: http
+
+ - it: should expose TCP port 9000
+ documentIndex: 0
+ asserts:
+ - contains:
+ path: spec.ports
+ content:
+ port: 9000
+ targetPort: tcp
+ protocol: TCP
+ name: tcp
+
+ - it: should create headless service
+ documentIndex: 1
+ asserts:
+ - equal:
+ path: metadata.name
+ value: RELEASE-NAME-clickhouse-headless
+ - equal:
+ path: spec.clusterIP
+ value: None
+
+ - it: should support custom service ports
+ set:
+ service:
+ httpPort: 8124
+ tcpPort: 9001
+ documentIndex: 0
+ asserts:
+ - contains:
+ path: spec.ports
+ content:
+ port: 8124
+ targetPort: http
+ protocol: TCP
+ name: http
+ - contains:
+ path: spec.ports
+ content:
+ port: 9001
+ targetPort: tcp
+ protocol: TCP
+ name: tcp
+
+ - it: should support LoadBalancer service type
+ set:
+ service:
+ type: LoadBalancer
+ documentIndex: 0
+ asserts:
+ - equal:
+ path: spec.type
+ value: LoadBalancer
diff --git a/charts/clickhouse/tests/volume-claim_test.yaml b/charts/clickhouse/tests/volume-claim_test.yaml
new file mode 100644
index 000000000..0eb592a1b
--- /dev/null
+++ b/charts/clickhouse/tests/volume-claim_test.yaml
@@ -0,0 +1,64 @@
+suite: test clickhouse persistence
+templates:
+ - statefulset.yaml
+tests:
+ - it: should create volumeClaimTemplate when persistence is enabled
+ asserts:
+ - isNotEmpty:
+ path: spec.volumeClaimTemplates
+ - equal:
+ path: spec.volumeClaimTemplates[0].metadata.name
+ value: data
+ - equal:
+ path: spec.volumeClaimTemplates[0].spec.resources.requests.storage
+ value: 10Gi
+
+ - it: should use emptyDir when persistence is disabled
+ set:
+ persistence:
+ enabled: false
+ asserts:
+ - contains:
+ path: spec.template.spec.volumes
+ content:
+ name: data
+ emptyDir: {}
+
+ - it: should use existingClaim when set
+ set:
+ persistence:
+ existingClaim: "my-existing-pvc"
+ asserts:
+ - contains:
+ path: spec.template.spec.volumes
+ content:
+ name: data
+ persistentVolumeClaim:
+ claimName: my-existing-pvc
+
+ - it: should use custom storageClass
+ set:
+ persistence:
+ storageClass: "fast-ssd"
+ asserts:
+ - equal:
+ path: spec.volumeClaimTemplates[0].spec.storageClassName
+ value: fast-ssd
+
+ - it: should set empty storageClass when set to dash
+ set:
+ persistence:
+ storageClass: "-"
+ asserts:
+ - equal:
+ path: spec.volumeClaimTemplates[0].spec.storageClassName
+ value: ""
+
+ - it: should use custom persistence size
+ set:
+ persistence:
+ size: 50Gi
+ asserts:
+ - equal:
+ path: spec.volumeClaimTemplates[0].spec.resources.requests.storage
+ value: 50Gi
diff --git a/charts/clickhouse/values.schema.json b/charts/clickhouse/values.schema.json
new file mode 100644
index 000000000..66cc34cbc
--- /dev/null
+++ b/charts/clickhouse/values.schema.json
@@ -0,0 +1,556 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "type": "object",
+ "properties": {
+ "affinity": {
+ "type": "object"
+ },
+ "args": {
+ "type": "array"
+ },
+ "auth": {
+ "type": "object",
+ "properties": {
+ "database": {
+ "type": "string"
+ },
+ "existingSecret": {
+ "type": "string"
+ },
+ "password": {
+ "type": "string"
+ },
+ "secretKeys": {
+ "type": "object",
+ "properties": {
+ "passwordKey": {
+ "type": "string"
+ }
+ }
+ },
+ "username": {
+ "type": "string"
+ }
+ }
+ },
+ "command": {
+ "type": "array"
+ },
+ "commonAnnotations": {
+ "type": "object"
+ },
+ "commonLabels": {
+ "type": "object"
+ },
+ "config": {
+ "type": "object",
+ "properties": {
+ "existingConfigmap": {
+ "type": "string"
+ },
+ "existingUsersConfigmap": {
+ "type": "string"
+ },
+ "extraConfig": {
+ "type": "string"
+ },
+ "extraUsersConfig": {
+ "type": "string"
+ },
+ "listenHost": {
+ "type": "string"
+ },
+ "logLevel": {
+ "type": "string"
+ },
+ "maxConcurrentQueries": {
+ "type": "integer"
+ },
+ "maxConnections": {
+ "type": "integer"
+ },
+ "maxMemoryUsage": {
+ "type": "integer"
+ },
+ "timezone": {
+ "type": "string"
+ }
+ }
+ },
+ "containerSecurityContext": {
+ "type": "object",
+ "properties": {
+ "allowPrivilegeEscalation": {
+ "type": "boolean"
+ },
+ "capabilities": {
+ "type": "object",
+ "properties": {
+ "drop": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "readOnlyRootFilesystem": {
+ "type": "boolean"
+ },
+ "runAsGroup": {
+ "type": "integer"
+ },
+ "runAsNonRoot": {
+ "type": "boolean"
+ },
+ "runAsUser": {
+ "type": "integer"
+ }
+ }
+ },
+ "extraEnvVars": {
+ "type": "array"
+ },
+ "extraEnvVarsSecret": {
+ "type": "string"
+ },
+ "extraObjects": {
+ "type": "array"
+ },
+ "extraVolumeMounts": {
+ "type": "array"
+ },
+ "extraVolumes": {
+ "type": "array"
+ },
+ "fullnameOverride": {
+ "type": "string"
+ },
+ "gatewayAPI": {
+ "type": "object",
+ "properties": {
+ "httpRoute": {
+ "type": "object",
+ "properties": {
+ "annotations": {
+ "type": "object"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "hostnames": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "parentRefs": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string"
+ },
+ "namespace": {
+ "type": "string"
+ },
+ "sectionName": {
+ "type": "string"
+ }
+ }
+ }
+ },
+ "rules": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "matches": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "object",
+ "properties": {
+ "type": {
+ "type": "string"
+ },
+ "value": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "global": {
+ "type": "object",
+ "properties": {
+ "enableServiceLinks": {
+ "type": "boolean"
+ },
+ "imagePullSecrets": {
+ "type": "array"
+ },
+ "imageRegistry": {
+ "type": "string"
+ }
+ }
+ },
+ "image": {
+ "type": "object",
+ "properties": {
+ "imagePullPolicy": {
+ "type": "string"
+ },
+ "registry": {
+ "type": "string"
+ },
+ "repository": {
+ "type": "string"
+ },
+ "tag": {
+ "type": "string"
+ }
+ }
+ },
+ "ingress": {
+ "type": "object",
+ "properties": {
+ "annotations": {
+ "type": "object"
+ },
+ "className": {
+ "type": "string"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "hosts": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "host": {
+ "type": "string"
+ },
+ "paths": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "properties": {
+ "path": {
+ "type": "string"
+ },
+ "pathType": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "tls": {
+ "type": "array"
+ }
+ }
+ },
+ "initContainers": {
+ "type": "array"
+ },
+ "initdb": {
+ "type": "object",
+ "properties": {
+ "scripts": {
+ "type": "object"
+ },
+ "scriptsConfigMap": {
+ "type": "string"
+ }
+ }
+ },
+ "livenessProbe": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "failureThreshold": {
+ "type": "integer"
+ },
+ "initialDelaySeconds": {
+ "type": "integer"
+ },
+ "periodSeconds": {
+ "type": "integer"
+ },
+ "successThreshold": {
+ "type": "integer"
+ },
+ "timeoutSeconds": {
+ "type": "integer"
+ }
+ }
+ },
+ "metrics": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "image": {
+ "type": "object",
+ "properties": {
+ "pullPolicy": {
+ "type": "string"
+ },
+ "registry": {
+ "type": "string"
+ },
+ "repository": {
+ "type": "string"
+ },
+ "tag": {
+ "type": "string"
+ }
+ }
+ },
+ "resources": {
+ "type": "object"
+ },
+ "service": {
+ "type": "object",
+ "properties": {
+ "annotations": {
+ "type": "object"
+ },
+ "labels": {
+ "type": "object"
+ },
+ "port": {
+ "type": "integer"
+ }
+ }
+ },
+ "serviceMonitor": {
+ "type": "object",
+ "properties": {
+ "annotations": {
+ "type": "object"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "honorLabels": {
+ "type": "boolean"
+ },
+ "interval": {
+ "type": "string"
+ },
+ "metricRelabelings": {
+ "type": "array"
+ },
+ "namespace": {
+ "type": "string"
+ },
+ "namespaceSelector": {
+ "type": "object"
+ },
+ "relabelings": {
+ "type": "array"
+ },
+ "scrapeTimeout": {
+ "type": "string"
+ },
+ "selector": {
+ "type": "object"
+ }
+ }
+ }
+ }
+ },
+ "nameOverride": {
+ "type": "string"
+ },
+ "nodeSelector": {
+ "type": "object"
+ },
+ "persistence": {
+ "type": "object",
+ "properties": {
+ "accessModes": {
+ "type": "array",
+ "items": {
+ "type": "string"
+ }
+ },
+ "annotations": {
+ "type": "object"
+ },
+ "enabled": {
+ "type": "boolean"
+ },
+ "existingClaim": {
+ "type": "string"
+ },
+ "labels": {
+ "type": "object"
+ },
+ "size": {
+ "type": "string"
+ },
+ "storageClass": {
+ "type": "string"
+ },
+ "subPath": {
+ "type": "string"
+ },
+ "volumeName": {
+ "type": "string"
+ }
+ }
+ },
+ "persistentVolumeClaimRetentionPolicy": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "whenDeleted": {
+ "type": "string"
+ },
+ "whenScaled": {
+ "type": "string"
+ }
+ }
+ },
+ "podAnnotations": {
+ "type": "object"
+ },
+ "podLabels": {
+ "type": "object"
+ },
+ "podSecurityContext": {
+ "type": "object",
+ "properties": {
+ "fsGroup": {
+ "type": "integer"
+ }
+ }
+ },
+ "priorityClassName": {
+ "type": "string"
+ },
+ "readinessProbe": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "failureThreshold": {
+ "type": "integer"
+ },
+ "initialDelaySeconds": {
+ "type": "integer"
+ },
+ "periodSeconds": {
+ "type": "integer"
+ },
+ "successThreshold": {
+ "type": "integer"
+ },
+ "timeoutSeconds": {
+ "type": "integer"
+ }
+ }
+ },
+ "replicaCount": {
+ "type": "integer"
+ },
+ "resources": {
+ "type": "object"
+ },
+ "service": {
+ "type": "object",
+ "properties": {
+ "annotations": {
+ "type": "object"
+ },
+ "externalTrafficPolicy": {
+ "type": "string"
+ },
+ "httpPort": {
+ "type": "integer"
+ },
+ "loadBalancerIP": {
+ "type": "string"
+ },
+ "nodePort": {
+ "type": "integer"
+ },
+ "tcpPort": {
+ "type": "integer"
+ },
+ "type": {
+ "type": "string"
+ }
+ }
+ },
+ "serviceAccount": {
+ "type": "object",
+ "properties": {
+ "annotations": {
+ "type": "object"
+ },
+ "automountServiceAccountToken": {
+ "type": "boolean"
+ },
+ "create": {
+ "type": "boolean"
+ },
+ "name": {
+ "type": "string"
+ }
+ }
+ },
+ "startupProbe": {
+ "type": "object",
+ "properties": {
+ "enabled": {
+ "type": "boolean"
+ },
+ "failureThreshold": {
+ "type": "integer"
+ },
+ "initialDelaySeconds": {
+ "type": "integer"
+ },
+ "periodSeconds": {
+ "type": "integer"
+ },
+ "successThreshold": {
+ "type": "integer"
+ },
+ "timeoutSeconds": {
+ "type": "integer"
+ }
+ }
+ },
+ "terminationGracePeriodSeconds": {
+ "type": "integer"
+ },
+ "tolerations": {
+ "type": "array"
+ }
+ }
+}
diff --git a/charts/clickhouse/values.yaml b/charts/clickhouse/values.yaml
new file mode 100644
index 000000000..270ce3f16
--- /dev/null
+++ b/charts/clickhouse/values.yaml
@@ -0,0 +1,351 @@
+## @section Global parameters
+global:
+ ## @param global.imageRegistry Global Docker Image registry
+ imageRegistry: ""
+ ## @param global.imagePullSecrets Global Docker registry secret names as an array
+ imagePullSecrets: []
+ enableServiceLinks: true
+
+## @section Common parameters
+## @param nameOverride String to partially override clickhouse.fullname
+nameOverride: ""
+## @param fullnameOverride String to fully override clickhouse.fullname
+fullnameOverride: ""
+## @param commonLabels Labels to add to all deployed objects
+commonLabels: {}
+## @param commonAnnotations Annotations to add to all deployed objects
+commonAnnotations: {}
+## @param priorityClassName Priority class name to be used for the pods
+priorityClassName: ""
+
+## @param terminationGracePeriodSeconds Time for Kubernetes to wait for the pod to gracefully terminate
+terminationGracePeriodSeconds: 30
+
+## @section ClickHouse image configuration
+image:
+ ## @param image.registry ClickHouse image registry
+ registry: docker.io
+ ## @param image.repository ClickHouse image repository
+ repository: clickhouse/clickhouse-server
+ ## @param image.tag ClickHouse image tag (immutable tags are recommended)
+ tag: "25.3@sha256:b627d7a9bc0e0c1bac26cdbe9d2fc6316faa29c5d8a174f28f5abd57d0fa6ba2"
+ ## @param image.imagePullPolicy ClickHouse image pull policy
+ imagePullPolicy: Always
+
+## @section Deployment configuration
+## @param replicaCount Number of ClickHouse replicas to deploy
+replicaCount: 1
+
+## @section Pod annotations and labels
+## @param podAnnotations Map of annotations to add to the pods
+podAnnotations: {}
+## @param podLabels Map of labels to add to the pods
+podLabels: {}
+
+## @section Security Context
+podSecurityContext:
+ ## @param podSecurityContext.fsGroup Group ID for the volumes of the pod
+ fsGroup: 101
+
+containerSecurityContext:
+ ## @param containerSecurityContext.allowPrivilegeEscalation Enable container privilege escalation
+ allowPrivilegeEscalation: false
+ ## @param containerSecurityContext.runAsNonRoot Configure the container to run as a non-root user
+ runAsNonRoot: true
+ ## @param containerSecurityContext.runAsUser User ID for the ClickHouse container
+ runAsUser: 101
+ ## @param containerSecurityContext.runAsGroup Group ID for the ClickHouse container
+ runAsGroup: 101
+ ## @param containerSecurityContext.readOnlyRootFilesystem Mount container root filesystem as read-only
+ readOnlyRootFilesystem: false
+ ## @param containerSecurityContext.capabilities.drop Linux capabilities to be dropped
+ capabilities:
+ drop:
+ - ALL
+
+## @section ClickHouse Authentication
+auth:
+ ## @param auth.username ClickHouse admin username
+ username: "default"
+ ## @param auth.password Password for the ClickHouse admin user (auto-generated if empty)
+ password: ""
+ ## @param auth.database Default database to create at initialisation
+ database: "default"
+ ## @param auth.existingSecret Name of existing secret to use for ClickHouse credentials
+ existingSecret: ""
+ secretKeys:
+ ## @param auth.secretKeys.passwordKey Name of key in existing secret for ClickHouse admin password
+ passwordKey: "clickhouse-password"
+
+## @section ClickHouse Configuration
+config:
+ ## @param config.existingConfigmap Name of existing ConfigMap with ClickHouse configuration (config.xml)
+ existingConfigmap: ""
+ ## @param config.existingUsersConfigmap Name of existing ConfigMap with ClickHouse users configuration (users.xml)
+ existingUsersConfigmap: ""
+ ## @param config.listenHost Listen host for ClickHouse (default: listen on all interfaces)
+ listenHost: "0.0.0.0"
+ ## @param config.maxConnections Maximum number of simultaneous client connections
+ maxConnections: 4096
+ ## @param config.maxConcurrentQueries Maximum number of simultaneously processed queries
+ maxConcurrentQueries: 100
+ ## @param config.maxMemoryUsage Maximum memory usage for a single query in bytes (0 = unlimited)
+ maxMemoryUsage: 0
+ ## @param config.timezone Default timezone
+ timezone: "UTC"
+ ## @param config.logLevel Log level (trace, debug, information, warning, error, fatal)
+ logLevel: "information"
+ ## @param config.extraConfig Additional ClickHouse XML configuration snippets merged into config.xml
+ extraConfig: ""
+ ## @param config.extraUsersConfig Additional ClickHouse XML configuration snippets merged into users.xml
+ extraUsersConfig: ""
+
+## @section ClickHouse Initialization scripts
+initdb:
+ ## @param initdb.scripts Dictionary of SQL scripts to run at first boot (key: filename, value: SQL content)
+ scripts: {}
+ ## @param initdb.scriptsConfigMap ConfigMap with SQL scripts to be run at first boot
+ scriptsConfigMap: ""
+
+## @section Service configuration
+service:
+ ## @param service.type ClickHouse service type
+ type: ClusterIP
+ ## @param service.httpPort ClickHouse HTTP interface port
+ httpPort: 8123
+ ## @param service.tcpPort ClickHouse TCP (native) interface port
+ tcpPort: 9000
+ ## @param service.nodePort NodePort for TCP service (only used when type=NodePort)
+ nodePort: 30900
+ ## @param service.annotations Service annotations
+ annotations: {}
+ ## @param service.loadBalancerIP LoadBalancer IP if service type is `LoadBalancer`
+ loadBalancerIP: ""
+ ## @param service.externalTrafficPolicy External traffic policy for the service
+ externalTrafficPolicy: ""
+
+## @section Ingress configuration
+ingress:
+ ## @param ingress.enabled Enable ingress record generation for ClickHouse HTTP interface
+ enabled: false
+ ## @param ingress.className IngressClass that will be used to implement the Ingress
+ className: ""
+ ## @param ingress.annotations Additional annotations for the Ingress resource
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ ## @param ingress.hosts[0].host Hostname for ClickHouse ingress
+ ## @param ingress.hosts[0].paths[0].path Path for ClickHouse ingress
+ ## @param ingress.hosts[0].paths[0].pathType Path type for ClickHouse ingress
+ hosts:
+ - host: clickhouse.local
+ paths:
+ - path: /
+ pathType: Prefix
+ ## @param ingress.tls TLS configuration for ClickHouse ingress
+ tls: []
+ # - secretName: clickhouse-tls
+ # hosts:
+ # - clickhouse.local
+
+## @section Gateway API parameters
+gatewayAPI:
+ httpRoute:
+ ## @param gatewayAPI.httpRoute.enabled Enable Gateway API HTTPRoute generation for ClickHouse
+ enabled: false
+ ## @param gatewayAPI.httpRoute.annotations Additional annotations for the HTTPRoute resource
+ annotations: {}
+ ## @param gatewayAPI.httpRoute.parentRefs References to the parent Gateways
+ parentRefs:
+ - name: gateway
+ namespace: ""
+ sectionName: ""
+ ## @param gatewayAPI.httpRoute.hostnames List of hostnames to match
+ hostnames:
+ - clickhouse.local
+ ## @param gatewayAPI.httpRoute.rules HTTPRoute rules
+ rules:
+ - matches:
+ - path:
+ type: PathPrefix
+ value: /
+
+## @section Resources
+resources: {}
+ ## We usually recommend not to specify default resources and to leave this as a conscious
+ ## choice for the user. This also increases chances charts run on environments with little
+ ## resources, such as Minikube. If you do want to specify resources, uncomment the following
+ ## lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+ # limits:
+ # cpu: "2"
+ # memory: 4Gi
+ # requests:
+ # cpu: 500m
+ # memory: 1Gi
+
+## @section Persistence
+persistence:
+ ## @param persistence.enabled Enable persistence using Persistent Volume Claims
+ enabled: true
+ ## @param persistence.storageClass Persistent Volume storage class
+ storageClass: ""
+ ## @param persistence.annotations Persistent Volume Claim annotations
+ annotations: {}
+ ## @param persistence.size Persistent Volume size
+ size: 10Gi
+ ## @param persistence.accessModes Persistent Volume access modes
+ accessModes:
+ - ReadWriteOnce
+ ## @param persistence.existingClaim The name of an existing PVC to use for persistence
+ existingClaim: ""
+ ## @param persistence.subPath The subdirectory of the volume to mount to
+ subPath: ""
+ ## @param persistence.labels Labels for persistent volume claims
+ labels: {}
+ ## @param persistence.volumeName Container volume name and volume claim prefix
+ volumeName: "data"
+
+## @section Persistent Volume Claim Retention Policy
+persistentVolumeClaimRetentionPolicy:
+ ## @param persistentVolumeClaimRetentionPolicy.enabled Enable Persistent volume retention policy for the Statefulset
+ enabled: false
+ ## @param persistentVolumeClaimRetentionPolicy.whenScaled Volume retention behavior when the replica count of the StatefulSet is reduced
+ whenScaled: Retain
+ ## @param persistentVolumeClaimRetentionPolicy.whenDeleted Volume retention behavior that applies when the StatefulSet is deleted
+ whenDeleted: Retain
+
+## @section Liveness and readiness probes
+livenessProbe:
+ ## @param livenessProbe.enabled Enable livenessProbe on ClickHouse containers
+ enabled: true
+ ## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe
+ initialDelaySeconds: 30
+ ## @param livenessProbe.periodSeconds Period seconds for livenessProbe
+ periodSeconds: 10
+ ## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe
+ timeoutSeconds: 5
+ ## @param livenessProbe.failureThreshold Failure threshold for livenessProbe
+ failureThreshold: 3
+ ## @param livenessProbe.successThreshold Success threshold for livenessProbe
+ successThreshold: 1
+
+readinessProbe:
+ ## @param readinessProbe.enabled Enable readinessProbe on ClickHouse containers
+ enabled: true
+ ## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe
+ initialDelaySeconds: 10
+ ## @param readinessProbe.periodSeconds Period seconds for readinessProbe
+ periodSeconds: 5
+ ## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe
+ timeoutSeconds: 5
+ ## @param readinessProbe.failureThreshold Failure threshold for readinessProbe
+ failureThreshold: 3
+ ## @param readinessProbe.successThreshold Success threshold for readinessProbe
+ successThreshold: 1
+
+startupProbe:
+ ## @param startupProbe.enabled Enable startupProbe on ClickHouse containers
+ enabled: true
+ ## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe
+ initialDelaySeconds: 30
+ ## @param startupProbe.periodSeconds Period seconds for startupProbe
+ periodSeconds: 10
+ ## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe
+ timeoutSeconds: 5
+ ## @param startupProbe.failureThreshold Failure threshold for startupProbe
+ failureThreshold: 30
+ ## @param startupProbe.successThreshold Success threshold for startupProbe
+ successThreshold: 1
+
+## @section Node Selection
+## @param nodeSelector Node labels for pod assignment
+nodeSelector: {}
+
+## @param tolerations Toleration labels for pod assignment
+tolerations: []
+
+## @param affinity Affinity settings for pod assignment
+affinity: {}
+
+## @section Service Account
+serviceAccount:
+ ## @param serviceAccount.create Specifies whether a service account should be created
+ create: false
+ ## @param serviceAccount.annotations Annotations to add to the service account
+ annotations: {}
+ ## @param serviceAccount.name The name of the service account to use. If not set and create is true, a name is generated using the `fullname` template.
+ name: ""
+ ## @param serviceAccount.automountServiceAccountToken whether to automount the SA token inside the pod
+ automountServiceAccountToken: false
+
+## @param extraEnvVars Additional environment variables to set
+extraEnvVars: []
+ # - name: CUSTOM_VAR
+ # value: "custom-value"
+
+## @param extraEnvVarsSecret Name of a secret containing additional environment variables
+extraEnvVarsSecret: ""
+
+## @param extraVolumes Additional volumes to add to the pod
+extraVolumes: []
+
+## @param extraVolumeMounts Additional volume mounts to add to the ClickHouse container
+extraVolumeMounts: []
+
+## @param initContainers Init containers to add to the ClickHouse pods
+initContainers: []
+
+## @param command Override default container command
+command: []
+
+## @param args Override default container args
+args: []
+
+## @param extraObjects Array of extra objects to deploy with the release
+extraObjects: []
+
+## @section Metrics configuration
+metrics:
+ ## @param metrics.enabled Start a sidecar prometheus exporter to expose ClickHouse metrics
+ enabled: false
+ image:
+ ## @param metrics.image.registry ClickHouse exporter image registry
+ registry: docker.io
+ ## @param metrics.image.repository ClickHouse exporter image repository
+ repository: altinity/clickhouse-exporter
+ ## @param metrics.image.tag ClickHouse exporter image tag
+ tag: "0.0.2@sha256:d19bb9e5e42c3eedbb14e1da7e43b59de86cf87b0012f9acb6c7d74e69cefb58"
+ ## @param metrics.image.pullPolicy ClickHouse exporter image pull policy
+ pullPolicy: Always
+ ## @param metrics.resources Resource limits and requests for metrics container
+ resources: {}
+ ## Metrics service configuration
+ service:
+ ## @param metrics.service.annotations Additional custom annotations for Metrics service
+ annotations: {}
+ ## @param metrics.service.labels Additional custom labels for Metrics service
+ labels: {}
+ ## @param metrics.service.port Metrics service port
+ port: 9116
+ ## Prometheus Operator ServiceMonitor configuration
+ serviceMonitor:
+ ## @param metrics.serviceMonitor.enabled Create ServiceMonitor resource(s) for scraping metrics using PrometheusOperator
+ enabled: false
+ ## @param metrics.serviceMonitor.namespace The namespace in which the ServiceMonitor will be created
+ namespace: ""
+ ## @param metrics.serviceMonitor.interval The interval at which metrics should be scraped
+ interval: 30s
+ ## @param metrics.serviceMonitor.scrapeTimeout The timeout after which the scrape is ended
+ scrapeTimeout: 10s
+ ## @param metrics.serviceMonitor.selector Additional labels for ServiceMonitor resource
+ selector: {}
+ ## @param metrics.serviceMonitor.annotations ServiceMonitor annotations
+ annotations: {}
+ ## @param metrics.serviceMonitor.honorLabels honorLabels chooses the metric's labels on collisions with target labels
+ honorLabels: false
+ ## @param metrics.serviceMonitor.relabelings ServiceMonitor relabel configs to apply to samples before scraping
+ relabelings: []
+ ## @param metrics.serviceMonitor.metricRelabelings ServiceMonitor metricRelabelings configs to apply to samples before ingestion
+ metricRelabelings: []
+ ## @param metrics.serviceMonitor.namespaceSelector ServiceMonitor namespace selector
+ namespaceSelector: {}