Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions helm/tansu/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Helm
Chart.lock
*.tgz
14 changes: 14 additions & 0 deletions helm/tansu/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v2
name: tansu
description: Tansu - Apache Kafka-compatible broker with pluggable storage backends
type: application
version: 0.1.0
appVersion: "1"
keywords:
- kafka
- message-broker
- event-streaming
maintainers: []
home: https://github.com/tansu-io/tansu
sources: []
license: Apache-2.0
173 changes: 173 additions & 0 deletions helm/tansu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
# Tansu Helm Chart

[Tansu](https://github.com/tansu-io/tansu) is an Apache Kafka-compatible broker with pluggable storage backends. This chart runs the Tansu broker as a Deployment with configurable replicas, autoscaling, and storage engine.

## Prerequisites

- Kubernetes 1.23+
- Helm 3+

## Install

```bash
helm repo add tansu https://tansu-io.github.io/tansu
helm install tansu ./helm/tansu
```

## Configuration

### Replicas and autoscaling

- **Replicas**: Set `replicaCount` (used when autoscaling is disabled).
- **Autoscaling**: Enable HPA with `autoscaling.enabled: true`, then set:
- `autoscaling.minReplicas` / `autoscaling.maxReplicas`
- `autoscaling.targetCPUUtilizationPercentage` (and optionally `targetMemoryUtilizationPercentage`)

Example:

```yaml
replicaCount: 2

autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 10
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
```

### Storage engine

Set `storageEngine.type` to one of: **memory**, **s3**, **postgres**, **sqlite**.

| Type | Use case | Required config |
|-----------|------------------|-----------------|
| `memory` | Dev / tests | `storageEngine.memory.prefix` (default `tansu`) |
| `s3` | Production (S3) | `storageEngine.s3.bucket`, and credentials via `storageEngine.s3.existingSecret` (keys `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`). Optional: `endpoint`, `region`, `allowHttp` |
| `postgres`| Production | `storageEngine.postgres.host`, `user`, `database`. Set `storageEngine.postgres.password` or use `storageEngine.postgres.existingSecret` (key `password`) for the DB password |
| `sqlite` | Single-node / dev | `storageEngine.sqlite.path` (default `/data/tansu.db`). Uses `emptyDir` by default; for persistence use `extraVolumes` / `extraVolumeMounts` with a PVC |

Example – S3 with existing secret:

```yaml
storageEngine:
type: s3
s3:
bucket: tansu
region: eu-west-2
endpoint: "" # omit for default AWS
allowHttp: "true"
existingSecret: tansu-s3-credentials
```

Example – Postgres with password from secret:

```yaml
storageEngine:
type: postgres
postgres:
host: postgres
port: 5432
database: postgres
user: postgres
existingSecret: tansu-postgres-password
existingSecretPasswordKey: password
```

For a fully custom storage URL (e.g. postgres URL with special characters), use a Secret and reference it:

```yaml
storageUrlFromSecret:
name: tansu-storage-url
key: STORAGE_ENGINE
```

Create the secret with the exact URL, e.g.:

```bash
kubectl create secret generic tansu-storage-url --from-literal=STORAGE_ENGINE='postgres://user:pass@host:5432/db'
```

### Image

Default image: `ghcr.io/tansu-io/tansu`. Override with:

```yaml
image:
repository: ghcr.io/tansu-io/tansu
tag: "v1.0.0"
pullPolicy: IfNotPresent
```

### Advertised listener

Clients use the advertised listener to connect. In-cluster default is `tansu:9092`. For a specific namespace or release name:

```yaml
advertisedListener: "tansu.my-namespace.svc.cluster.local:9092"
```

### Kafka LoadBalancer

To expose Kafka (TCP 9092) externally via a cloud LoadBalancer, enable the dedicated Kafka LoadBalancer service. The main service stays ClusterIP for in-cluster traffic.

```yaml
kafkaLoadBalancer:
enabled: true
port: 9092
# annotations: # optional, e.g. for AWS NLB
# service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
# service.beta.kubernetes.io/aws-load-balancer-scheme: "internet-facing"
```

Set `advertisedListener` to the external host and port clients will use (e.g. the LoadBalancer hostname or IP and `9092`), so broker metadata points clients to the right address.

### Ingress

Standard Ingress is HTTP/HTTPS only. The chart defaults the Ingress backend to the **metrics** port (9100). For Kafka (TCP 9092), use the Kafka LoadBalancer above or NodePort.

Enable and configure Ingress:

```yaml
ingress:
enabled: true
className: nginx
hosts:
- host: tansu.example.com
paths:
- path: /
pathType: Prefix
port: metrics
tls:
- secretName: tansu-tls
hosts:
- tansu.example.com
```

## Values reference

| Key | Default | Description |
|-----|---------|-------------|
| `replicaCount` | `1` | Number of replicas when autoscaling is disabled |
| `autoscaling.enabled` | `false` | Enable HorizontalPodAutoscaler |
| `autoscaling.minReplicas` | `1` | Minimum replicas under HPA |
| `autoscaling.maxReplicas` | `10` | Maximum replicas under HPA |
| `autoscaling.targetCPUUtilizationPercentage` | `70` | Target CPU % for HPA |
| `storageEngine.type` | `memory` | One of: `memory`, `s3`, `postgres`, `sqlite` |
| `image.repository` | `ghcr.io/tansu-io/tansu` | Container image |
| `image.tag` | (chart appVersion) | Image tag |
| `clusterId` | `tansu` | Kafka cluster ID |
| `advertisedListener` | `tansu:9092` | Advertised listener URL host:port |
| `service.kafkaPort` | `9092` | Kafka port |
| `service.metricsPort` | `9100` | Metrics port |
| `kafkaLoadBalancer.enabled` | `false` | Create a LoadBalancer/NodePort service for Kafka TCP |
| `kafkaLoadBalancer.serviceType` | `LoadBalancer` | `LoadBalancer` (cloud) or `NodePort` (local k8s) |
| `kafkaLoadBalancer.nodePort` | `null` | For NodePort: fixed port (e.g. 30092); omit for auto |
| `kafkaLoadBalancer.port` | `9092` | Service port |
| `kafkaLoadBalancer.annotations` | `{}` | Annotations (e.g. AWS NLB type) |
| `ingress.enabled` | `false` | Enable Ingress (HTTP; for metrics) |
| `ingress.className` | `""` | IngressClass name (e.g. nginx) |
| `ingress.hosts` | see values | Hosts and paths (default: metrics port) |
| `ingress.tls` | `[]` | TLS secret and hosts |

See [values.yaml](values.yaml) for all options.
7 changes: 7 additions & 0 deletions helm/tansu/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
1. Kafka bootstrap (in-cluster):
{{ include "tansu.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local:{{ .Values.service.kafkaPort }}

2. Connect to the broker (in-cluster):
kafka-bootstrap-servers: {{ include "tansu.fullname" . }}.{{ .Release.Namespace }}.svc:{{ .Values.service.kafkaPort }}

3. Storage engine: {{ .Values.storageEngine.type }}
86 changes: 86 additions & 0 deletions helm/tansu/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "tansu.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Create a default fully qualified app name.
*/}}
{{- define "tansu.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 "tansu.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}

{{/*
Common labels
*/}}
{{- define "tansu.labels" -}}
helm.sh/chart: {{ include "tansu.chart" . }}
{{ include "tansu.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}

{{/*
Selector labels
*/}}
{{- define "tansu.selectorLabels" -}}
app.kubernetes.io/name: {{ include "tansu.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}

{{/*
Storage engine URL from values (when not using storageUrlFromSecret).
For postgres with password from secret, use storageUrlFromSecret with a secret containing the full URL.
*/}}
{{- define "tansu.storageEngineUrl" -}}
{{- $type := .Values.storageEngine.type -}}
{{- if eq $type "memory" -}}
memory://{{ .Values.storageEngine.memory.prefix }}/
{{- else if eq $type "s3" -}}
s3://{{ .Values.storageEngine.s3.bucket }}/{{ .Values.storageEngine.s3.path | trimSuffix "/" }}{{- if .Values.storageEngine.s3.path }}/{{ end }}
{{- else if eq $type "postgres" -}}
postgres://{{ .Values.storageEngine.postgres.user }}:{{ .Values.storageEngine.postgres.password | default "" }}@{{ .Values.storageEngine.postgres.host }}:{{ .Values.storageEngine.postgres.port }}/{{ .Values.storageEngine.postgres.database }}
{{- else if eq $type "sqlite" -}}
sqlite://{{ .Values.storageEngine.sqlite.path }}
{{- else -}}
memory://tansu/
{{- end -}}
{{- end }}

{{/*
Whether storage URL comes from a secret (key STORAGE_ENGINE).
*/}}
{{- define "tansu.storageUrlFromSecret" -}}
{{- if and .Values.storageUrlFromSecret .Values.storageUrlFromSecret.name .Values.storageUrlFromSecret.key }}true{{ end }}
{{- end }}

{{/*
ServiceAccount name.
*/}}
{{- define "tansu.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "tansu.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
Loading