From a68df28a8e59ed7d2ca8ca67cfd32b156093ae36 Mon Sep 17 00:00:00 2001 From: Kacy Fortner Date: Sun, 8 Feb 2026 18:58:16 -0500 Subject: [PATCH 1/2] feat: add helm chart for kubernetes deployment minimal chart with deployment, service, and serviceaccount. configures ember via EMBER_* env vars from values.yaml. --- helm/ember/Chart.yaml | 6 ++ helm/ember/templates/NOTES.txt | 17 +++++ helm/ember/templates/_helpers.tpl | 51 +++++++++++++++ helm/ember/templates/deployment.yaml | 81 ++++++++++++++++++++++++ helm/ember/templates/service.yaml | 21 ++++++ helm/ember/templates/serviceaccount.yaml | 8 +++ helm/ember/values.yaml | 32 ++++++++++ 7 files changed, 216 insertions(+) create mode 100644 helm/ember/Chart.yaml create mode 100644 helm/ember/templates/NOTES.txt create mode 100644 helm/ember/templates/_helpers.tpl create mode 100644 helm/ember/templates/deployment.yaml create mode 100644 helm/ember/templates/service.yaml create mode 100644 helm/ember/templates/serviceaccount.yaml create mode 100644 helm/ember/values.yaml diff --git a/helm/ember/Chart.yaml b/helm/ember/Chart.yaml new file mode 100644 index 00000000..e36cd0cc --- /dev/null +++ b/helm/ember/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: ember +description: a low-latency, memory-efficient distributed cache +type: application +version: 0.1.0 +appVersion: "0.3.1" diff --git a/helm/ember/templates/NOTES.txt b/helm/ember/templates/NOTES.txt new file mode 100644 index 00000000..b172c6d9 --- /dev/null +++ b/helm/ember/templates/NOTES.txt @@ -0,0 +1,17 @@ +ember has been deployed! + +to connect from within the cluster: + + redis-cli -h {{ include "ember.fullname" . }}.{{ .Release.Namespace }}.svc.cluster.local -p {{ .Values.service.port }} + +to connect from your local machine: + + kubectl port-forward svc/{{ include "ember.fullname" . }} {{ .Values.service.port }}:{{ .Values.service.port }} + redis-cli -h 127.0.0.1 -p {{ .Values.service.port }} +{{- if .Values.ember.metricsPort }} + +prometheus metrics are available at: + + kubectl port-forward svc/{{ include "ember.fullname" . }} {{ .Values.ember.metricsPort }}:{{ .Values.ember.metricsPort }} + curl http://127.0.0.1:{{ .Values.ember.metricsPort }}/metrics +{{- end }} diff --git a/helm/ember/templates/_helpers.tpl b/helm/ember/templates/_helpers.tpl new file mode 100644 index 00000000..2ead0d3f --- /dev/null +++ b/helm/ember/templates/_helpers.tpl @@ -0,0 +1,51 @@ +{{/* +chart name, truncated to 63 chars. +*/}} +{{- define "ember.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +fully qualified app name, truncated to 63 chars. +*/}} +{{- define "ember.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 }} + +{{/* +common labels +*/}} +{{- define "ember.labels" -}} +helm.sh/chart: {{ printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{ include "ember.selectorLabels" . }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +selector labels +*/}} +{{- define "ember.selectorLabels" -}} +app.kubernetes.io/name: {{ include "ember.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +service account name +*/}} +{{- define "ember.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "ember.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/ember/templates/deployment.yaml b/helm/ember/templates/deployment.yaml new file mode 100644 index 00000000..257027af --- /dev/null +++ b/helm/ember/templates/deployment.yaml @@ -0,0 +1,81 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "ember.fullname" . }} + labels: + {{- include "ember.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "ember.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "ember.selectorLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "ember.serviceAccountName" . }} + containers: + - name: {{ .Chart.Name }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + - name: EMBER_HOST + value: "0.0.0.0" + - name: EMBER_PORT + value: {{ .Values.ember.port | quote }} + {{- if .Values.ember.metricsPort }} + - name: EMBER_METRICS_PORT + value: {{ .Values.ember.metricsPort | quote }} + {{- end }} + {{- if .Values.ember.maxMemory }} + - name: EMBER_MAX_MEMORY + value: {{ .Values.ember.maxMemory | quote }} + {{- end }} + {{- if ne .Values.ember.evictionPolicy "noeviction" }} + - name: EMBER_EVICTION_POLICY + value: {{ .Values.ember.evictionPolicy | quote }} + {{- end }} + {{- if .Values.ember.appendonly }} + - name: EMBER_APPENDONLY + value: "true" + - name: EMBER_APPENDFSYNC + value: {{ .Values.ember.appendfsync | quote }} + {{- end }} + {{- if .Values.ember.concurrent }} + - name: EMBER_CONCURRENT + value: "true" + {{- end }} + {{- if .Values.ember.requirepass }} + - name: EMBER_REQUIREPASS + value: {{ .Values.ember.requirepass | quote }} + {{- end }} + ports: + - name: cache + containerPort: {{ .Values.ember.port }} + protocol: TCP + {{- if .Values.ember.metricsPort }} + - name: metrics + containerPort: {{ .Values.ember.metricsPort }} + protocol: TCP + {{- end }} + livenessProbe: + tcpSocket: + port: cache + initialDelaySeconds: 5 + periodSeconds: 10 + readinessProbe: + tcpSocket: + port: cache + initialDelaySeconds: 2 + periodSeconds: 5 + volumeMounts: + - name: data + mountPath: /data + {{- with .Values.resources }} + resources: + {{- toYaml . | nindent 12 }} + {{- end }} + volumes: + - name: data + emptyDir: {} diff --git a/helm/ember/templates/service.yaml b/helm/ember/templates/service.yaml new file mode 100644 index 00000000..930e7015 --- /dev/null +++ b/helm/ember/templates/service.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ember.fullname" . }} + labels: + {{- include "ember.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: cache + protocol: TCP + name: cache + {{- if .Values.ember.metricsPort }} + - port: {{ .Values.ember.metricsPort }} + targetPort: metrics + protocol: TCP + name: metrics + {{- end }} + selector: + {{- include "ember.selectorLabels" . | nindent 4 }} diff --git a/helm/ember/templates/serviceaccount.yaml b/helm/ember/templates/serviceaccount.yaml new file mode 100644 index 00000000..ee60e672 --- /dev/null +++ b/helm/ember/templates/serviceaccount.yaml @@ -0,0 +1,8 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "ember.serviceAccountName" . }} + labels: + {{- include "ember.labels" . | nindent 4 }} +{{- end }} diff --git a/helm/ember/values.yaml b/helm/ember/values.yaml new file mode 100644 index 00000000..9f0f5c11 --- /dev/null +++ b/helm/ember/values.yaml @@ -0,0 +1,32 @@ +replicaCount: 1 + +image: + repository: ember + tag: latest + pullPolicy: IfNotPresent + +service: + type: ClusterIP + port: 6379 + +ember: + port: 6379 + metricsPort: 9100 + maxMemory: "" + evictionPolicy: noeviction + appendonly: false + appendfsync: everysec + concurrent: false + requirepass: "" + +resources: {} + # limits: + # cpu: "2" + # memory: 512Mi + # requests: + # cpu: 500m + # memory: 256Mi + +serviceAccount: + create: true + name: "" From f0d47a14257a29de1b7a03614ba238d98608519c Mon Sep 17 00:00:00 2001 From: Kacy Fortner Date: Sun, 8 Feb 2026 18:58:18 -0500 Subject: [PATCH 2/2] docs: add helm targets to makefile and kubernetes section to readme --- Makefile | 11 ++++++++++- README.md | 25 ++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index d6954489..53ad2e53 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,7 @@ .PHONY: build release test fmt fmt-check clippy check clean docker-build docker-run \ release-patch release-minor release-major github-release \ - publish publish-dry-run bench bench-core bench-protocol bench-compare bench-quick + publish publish-dry-run bench bench-core bench-protocol bench-compare bench-quick \ + helm-lint helm-template # extract the workspace version from the root Cargo.toml VERSION = $(shell sed -n 's/^version = "\(.*\)"/\1/p' Cargo.toml) @@ -128,3 +129,11 @@ publish: done @echo "" @echo "all crates published successfully" + +# --- helm --- + +helm-lint: + helm lint helm/ember + +helm-template: + helm template ember helm/ember diff --git a/README.md b/README.md index 66a0b30f..f4337af5 100644 --- a/README.md +++ b/README.md @@ -141,11 +141,34 @@ make check # fmt, clippy, tests make build # debug build make release # release build make test # run all tests -make docker-build # build docker image +make docker-build # build docker image +make helm-lint # validate helm chart +make helm-template # render helm templates ``` see [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow and code standards. +## kubernetes + +deploy to kubernetes with [Helm](https://helm.sh): + +```bash +# install with defaults (single replica, ClusterIP service) +helm install ember helm/ember + +# install with custom settings +helm install ember helm/ember \ + --set ember.maxMemory=512M \ + --set ember.evictionPolicy=allkeys-lru \ + --set ember.appendonly=true + +# connect via port-forward +kubectl port-forward svc/ember 6379:6379 +redis-cli -h 127.0.0.1 +``` + +see [helm/ember/values.yaml](helm/ember/values.yaml) for all configurable values. + ## project structure ```