feat(ch-ui): add CH-UI

This commit is contained in:
Masaki Yatsu
2025-09-12 23:30:16 +09:00
parent d43dadb91f
commit cf28e427c2
19 changed files with 1002 additions and 0 deletions

2
ch-ui/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
ch-ui-values.yaml
ch-ui-credentials-external-secret.yaml

View File

@@ -0,0 +1,22 @@
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: ch-ui-credentials-external-secret
namespace: {{ .Env.CH_UI_NAMESPACE }}
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-secret-store
kind: ClusterSecretStore
target:
name: ch-ui-credentials
creationPolicy: Owner
template:
type: Opaque
data:
clickhouse-password: "{{ `{{ .clickhouse_password }}` }}"
data:
- secretKey: clickhouse_password
remoteRef:
key: ch-ui/credentials
property: clickhouse-password

View File

@@ -0,0 +1,71 @@
# CH-UI Helm chart values
replicaCount: 1
image:
repository: ghcr.io/caioricciuti/ch-ui
pullPolicy: IfNotPresent
tag: ""
service:
type: ClusterIP
port: 80
targetPort: 5521
ingress:
enabled: true
className: traefik
annotations:
kubernetes.io/ingress.class: traefik
traefik.ingress.kubernetes.io/router.entrypoints: websecure
hosts:
- host: {{ .Env.CH_UI_HOST }}
paths:
- path: /
pathType: Prefix
tls:
- hosts:
- {{ .Env.CH_UI_HOST }}
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
clickhouse:
# ClickHouse server URL
url: {{ .Env.CLICKHOUSE_HOST }}
# Authentication configuration
auth:
# ClickHouse username
username: {{ env.Getenv "CH_UI_CLICKHOUSE_USERNAME" "ch-ui" }}
# Reference to existing secret
existingSecret: "ch-ui-credentials"
# Secret keys for authentication credentials
secretKeys:
password: "clickhouse-password"
# Advanced configuration
useAdvanced: {{ env.Getenv "CH_UI_USE_ADVANCED" "false" }}
requestTimeout: {{ env.Getenv "CH_UI_REQUEST_TIMEOUT" "30000" }}
basePath: {{ env.Getenv "CH_UI_BASE_PATH" "/" }}
# Additional environment variables
extraEnvVars: []
# Environment variables from existing ConfigMaps or Secrets
extraEnvVarsCM: ""
extraEnvVarsSecret: ""
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 3
targetCPUUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}

135
ch-ui/justfile Normal file
View File

@@ -0,0 +1,135 @@
set fallback := true
export CH_UI_NAMESPACE := env("CH_UI_NAMESPACE", "clickhouse")
export CH_UI_HOST := env("CH_UI_HOST", "")
export CLICKHOUSE_NAMESPACE := env("CLICKHOUSE_NAMESPACE", "clickhouse")
export EXTERNAL_SECRETS_NAMESPACE := env("EXTERNAL_SECRETS_NAMESPACE", "external-secrets")
[private]
default:
@just --list --unsorted --list-submodules
# Create CH-UI user in ClickHouse
create-ch-ui-user:
#!/bin/bash
set -euo pipefail
echo "Creating CH-UI dedicated user in ClickHouse..."
CH_UI_USERNAME="ch-ui"
if just clickhouse::user-exists ${CH_UI_USERNAME} &>/dev/null; then
echo "User '${CH_UI_USERNAME}' already exists."
if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then
CH_PASSWORD=$(just vault::get ch-ui/credentials clickhouse-password 2>/dev/null || echo "")
else
CH_PASSWORD=$(kubectl get secret ch-ui-credentials -n ${CH_UI_NAMESPACE} \
-o jsonpath='{.data.clickhouse-password}' 2>/dev/null | base64 -d || echo "")
fi
if [ -z "${CH_PASSWORD}" ]; then
echo "Existing password not found. Generating new password..."
CH_PASSWORD=$(just utils::random-password)
# Update user password
just clickhouse::change-password ${CH_UI_USERNAME} ${CH_PASSWORD}
else
echo "Existing password found. Syncing password to ClickHouse..."
# Update user password in ClickHouse to match stored password
just clickhouse::change-password ${CH_UI_USERNAME} ${CH_PASSWORD}
fi
else
CH_PASSWORD=$(just utils::random-password)
just clickhouse::create-user ${CH_UI_USERNAME} ${CH_PASSWORD}
just clickhouse::grant-admin ${CH_UI_USERNAME}
fi
if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then
echo "Storing password in Vault..."
just vault::put ch-ui/credentials clickhouse-password="${CH_PASSWORD}"
else
echo "Storing password in Kubernetes Secret..."
kubectl delete secret ch-ui-credentials -n ${CH_UI_NAMESPACE} --ignore-not-found
kubectl create secret generic ch-ui-credentials -n ${CH_UI_NAMESPACE} \
--from-literal=clickhouse-password="${CH_PASSWORD}"
fi
echo "CH-UI user setup completed"
# Create CH-UI credentials secret
create-credentials:
#!/bin/bash
set -euo pipefail
echo "Setting up CH-UI credentials..."
just create-ch-ui-user
if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then
echo "Creating ExternalSecret for CH-UI credentials..."
gomplate -f ch-ui-credentials-external-secret.gomplate.yaml -o ch-ui-credentials-external-secret.yaml
kubectl apply -f ch-ui-credentials-external-secret.yaml
echo "Waiting for credentials secret to be ready..."
kubectl wait --for=condition=Ready externalsecret/ch-ui-credentials-external-secret \
-n ${CH_UI_NAMESPACE} --timeout=60s
fi
echo "CH-UI credentials setup completed"
# Delete CH-UI user from ClickHouse
delete-ch-ui-user:
#!/bin/bash
set -euo pipefail
CH_UI_USERNAME="ch-ui"
if just clickhouse::user-exists ${CH_UI_USERNAME} &>/dev/null; then
echo "Deleting CH-UI user from ClickHouse..."
just clickhouse::delete-user ${CH_UI_USERNAME}
echo "CH-UI user deleted"
else
echo "CH-UI user does not exist"
fi
# Delete CH-UI credentials secret
delete-credentials-secret:
@kubectl delete secret ch-ui-credentials -n ${CH_UI_NAMESPACE} --ignore-not-found
@kubectl delete externalsecret ch-ui-credentials-external-secret -n ${CH_UI_NAMESPACE} --ignore-not-found
# Install CH-UI
install:
#!/bin/bash
set -euo pipefail
export CH_UI_HOST=${CH_UI_HOST:-}
while [ -z "${CH_UI_HOST}" ]; do
CH_UI_HOST=$(
gum input --prompt="CH-UI host (FQDN): " --width=100 \
--placeholder="e.g., ch-ui.example.com"
)
done
echo "Installing CH-UI..."
if ! kubectl get namespace ${CLICKHOUSE_NAMESPACE} &>/dev/null; then
echo "Error: ClickHouse namespace '${CLICKHOUSE_NAMESPACE}' does not exist."
echo "Please install ClickHouse first: just clickhouse::install"
exit 1
fi
if ! kubectl get clickhouseinstallation -n ${CLICKHOUSE_NAMESPACE} &>/dev/null; then
echo "Error: ClickHouse is not installed in namespace '${CLICKHOUSE_NAMESPACE}'."
echo "Please install ClickHouse first: just clickhouse::install"
exit 1
fi
CLICKHOUSE_HOST=$(kubectl get ingress -n ${CLICKHOUSE_NAMESPACE} clickhouse-ingress \
-o jsonpath='{.spec.rules[0].host}' 2>/dev/null || echo "")
if [ -z "${CLICKHOUSE_HOST}" ]; then
echo "Error: ClickHouse Ingress not found."
echo "Please ensure ClickHouse is properly installed with Ingress configuration."
echo "Run: just clickhouse::setup-ingress"
exit 1
fi
export CLICKHOUSE_HOST="https://${CLICKHOUSE_HOST}"
just create-credentials
gomplate -f ch-ui-values.gomplate.yaml -o ch-ui-values.yaml
helm upgrade --install ch-ui ../charts/ch-ui \
--values ch-ui-values.yaml \
--namespace ${CH_UI_NAMESPACE} \
--wait
echo "CH-UI installation completed successfully"
echo "Access CH-UI at: https://${CH_UI_HOST}"
echo "ClickHouse API at: ${CLICKHOUSE_HOST}"
# Uninstall CH-UI
uninstall:
#!/bin/bash
set -euo pipefail
echo "Uninstalling CH-UI..."
helm uninstall ch-ui -n ${CH_UI_NAMESPACE} --wait --ignore-not-found
just delete-credentials-secret
just delete-ch-ui-user
echo "CH-UI uninstalled successfully"

1
charts/ch-ui/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
ch-ui-values.yaml

23
charts/ch-ui/.helmignore Normal file
View File

@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/

24
charts/ch-ui/Chart.yaml Normal file
View File

@@ -0,0 +1,24 @@
apiVersion: v2
name: ch-ui
description: A modern, feature-rich web interface for ClickHouse databases
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.0
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "1.6.1"

273
charts/ch-ui/README.md Normal file
View File

@@ -0,0 +1,273 @@
# CH-UI
[CH-UI](https://github.com/caioricciuti/ch-ui) is a modern, feature-rich web interface for ClickHouse databases.
## TL;DR
```bash
helm install ch-ui ./charts/ch-ui \
--set clickhouse.url="http://clickhouse:8123" \
--set clickhouse.auth.password="your-password"
```
## Introduction
This chart bootstraps a [CH-UI](https://github.com/caioricciuti/ch-ui) deployment on a [Kubernetes](https://kubernetes.io) cluster using the [Helm](https://helm.sh) package manager.
## Prerequisites
- Kubernetes 1.19+
- Helm 3.2.0+
- PV provisioner support in the underlying infrastructure (if persistence is needed)
- ClickHouse server accessible from the cluster
## Installing the Chart
To install the chart with the release name `ch-ui`:
```bash
helm install ch-ui ./charts/ch-ui
```
The command deploys CH-UI on the Kubernetes cluster in the default configuration. The [Parameters](#parameters) section lists the parameters that can be configured during installation.
> **Tip**: List all releases using `helm list`
## Uninstalling the Chart
To uninstall/delete the `ch-ui` deployment:
```bash
helm delete ch-ui
```
The command removes all the Kubernetes components associated with the chart and deletes the release.
## Parameters
### Global parameters
| Name | Description | Value |
| ------------------------- | ----------------------------------------------- | ----- |
| `nameOverride` | String to partially override ch-ui.fullname | `""` |
| `fullnameOverride` | String to fully override ch-ui.fullname | `""` |
| `imagePullSecrets` | Global Docker registry secret names as an array | `[]` |
### Common parameters
| Name | Description | Value |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `replicaCount` | Number of CH-UI replicas to deploy | `1` |
| `image.repository` | CH-UI image repository | `ghcr.io/caioricciuti/ch-ui` |
| `image.pullPolicy` | CH-UI image pull policy | `IfNotPresent` |
| `image.tag` | CH-UI image tag (immutable tags are recommended) | `""` |
| `serviceAccount.create` | Specifies whether a ServiceAccount should be created | `true` |
| `serviceAccount.automount` | Automatically mount a ServiceAccount's API credentials? | `true` |
| `serviceAccount.annotations` | Annotations to add to the service account | `{}` |
| `serviceAccount.name` | The name of the ServiceAccount to use | `""` |
| `podAnnotations` | Annotations for CH-UI pods | `{}` |
| `podLabels` | Extra labels for CH-UI pods | `{}` |
| `podSecurityContext` | Set CH-UI pod's Security Context | `{}` |
| `securityContext` | Set CH-UI container's Security Context | `{}` |
### CH-UI Configuration parameters
| Name | Description | Value |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `clickhouse.url` | ClickHouse server URL | `"http://clickhouse:8123"` |
| `clickhouse.auth.username` | ClickHouse username | `"default"` |
| `clickhouse.auth.password` | ClickHouse password (ignored if existingSecret is set) | `""` |
| `clickhouse.auth.existingSecret` | Name of existing Secret containing ClickHouse password | `""` |
| `clickhouse.auth.secretKeys.password` | Key in the existing Secret containing the password | `"clickhouse-password"` |
| `clickhouse.useAdvanced` | Enable advanced mode | `false` |
| `clickhouse.requestTimeout` | Request timeout in milliseconds | `30000` |
| `clickhouse.basePath` | Base path for the application | `"/"` |
### Exposure parameters
| Name | Description | Value |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `service.type` | CH-UI service type | `ClusterIP` |
| `service.port` | CH-UI service HTTP port | `80` |
| `service.targetPort` | CH-UI container port | `5521` |
| `ingress.enabled` | Enable ingress record generation for CH-UI | `false` |
| `ingress.className` | IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+) | `""` |
| `ingress.annotations` | Additional annotations for the Ingress resource | `{}` |
| `ingress.hosts[0].host` | Default host for the ingress record | `ch-ui.local` |
| `ingress.hosts[0].paths[0].path` | Default path for the default host | `/` |
| `ingress.hosts[0].paths[0].pathType` | Ingress path type | `ImplementationSpecific` |
| `ingress.tls` | Enable TLS configuration for the host defined at `ingress.hosts[0].host` parameter | `[]` |
### Resource parameters
| Name | Description | Value |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `resources.limits.cpu` | The CPU limits for the CH-UI containers | `500m` |
| `resources.limits.memory` | The memory limits for the CH-UI containers | `512Mi` |
| `resources.requests.cpu` | The requested CPU for the CH-UI containers | `100m` |
| `resources.requests.memory` | The requested memory for the CH-UI containers | `128Mi` |
| `livenessProbe.httpGet.path` | Path for liveness probe | `/` |
| `livenessProbe.httpGet.port` | Port for liveness probe | `http` |
| `livenessProbe.initialDelaySeconds` | Initial delay seconds for liveness probe | `30` |
| `livenessProbe.timeoutSeconds` | Timeout seconds for liveness probe | `5` |
| `readinessProbe.httpGet.path` | Path for readiness probe | `/` |
| `readinessProbe.httpGet.port` | Port for readiness probe | `http` |
| `readinessProbe.initialDelaySeconds` | Initial delay seconds for readiness probe | `5` |
| `readinessProbe.timeoutSeconds` | Timeout seconds for readiness probe | `5` |
| `autoscaling.enabled` | Enable Horizontal POD autoscaling for CH-UI | `false` |
| `autoscaling.minReplicas` | Minimum number of CH-UI replicas | `1` |
| `autoscaling.maxReplicas` | Maximum number of CH-UI replicas | `3` |
| `autoscaling.targetCPUUtilizationPercentage`| Target CPU utilization percentage | `80` |
### Additional parameters
| Name | Description | Value |
| ------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `extraEnvVars` | Array with extra environment variables to add to CH-UI containers | `[]` |
| `extraEnvVarsCM` | Name of existing ConfigMap containing extra env vars for CH-UI containers | `""` |
| `extraEnvVarsSecret` | Name of existing Secret containing extra env vars for CH-UI containers | `""` |
| `volumes` | Optionally specify extra list of additional volumes for the CH-UI pod(s) | `[]` |
| `volumeMounts` | Optionally specify extra list of additional volumeMounts for the CH-UI container(s) | `[]` |
| `nodeSelector` | Node labels for pod assignment | `{}` |
| `tolerations` | Tolerations for pod assignment | `[]` |
| `affinity` | Affinity for pod assignment | `{}` |
## Configuration and installation details
### Using an existing Secret
Instead of passing the ClickHouse password directly, you can use an existing Kubernetes Secret:
1. Create a Secret with your ClickHouse password:
```bash
kubectl create secret generic clickhouse-secret \
--from-literal=clickhouse-password="your-password"
```
2. Install the chart using the existing Secret:
```bash
helm install ch-ui ./charts/ch-ui \
--set clickhouse.auth.existingSecret="clickhouse-secret" \
--set clickhouse.auth.secretKeys.password="clickhouse-password"
```
### Exposing CH-UI
#### Using Ingress
To expose CH-UI using an Ingress:
```bash
helm install ch-ui ./charts/ch-ui \
--set ingress.enabled=true \
--set ingress.hosts[0].host="ch-ui.example.com" \
--set ingress.className="nginx"
```
#### Using LoadBalancer
To expose CH-UI using a LoadBalancer service:
```bash
helm install ch-ui ./charts/ch-ui \
--set service.type=LoadBalancer
```
#### Using NodePort
To expose CH-UI using a NodePort service:
```bash
helm install ch-ui ./charts/ch-ui \
--set service.type=NodePort
```
### Adding extra environment variables
You can add extra environment variables using `extraEnvVars`:
```bash
helm install ch-ui ./charts/ch-ui \
--set extraEnvVars[0].name=LOG_LEVEL \
--set extraEnvVars[0].value=debug
```
Or by referencing an existing ConfigMap or Secret:
```bash
helm install ch-ui ./charts/ch-ui \
--set extraEnvVarsCM=my-configmap \
--set extraEnvVarsSecret=my-secret
```
## Examples
### Basic installation with password
```bash
helm install ch-ui ./charts/ch-ui \
--set clickhouse.url="http://my-clickhouse:8123" \
--set clickhouse.auth.username="admin" \
--set clickhouse.auth.password="secretpassword"
```
### Installation with external ClickHouse and Ingress
```bash
helm install ch-ui ./charts/ch-ui \
--set clickhouse.url="http://clickhouse.example.com:8123" \
--set clickhouse.auth.existingSecret="clickhouse-credentials" \
--set ingress.enabled=true \
--set ingress.hosts[0].host="ch-ui.example.com" \
--set ingress.tls[0].secretName="ch-ui-tls" \
--set ingress.tls[0].hosts[0]="ch-ui.example.com"
```
### Installation with resource limits
```bash
helm install ch-ui ./charts/ch-ui \
--set resources.requests.memory="256Mi" \
--set resources.requests.cpu="250m" \
--set resources.limits.memory="1Gi" \
--set resources.limits.cpu="1"
```
## Troubleshooting
### CH-UI cannot connect to ClickHouse
1. Verify that the ClickHouse URL is correct and accessible from within the cluster:
```bash
kubectl run -it --rm debug --image=busybox --restart=Never -- wget -O- http://clickhouse:8123
```
2. Check the CH-UI logs:
```bash
kubectl logs -l app.kubernetes.io/name=ch-ui
```
3. Verify the credentials are correct by checking the Secret:
```bash
kubectl get secret ch-ui-secret -o jsonpath='{.data.clickhouse-password}' | base64 -d
```
### CH-UI is not accessible
1. Check the service is running:
```bash
kubectl get svc -l app.kubernetes.io/name=ch-ui
```
2. For Ingress issues, check the Ingress controller logs and ensure the Ingress resource is created:
```bash
kubectl get ingress
kubectl describe ingress ch-ui
```

View File

@@ -0,0 +1,35 @@
CH-UI has been deployed successfully!
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "ch-ui.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch its status by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "ch-ui.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "ch-ui.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "ch-ui.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
{{- end }}
2. Configure ClickHouse connection:
The application is configured to connect to: {{ .Values.clickhouse.url }}
Using username: {{ .Values.clickhouse.auth.username }}
Make sure your ClickHouse server is accessible and the credentials are correct.
3. To update the ClickHouse password, run:
kubectl create secret generic {{ include "ch-ui.fullname" . }}-secret \
--from-literal=clickhouse-password="your-password" \
--namespace {{ .Release.Namespace }} --dry-run=client -o yaml | kubectl apply -f -

View File

@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "ch-ui.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 "ch-ui.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "ch-ui.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "ch-ui.labels" -}}
helm.sh/chart: {{ include "ch-ui.chart" . }}
{{ include "ch-ui.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "ch-ui.selectorLabels" -}}
app.kubernetes.io/name: {{ include "ch-ui.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "ch-ui.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "ch-ui.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,108 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "ch-ui.fullname" . }}
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "ch-ui.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "ch-ui.labels" . | nindent 8 }}
{{- with .Values.podLabels }}
{{- toYaml . | nindent 8 }}
{{- end }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "ch-ui.serviceAccountName" . }}
{{- with .Values.podSecurityContext }}
securityContext:
{{- toYaml . | nindent 8 }}
{{- end }}
containers:
- name: {{ .Chart.Name }}
{{- with .Values.securityContext }}
securityContext:
{{- toYaml . | nindent 12 }}
{{- end }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.targetPort }}
protocol: TCP
env:
- name: VITE_CLICKHOUSE_URL
value: {{ .Values.clickhouse.url | quote }}
- name: VITE_CLICKHOUSE_USER
value: {{ .Values.clickhouse.auth.username | quote }}
- name: VITE_CLICKHOUSE_PASS
valueFrom:
secretKeyRef:
name: {{ .Values.clickhouse.auth.existingSecret | default (printf "%s-secret" (include "ch-ui.fullname" .)) }}
key: {{ .Values.clickhouse.auth.secretKeys.password }}
- name: VITE_CLICKHOUSE_USE_ADVANCED
value: {{ .Values.clickhouse.useAdvanced | quote }}
- name: VITE_CLICKHOUSE_REQUEST_TIMEOUT
value: {{ .Values.clickhouse.requestTimeout | quote }}
- name: VITE_BASE_PATH
value: {{ .Values.clickhouse.basePath | quote }}
{{- if .Values.extraEnvVars }}
{{- toYaml .Values.extraEnvVars | nindent 12 }}
{{- end }}
{{- if or .Values.extraEnvVarsCM .Values.extraEnvVarsSecret }}
envFrom:
{{- if .Values.extraEnvVarsCM }}
- configMapRef:
name: {{ .Values.extraEnvVarsCM }}
{{- end }}
{{- if .Values.extraEnvVarsSecret }}
- secretRef:
name: {{ .Values.extraEnvVarsSecret }}
{{- end }}
{{- end }}
{{- with .Values.livenessProbe }}
livenessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.readinessProbe }}
readinessProbe:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.resources }}
resources:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumeMounts }}
volumeMounts:
{{- toYaml . | nindent 12 }}
{{- end }}
{{- with .Values.volumes }}
volumes:
{{- toYaml . | 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 }}

View File

@@ -0,0 +1,32 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "ch-ui.fullname" . }}
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "ch-ui.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
target:
type: Utilization
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,43 @@
{{- if .Values.ingress.enabled -}}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ include "ch-ui.fullname" . }}
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- with .Values.ingress.className }}
ingressClassName: {{ . }}
{{- 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 }}
{{- with .pathType }}
pathType: {{ . }}
{{- end }}
backend:
service:
name: {{ include "ch-ui.fullname" $ }}
port:
number: {{ $.Values.service.port }}
{{- end }}
{{- end }}
{{- end }}

View File

@@ -0,0 +1,11 @@
{{- if not .Values.clickhouse.auth.existingSecret }}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "ch-ui.fullname" . }}-secret
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
type: Opaque
data:
{{ .Values.clickhouse.auth.secretKeys.password }}: {{ .Values.clickhouse.auth.password | b64enc }}
{{- end }}

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "ch-ui.fullname" . }}
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "ch-ui.selectorLabels" . | nindent 4 }}

View File

@@ -0,0 +1,13 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "ch-ui.serviceAccountName" . }}
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
automountServiceAccountToken: {{ .Values.serviceAccount.automount }}
{{- end }}

View File

@@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "ch-ui.fullname" . }}-test-connection"
labels:
{{- include "ch-ui.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "ch-ui.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never

116
charts/ch-ui/values.yaml Normal file
View File

@@ -0,0 +1,116 @@
# Default values for ch-ui.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: ghcr.io/caioricciuti/ch-ui
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
serviceAccount:
create: true
automount: true
annotations: {}
name: ""
podAnnotations: {}
podLabels: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 80
targetPort: 5521
ingress:
enabled: false
className: ""
annotations: {}
hosts:
- host: ch-ui.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 30
timeoutSeconds: 5
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
timeoutSeconds: 5
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 3
targetCPUUtilizationPercentage: 80
volumes: []
volumeMounts: []
nodeSelector: {}
tolerations: []
affinity: {}
# CH-UI specific configuration
clickhouse:
# ClickHouse server URL
url: "http://clickhouse:8123"
# Authentication configuration
auth:
# ClickHouse username
username: "default"
# ClickHouse password (ignored if existingSecret is set)
password: ""
# Name of an existing secret containing the authentication credentials
existingSecret: ""
# Secret keys for authentication credentials
secretKeys:
# Key in the secret containing the password
password: "clickhouse-password"
# Advanced configuration
useAdvanced: false
requestTimeout: 30000
basePath: "/"
# Additional environment variables
extraEnvVars: []
# - name: MY_ENV_VAR
# value: my-value
# Environment variables from existing ConfigMaps or Secrets
extraEnvVarsCM: ""
extraEnvVarsSecret: ""

View File

@@ -7,6 +7,7 @@ default:
@just --list --unsorted --list-submodules @just --list --unsorted --list-submodules
mod airflow mod airflow
mod ch-ui
mod clickhouse mod clickhouse
mod datahub mod datahub
mod env mod env